FastAPI is a modern Python web framework that simplifies the process of building APIs with high performance and great documentation. In this tutorial, we will focus on implementing authentication APIs using FastAPI. We will cover the following endpoints – Register, GET Token, Refresh Token, and User Details.
- Setting up the project:
Firstly, make sure you have Python and FastAPI installed. You can install FastAPI using pip:
pip install fastapi
pip install uvicorn
Create a new Python file, let’s call it main.py. This will be our main FastAPI file.
- Define models:
We will need to define the models for our user and tokens. Create a models.py file and add the following code:
from pydantic import BaseModel
class User(BaseModel):
username: str
password: str
class Token(BaseModel):
access_token: str
token_type: str
class UserInDB(User):
hashed_password: str
- Implement the endpoints:
In our main.py file, we will define our endpoints for authentication. Here is how you can implement them:
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt import PyJWTError, decode, encode
from passlib.context import CryptContext
from datetime import datetime, timedelta
from typing import Optional
from models import User, Token, UserInDB
app = FastAPI()
security = OAuth2PasswordBearer(tokenUrl="/token")
# Secret key
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# User database
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "$2b$12$EY/a9eOzVta9jj5/93o7BOlMuQ9fowmH5jz/Fo65t8hjijNUCeEqS" #hashed password - password123
}
}
# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# Authenticate User
def authenticate_user(username: str, password: str):
user = fake_users_db.get(username)
if not user:
return False
if not pwd_context.verify(password, user["hashed_password"]):
return False
return user
# Get user
def get_current_user(token: str = Depends(security)):
credentials_exception = HTTPException(
status_code=401,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except PyJWTError:
raise credentials_exception
user = fake_users_db.get(username)
if user is None:
raise credentials_exception
return user
# Create access token
def create_access_token(data: dict, expires_delta: Optional[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 = encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# Register user
@app.post("/register", response_model=User)
async def register_user(user: User):
if user.username in fake_users_db:
raise HTTPException(status_code=400, detail="Username already registered")
fake_users_db[user.username] = {
"username": user.username,
"full_name": user.username,
"email": user.username + "@example.com",
"hashed_password": pwd_context.hash(user.password)
}
return user
# Get Token
@app.post("/token", response_model=Token)
async def get_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect username or password")
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"}
# Refresh Token
@app.post("/refresh_token", response_model=Token)
async def refresh_token(user: User = Depends(get_current_user)):
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"}
# User Details
@app.get("/user/me", response_model=User)
async def read_users_me(user: User = Depends(get_current_user)):
return user
- Running the application:
You can run your FastAPI application using Uvicorn:
uvicorn main:app --reload
Now, you can test your authentication APIs using tools like Postman or curl. Here are the endpoints you can hit:
- /register – to register a new user
- /token – to get an access token by providing username and password
- /refresh_token – to refresh the access token
- /user/me – to get user details
Make sure to handle the authentication tokens securely and implement proper authorization and validation logic in your APIs.
This tutorial covers the basic implementation of authentication APIs using FastAPI. You can further enhance your authentication logic by adding features like JWT blacklisting, role-based access control, and more. FastAPI makes it easy to build secure and performant APIs with Python. Happy coding!
Congrats. Impressive work
Very nice tutorial. Thanks a lot.
Awesome video. I learnt so much about authentication in general. I was looking to setup fastapi just like Django and this video helped me do that. Thank you 🙂
Great tutorial. It was challenging, but I managed to work my way to the end. Thanks a lot!
This still does not explain how can I use refresh tokens. When I use PasswordBearer, then no refreshtoken is exposed in the response, which I can copy and use to generate another access token. Also how can I update the cookie with the new token ?
what is the difference between access and refresh tokens? in this code u can use a refresh token as aceess for autorisation. so where is the safety here? besides, refresh token has no expiration time
Rather than using any db to store the id and passwd can we use any secure vault like hashicprp to save the details ?
Great work ❤
thank you!
Why your endpoints does not have lock icon for oauth2?
awesome man !
thanks for this
Good
How can i setup database in mysql
Thanks
In 1:16:56 , UserResponse should inherit BaseResponse not BaseModel.
can you do same with mongo
this training is wider than just for JWT, but it's very good. It was difficult to go through MySQL setup though
Hello, can you prepare video content by adding Rabbitmq, Kafka, Redis technologies into this API?
Thank you for explaning this!
Thanks for the tutorial
1. refresh token doesn't have expiration time,
2. use can access protected endpoints using both refresh token and access token.
refresh token should only be used to obtain new access token
it is not a good practice
what i like about your video is you do your job with blind eyes not even debug it's okay when you do yourself but when you are teaching it's different