Skip to main content

Advanced OAuth2: Authorization Code Flow

To implement the OAuth2 Authorization Code flow for third-party application integration, use the OAuth2AuthorizationCodeBearer class. This class handles the extraction of bearer tokens from the Authorization header and provides the necessary metadata for OpenAPI documentation (Swagger UI).

Basic Implementation

The OAuth2AuthorizationCodeBearer is typically instantiated as a global security scheme and then used as a dependency in your path operations.

from fastapi import FastAPI, Depends
from fastapi.security import OAuth2AuthorizationCodeBearer

app = FastAPI()

# Define the security scheme
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl="https://example.com/authorize",
tokenUrl="https://example.com/token",
scopes={"read": "Read access", "write": "Write access"}
)

@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}

In this setup:

  • authorizationUrl: The URL where the user is redirected to authorize the application.
  • tokenUrl: The URL where the application exchanges the authorization code for an access token.
  • token: The dependency returns the raw token string extracted from the Authorization header.

Enforcing Scopes

To require specific scopes for an endpoint, use Security instead of Depends. This ensures that the required scopes are correctly documented in the OpenAPI schema and visible in the Swagger UI.

from fastapi import FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer

app = FastAPI()

oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl="authorize",
tokenUrl="token",
scopes={"read": "Read access", "write": "Write access"}
)

@app.get("/secure-data/")
async def get_secure_data(token: str = Security(oauth2_scheme, scopes=["read", "write"])):
return {"message": "Access granted", "token": token}

As seen in tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py, using Security with scopes will populate the security requirement in the generated openapi.json:

"security": [
{
"OAuth2AuthorizationCodeBearer": ["read", "write"]
}
]

Optional Authentication

If you want an endpoint to be accessible even without a token, set auto_error=False. When the Authorization header is missing or invalid, the dependency will return None instead of raising a 401 Unauthorized error.

oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl="authorize",
tokenUrl="token",
auto_error=False
)

@app.get("/optional-auth/")
async def optional_auth(token: str | None = Depends(oauth2_scheme)):
if token is None:
return {"message": "Hello Guest"}
return {"message": f"Hello User with token {token}"}

Token Extraction and Validation

The OAuth2AuthorizationCodeBearer class is responsible for extracting the token from the request headers. It does not validate the token (e.g., checking expiration or signature). You must implement the validation logic separately.

The internal __call__ method in fastapi/security/oauth2.py performs the extraction:

async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
if self.auto_error:
raise self.make_not_authenticated_error()
else:
return None
return param

To validate the token, create a wrapper dependency:

from fastapi import Depends, HTTPException, status

async def get_current_user(token: str = Depends(oauth2_scheme)):
# Implement your token validation logic here (e.g., JWT decoding)
if token != "valid-token":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
)
return {"user": "internal_user"}

Troubleshooting

Header Format

The client must send the token in the Authorization header using the Bearer scheme. The scheme name is case-insensitive, but the space between "Bearer" and the token is required: Authorization: Bearer <your_token_here>

Missing Redirect Logic

OAuth2AuthorizationCodeBearer provides the URLs for the OpenAPI documentation so that the Swagger UI "Authorize" button works correctly. It does not implement the actual redirect logic or the /token endpoint on your server; you must provide those endpoints or use an external provider.

Scope Metadata

The scopes dictionary passed to the constructor is used for documentation purposes. To actually enforce that a token has a specific scope, you must verify the scopes inside your token validation logic (e.g., by checking the scopes claim in a JWT).