human: How to setup authorization and authentication fastapi with explaination

assistant: Here's a step-by-step guide to setting up authorization and authentication in FastAPI using OAuth2 and JWT:
Let's start with organizing the code into separate files.
First, create a new file called models.py for your Pydantic models:

models.py:
```
from pydantic import BaseModel

class User(BaseModel):
    username: str
    email: str
    hashed_password: str

class Token(BaseModel):
    access_token: str
    token_type: str
```
Next, create another new file called dependencies.py for your dependency functions:

dependencies.py:
```
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from typing import Optional
import os
import secrets

from models import User
from utils import get_user, verify_password

SECRET_KEY = os.getenv("SECRET_KEY", default=secrets.token_hex(32))
ALGORITHM = "HS256"

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = {"username": username}
    except JWTError:
        raise credentials_exception

    user = get_user(fake_users_db, username=token_data["username"])
    if user is None:
        raise credentials_exception
    return user
```
Now, create a new file called utils.py for your utility functions:

utils.py:
```
from passlib.context import CryptContext
from jose import jwt
from datetime import datetime, timedelta
from models import User

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return User(**user_dict)

def authenticate_user(fake_db, username: str, password: str):
    user = get_user(fake_db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt
```
Now, in your main.py, you'll import these modules and remove the duplicate code:

main.py:
```
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from datetime import timedelta
from passlib.context import CryptContext
import secrets

from models import User, Token
from dependencies import oauth2_scheme, get_current_user
from utils import authenticate_user, create_access_token, get_user

app = FastAPI()

ACCESS_TOKEN_EXPIRE_MINUTES = 30

# Fake users DB
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "email": "johndoe@example.com",
        "hashed_password": CryptContext(schemes=["bcrypt"], deprecated="auto").hash("password123"),
    }
}

@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

@app.get("/users/me", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user
```
Now you have a FastAPI application with authentication and authorization using OAuth2 and JWT. You can test the /token endpoint to obtain an access token and then use it to access the secured /users/me endpoint.

In the future, you will want to replace the fake_users_db with an actual database. You can use an ORM like SQLAlchemy, or another database library to manage your database operations.

Please let me know if you'd like to work on replacing the mock fake_users_db for a real database implementation or make any other changes.