In the previous article, we learned how to:
- Register users
- Hash passwords using bcrypt
- Verify passwords during login
- Generate JWT tokens
However, generating a token alone doesn't secure an application.
Anyone can still access endpoints unless we verify the token before granting access.
Today we'll learn how FastAPI identifies users from JWT tokens and protects routes from unauthorized access.
Do check out the previous post to understand this:
The Problem
Suppose we have:
@app.get("/profile")
def get_profile():
return {"message": "My profile"}
Anyone can access this endpoint.
There is no verification of:
- Who is making the request
- Whether they are logged in
- Whether their token is valid
Authentication Flow
Login
↓
Generate JWT
↓
Store JWT
↓
Send JWT with Request
↓
Verify JWT
↓
Allow Access
Extracting the Token
OAuth2PasswordBearer
OAuth2PasswordBearer is a class provided by FastAPI to handle security and authentication using OAuth2 with the Password flow and Bearer tokens. This class simplifies the process of implementing secure authentication in your FastAPI application.
To use OAuth2PasswordBearer, you need to create an instance of it and pass the tokenUrl parameter, which specifies the URL where the client will send the username and password to obtain a token.
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="login"
)
When a request arrives:
Authorization: Bearer eyJhbGc...
FastAPI automatically extracts the token.
Decoding JWT Tokens
from jose import jwt
from jose import JWTError
def verify_token(token: str):
try:
payload = jwt.decode(
token,
SECRET_KEY,
algorithms=[ALGORITHM]
)
username = payload.get("sub")
return username
except JWTError:
return None
JWT contains:
{
"sub": "suman",
"exp": ...
}
We extract the username from "sub".
Creating get_current_user()
This is the most important concept.
from fastapi import Depends
def get_current_user(
token: str = Depends(oauth2_scheme)
):
username = verify_token(token)
if username is None:
raise Exception("Invalid token")
return username
Every protected endpoint will use:
Depends(get_current_user)
This ensures that users who have registered and who's JWT token has been verified only they have access to the protected route.
Protecting Routes
@app.get("/profile")
def get_profile(
current_user: str = Depends(
get_current_user
)
):
return {
"message": f"Welcome {current_user}"
}
Now:
Valid Token (When access is granted as JWT token matches)
{
"message": "Welcome suman"
}
Invalid Token (Access not granted)
{
"detail": "Could not validate credentials"
}
Visual Flow
User Login
↓
JWT Token Generated
↓
Token Sent in Request
↓
FastAPI Extracts Token
↓
JWT Verification
↓
Current User Identified
↓
Protected Route Access
Conclusion
Today we learned:
- OAuth2PasswordBearer
- Extracting JWT tokens
- Decoding JWT tokens
- Creating get_current_user()
- Protecting routes using Depends()
In the next article, we'll move beyond authentication and implement Role-Based Access Control (RBAC), allowing different users to have different permissions.
Top comments (0)