FastAPI Basics • Lesson 30

Security - OAuth2 with JWT Tokens

Implement secure authentication using JWT tokens with password hashing and OAuth2 Bearer authentication.

OAuth2 with Password (and hashing), Bearer with JWT tokens

🎯 What You'll Learn

  • Implement JWT tokens for secure authentication
  • Use password hashing with bcrypt for secure password storage
  • Create real JWT tokens with expiration
  • Handle token validation and user authentication securely

📚 Theory

Now that we have all the security flow, let's make the application actually secure, using JWT tokens and secure password hashing.

This code is something you can actually use in your application, save the password hashes in your database, etc.

We are going to start from where we left in the previous chapter and increment it.

About JWT

JWT means "JSON Web Tokens".

It's a standard to codify a JSON object in a long dense string without spaces. It looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

It is not encrypted, so, anyone could recover the information from the contents.

But it's signed. So, when you receive a token that you emitted, you can verify that you actually emitted it.

That way, you can create a token with an expiration of, let's say, 1 week. And then when the user comes back the next day with the token, you know that user is still logged in to your system.

After a week, the token will be expired and the user will not be authorized and will have to sign in again to get a new token. And if the user (or a third party) tried to modify the token to change the expiration, you would be able to discover it, because the signatures would not match.

Password Hashing

In the previous examples we were storing the user passwords in plaintext. But now we are going to hash the user passwords using Passlib and Bcrypt.

Passlib is a great Python package to handle password hashes. It supports many secure hashing algorithms and utilities to work with them.

The recommended algorithm is Bcrypt.

🔧 Key Concepts

Password Hashing with PassLib

from passlib.context import CryptContext

# Create password context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Hash a password
hashed = pwd_context.hash("secret")

# Verify a password
is_valid = pwd_context.verify("secret", hashed)

JWT Token Creation

import jwt
from datetime import datetime, timedelta

# Create token with expiration
to_encode = {"sub": username, "exp": datetime.utcnow() + timedelta(minutes=30)}
token = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")

JWT Token Verification

try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    username = payload.get("sub")
except jwt.PyJWTError:
    # Token is invalid
    raise HTTPException(status_code=401, detail="Invalid token")

OAuth2 Bearer Authentication

from fastapi.security import OAuth2PasswordBearer

# Define token URL for authentication
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# Use in dependency
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
    # Verify and decode token
    return user

💡 Best Practices

Security Considerations

  • Secret Key: Use a strong, randomly generated secret key
  • Token Expiration: Set reasonable expiration times (15-30 minutes)
  • HTTPS Only: Always use HTTPS in production
  • Password Strength: Enforce strong password requirements

Token Management

  • Refresh Tokens: Implement refresh tokens for better UX
  • Token Revocation: Consider token blacklisting for logout
  • Scope Limitations: Use scopes to limit token permissions

Error Handling

  • Consistent Responses: Return consistent error messages
  • No Information Leakage: Don't reveal whether username or password is wrong
  • Rate Limiting: Implement rate limiting on authentication endpoints

🔗 Additional Resources

💡 Hint

Install PyJWT and passlib[bcrypt] packages, then implement password hashing, JWT token creation, and secure authentication endpoints.

Ready to Practice?

Now that you understand the theory, let's put it into practice with hands-on coding!

Start Interactive Lesson