Integrating Authentication OAuth 2.0
Integrating authentication protocols like Azure AD (which heavily uses OAuth 2.0) and generic OAuth 2.0 into your APIs is crucial for securing your applications. Here's a breakdown of how to approach this, including key concepts and best practices:
Understanding OAuth 2.0 (the foundation)
OAuth 2.0 is an authorization framework that enables an application to obtain limited access to a user's protected resources on an HTTP service (like your API), without revealing the user's credentials to the application. Instead, the application obtains an access token from an authorization server (e.g., Azure AD) after the user grants consent.
Key Roles in OAuth 2.0:
Resource Owner: The user who owns the data (e.g., their profile information, documents) that the client application wants to access.
Client: The application (your API consumer, like a web app, mobile app, or another service) that wants to access the protected resources.
Authorization Server: The server that issues access tokens to the client after successfully authenticating the resource owner and obtaining their authorization. (Azure AD acts as an Authorization Server).
Resource Server: The API that hosts the protected resources and accepts access tokens to grant access. (Your API will be the Resource Server).
Common OAuth 2.0 Flows for APIs:
Authorization Code Flow (with PKCE): This is the most secure and recommended flow for web applications and mobile/native applications. It involves a redirect to the authorization server for user login and consent, then an authorization code is exchanged for an access token at the backend. PKCE (Proof Key for Code Exchange) adds an extra layer of security against interception.
Client Credentials Flow: Used for machine-to-machine communication where there's no user involved (e.g., a service authenticating to another service). The client uses its own credentials (Client ID and Client Secret) to obtain an access token.
On-Behalf-Of (OBO) Flow (Specific to Azure AD): If your API needs to call another downstream API on behalf of the user, Azure AD supports the OBO flow where your API exchanges the initial access token for another token with permissions to the downstream API.
Integrating Azure AD Authentication into APIs
Azure Active Directory (Azure AD) is Microsoft's cloud-based identity and access management service, and it heavily leverages OAuth 2.0 and OpenID Connect for authentication and authorization.
Steps to Integrate Azure AD into your API (as the Resource Server):
Register your API as an Application in Azure AD:
Go to the Azure portal and navigate to "App registrations."
Register a new application that represents your API.
Configure its Application ID URI (also known as Audience or Identifier URI).
Define API permissions (scopes) that your API exposes. These scopes represent the granular access rights that clients can request (e.g.,
api://your-api-id/read_data,api://your-api-id/write_data).For clients, you might also need to create a client secret (for confidential clients like web apps) or enable public client flows (for mobile/desktop apps).
Configure your API to Validate Azure AD Tokens:
Your API (Resource Server) needs to be able to validate the JSON Web Tokens (JWTs) issued by Azure AD.
This typically involves using a JWT bearer authentication middleware or library in your API framework (e.g.,
Microsoft.Identity.Webfor ASP.NET Core,passport-azure-adfor Node.js).The middleware will:
Extract the access token from the
Authorization: Bearer <token>header of incoming requests.Validate the token's signature against Azure AD's public keys.
Check the token's claims:
iss(Issuer): Ensures the token was issued by your Azure AD tenant.aud(Audience): Ensures the token is intended for your API (matches your API's Application ID URI).exp(Expiration): Checks if the token is still valid.nbf(Not Before): Checks if the token is active.scp(Scopes) orroles: Verifies if the client has the necessary permissions to access the requested resource/operation.
If the token is valid, the middleware will usually populate the user's identity (claims) into the current request context, allowing your API logic to perform further authorization checks based on these claims.
Implement Authorization Logic within your API:
Once the token is validated, your API needs to determine if the authenticated user/client has the necessary permissions (based on the scopes or roles in the token) to perform the requested action.
This often involves:
Role-based access control (RBAC): Checking if the user belongs to a specific role.
Scope-based authorization: Checking if the token contains the required scopes for the API endpoint.
Example (Conceptual - ASP.NET Core):
// In Startup.cs or Program.cs (for minimal APIs)
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd")); // Binds configuration from appsettings.json
services.AddAuthorization(options =>
{
options.AddPolicy("RequireReadAccess", policy => policy.RequireScope("api://your-app-id/read_data"));
options.AddPolicy("RequireWriteAccess", policy => policy.RequireScope("api://your-app-id/write_data"));
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication(); // Must be before UseAuthorization
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
// In your API Controller
[Authorize] // Requires any valid token
[Authorize(Policy = "RequireReadAccess")] // Requires the "read_data" scope
[HttpGet("data")]
public IActionResult GetData()
{
// Access user claims from HttpContext.User
return Ok("Data accessed!");
}
Generic OAuth 2.0 Integration for APIs
If you're using a different OAuth 2.0 provider (e.g., Google, Okta, Auth0, or your own custom authorization server), the principles are similar to Azure AD, but the specific configuration details and libraries will vary.
General Steps:
Register your API with the OAuth 2.0 Provider:
Obtain a Client ID and potentially a Client Secret for your API.
Define scopes that your API exposes.
Configure redirect URIs (if your API is part of a user-facing application).
Configure your API to Validate Tokens from the Provider:
Your API needs to trust the specific OAuth 2.0 provider.
This involves configuring your API's authentication middleware to:
Know the provider's JWKS (JSON Web Key Set) endpoint to retrieve public keys for token signature validation.
Set the expected
iss(Issuer) andaud(Audience) claims for tokens.Implement logic to extract and validate the access token (JWT) from the
Authorizationheader.
Implement Authorization based on Claims:
Similar to Azure AD, extract scopes, roles, or other claims from the validated token.
Use these claims to enforce fine-grained access control within your API endpoints.
Best Practices for API Authentication:
Always use HTTPS: All communication between clients, authorization servers, and your API should be encrypted with HTTPS to prevent man-in-the-middle attacks.
Validate Tokens Thoroughly: Always validate the token's signature, expiration, issuer, audience, and any required scopes or claims.
Use the Authorization Code Flow with PKCE: This is the most secure flow for public clients (mobile/SPA) and confidential clients (web apps). Avoid the Implicit Flow.
Securely Store Client Secrets: If your API acts as a confidential client (e.g., in Client Credentials flow), store client secrets in secure environments (e.g., Azure Key Vault, environment variables) and never hardcode them in your codebase or commit them to public repositories.
Short-lived Access Tokens, Long-lived Refresh Tokens: Issue access tokens with a short expiry (e.g., 1 hour) and use refresh tokens (for user-based flows) to obtain new access tokens without requiring the user to re-authenticate. Refresh tokens should be long-lived but managed securely and revoked if compromised.
Implement Scope-Based Authorization: Design your API endpoints to require specific scopes, ensuring clients only have access to what they truly need.
Error Handling: Provide clear and informative error messages (e.g., 401 Unauthorized, 403 Forbidden) when authentication or authorization fails, but avoid revealing too much sensitive information.
Logging and Monitoring: Log authentication and authorization events to monitor for suspicious activity.
Rate Limiting: Implement rate limiting on your authentication endpoints to prevent brute-force attacks.
Centralized Identity Provider: Leverage a robust identity provider like Azure AD, Auth0, Okta, etc., rather than building your own from scratch.
Regular Security Audits: Regularly review your authentication and authorization implementation for vulnerabilities.
By following these guidelines and leveraging appropriate libraries and services, you can effectively integrate robust authentication and authorization protocols into your APIs.
Integrating OAuth with Google and Azure AD in FastAPI involves several steps, primarily centered around handling the OAuth 2.0 authorization code flow. For simplicity and best practices, we'll use libraries like Authlib (a popular choice for OAuth clients in Python) and fastapi-microsoft-identity for Azure AD specifically.
Before you start:
Install necessary libraries:
Bashpip install fastapi uvicorn python-multipart python-jose[cryptography] authlib python-dotenv fastapi-microsoft-identitySet up environment variables: Create a
.envfile in your project root to store sensitive credentials.Google Cloud Console:
Create a new project or use an existing one.
Go to "APIs & Services" > "Credentials".
Create "OAuth client ID" (Web application).
Add
http://localhost:8000/auth/google/callbackto "Authorized redirect URIs".Note down your Client ID and Client Secret.
Enable the "Google People API" (or other APIs relevant to the scopes you request) if you want to fetch user profile information.
Azure AD (Entra ID) Portal:
Go to "App registrations" in your Azure AD tenant.
Register a new application for your FastAPI API.
For the API application (your backend):
Note down Application (client) ID and Directory (tenant) ID.
Go to "Expose an API" and set an Application ID URI (e.g.,
api://your-app-id). Add a scope (e.g.,access_as_user).Generate a Client Secret under "Certificates & secrets".
For a client application (e.g., a Single-Page Application, if you plan to use Swagger UI to log in):
Register another application for your client.
Under "Authentication", add a "Redirect URI" of type "Single-page application" (SPA) to
http://localhost:8000/oauth2-redirect.Under "API permissions", add the permission for your backend API's scope (e.g.,
access_as_user) and grant admin consent.
1. Google OAuth2 Integration
This example demonstrates the Authorization Code Flow with Google, where your FastAPI application acts as the client to Google's OAuth 2.0 service.
main.py
import os
from datetime import datetime, timedelta
from typing import Optional
from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.security import OAuth2PasswordBearer
from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client import OAuth
from jose import jwt, JWSAlgorithms
from dotenv import load_dotenv
load_dotenv()
# --- Configuration for Google OAuth ---
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = "http://localhost:8000/auth/google/callback" # Must match your Google Cloud Console setting
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-super-secret-key") # For your internal JWTs
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# --- FastAPI App Setup ---
app = FastAPI(
title="FastAPI OAuth Integrations",
description="Example for Google and Azure AD authentication",
docs_url="/docs",
redoc_url="/redoc"
)
# Session middleware is required for Authlib's OAuth client
app.add_middleware(SessionMiddleware, secret_key=os.getenv("SESSION_SECRET_KEY", "another-secret-key"))
oauth = OAuth()
oauth.register(
name='google',
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={'scope': 'openid email profile'},
)
# --- Internal JWT for authenticated users (after Google login) ---
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token") # This tokenUrl is for your API's internal token endpoint, if you had one.
# For external OAuth, we will issue a token upon successful login.
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 = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# --- Google OAuth Endpoints ---
@app.get("/auth/google/login")
async def login_google(request: Request):
"""
Redirects to Google for authentication.
"""
return await oauth.google.authorize_redirect(request, GOOGLE_REDIRECT_URI)
@app.get("/auth/google/callback")
async def auth_google_callback(request: Request):
"""
Handles the callback from Google after successful authentication.
"""
try:
token = await oauth.google.authorize_access_token(request)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Authentication failed: {e}"
)
user_info = await oauth.google.parse_id_token(request, token)
# Here, user_info contains user details from Google (e.g., 'email', 'name', 'sub')
# You would typically:
# 1. Look up the user in your database based on their Google ID (user_info['sub'] or 'email').
# 2. If the user doesn't exist, create a new user record.
# 3. Create an internal JWT for your application's session.
# For demonstration, we'll just create a simple JWT
user_data = {"email": user_info['email'], "name": user_info.get('name', 'N/A'), "google_id": user_info['sub']}
access_token = create_access_token(data=user_data, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
# Redirect to a frontend page or return the token directly (e.g., for SPA)
# For a real application, you'd typically redirect to your frontend with the token
# or set it in a secure cookie.
response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
response.set_cookie(key="access_token", value=access_token, httponly=True, max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60)
return response
@app.get("/google-protected-data")
async def get_google_protected_data(request: Request):
"""
An example protected endpoint.
Checks for the internal access_token cookie.
"""
access_token = request.cookies.get("access_token")
if not access_token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
try:
payload = jwt.decode(access_token, JWT_SECRET_KEY, algorithms=[ALGORITHM])
user_email = payload.get("email")
user_name = payload.get("name")
google_id = payload.get("google_id")
if user_email is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload")
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
return {"message": f"Hello, {user_name} ({user_email})! This is Google-protected data.", "google_id": google_id}
@app.get("/", response_class=HTMLResponse)
async def home():
return """
<html>
<head>
<title>FastAPI OAuth</title>
</head>
<body>
<h1>Welcome to FastAPI OAuth Demo</h1>
<p><a href="/auth/google/login">Login with Google</a></p>
<p><a href="/auth/azure/login">Login with Azure AD</a></p>
<p><a href="/google-protected-data">Access Google Protected Data (after Google login)</a></p>
<p><a href="/azure-protected-data">Access Azure Protected Data (after Azure login)</a></p>
</body>
</html>
"""
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
.env file (create this in the same directory as main.py)
GOOGLE_CLIENT_ID="YOUR_GOOGLE_CLIENT_ID"
GOOGLE_CLIENT_SECRET="YOUR_GOOGLE_CLIENT_SECRET"
JWT_SECRET_KEY="a-very-strong-and-random-secret-key-for-your-jwt"
SESSION_SECRET_KEY="another-long-random-string-for-session-middleware"
How to run (Google OAuth):
Make sure your
.envfile has the correctGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,JWT_SECRET_KEY, andSESSION_SECRET_KEY.Run the FastAPI app:
uvicorn main:app --reloadOpen your browser to
http://localhost:8000.Click "Login with Google". You'll be redirected to Google for login and consent.
After successful login, you'll be redirected back to
http://localhost:8000, and an internal JWT will be set as a cookie.Click "Access Google Protected Data" to see if your internal JWT works.
2. Azure AD Authentication Integration
For Azure AD, fastapi-microsoft-identity is a very convenient library as it handles much of the token validation complexity for you. It's designed to validate JWTs issued by Azure AD.
main.py (continuation from above, add the Azure AD parts)
import os
from datetime import datetime, timedelta
from typing import Optional
from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.security import OAuth2PasswordBearer
from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client import OAuth
from jose import jwt, JWSAlgorithms
from dotenv import load_dotenv
# --- Azure AD specific imports ---
from fastapi_microsoft_identity import initialize, requires_auth, AuthError, validate_scope
load_dotenv()
# --- Configuration for Google OAuth (already defined above) ---
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = "http://localhost:8000/auth/google/callback"
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-super-secret-key")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# --- Configuration for Azure AD ---
AZURE_TENANT_ID = os.getenv("AZURE_TENANT_ID")
AZURE_CLIENT_ID = os.getenv("AZURE_CLIENT_ID") # Client ID of your API app registration in Azure AD
AZURE_SCOPE = os.getenv("AZURE_SCOPE", "api://YOUR_AZURE_API_APP_ID/access_as_user") # This should be the scope you defined in Azure AD for your API
# Initialize fastapi-microsoft-identity
# Note: This is for validating tokens that *clients* send to your API.
# If your FastAPI app also acts as a client to Azure AD to get tokens for *itself*
# (e.g., if you were to implement a full user login flow initiated by FastAPI redirecting to Azure),
# you'd use Authlib's OAuth.register for 'microsoft' similar to 'google'.
# For now, we're focusing on FastAPI *validating* tokens issued by Azure AD.
try:
initialize(tenant_id=AZURE_TENANT_ID, client_id=AZURE_CLIENT_ID)
except ValueError as e:
print(f"Warning: Azure AD initialization failed. Ensure AZURE_TENANT_ID and AZURE_CLIENT_ID are set. Error: {e}")
# --- FastAPI App Setup (already defined above) ---
app = FastAPI(
title="FastAPI OAuth Integrations",
description="Example for Google and Azure AD authentication",
docs_url="/docs",
redoc_url="/redoc"
)
app.add_middleware(SessionMiddleware, secret_key=os.getenv("SESSION_SECRET_KEY", "another-secret-key"))
oauth = OAuth()
oauth.register(
name='google',
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={'scope': 'openid email profile'},
)
# --- Internal JWT for authenticated users (already defined above) ---
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/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 = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# --- Google OAuth Endpoints (already defined above) ---
@app.get("/auth/google/login")
async def login_google(request: Request):
return await oauth.google.authorize_redirect(request, GOOGLE_REDIRECT_URI)
@app.get("/auth/google/callback")
async def auth_google_callback(request: Request):
try:
token = await oauth.google.authorize_access_token(request)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Authentication failed: {e}"
)
user_info = await oauth.google.parse_id_token(request, token)
user_data = {"email": user_info['email'], "name": user_info.get('name', 'N/A'), "google_id": user_info['sub']}
access_token = create_access_token(data=user_data, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
response = RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
response.set_cookie(key="access_token", value=access_token, httponly=True, max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60)
return response
@app.get("/google-protected-data")
async def get_google_protected_data(request: Request):
access_token = request.cookies.get("access_token")
if not access_token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
try:
payload = jwt.decode(access_token, JWT_SECRET_KEY, algorithms=[ALGORITHM])
user_email = payload.get("email")
user_name = payload.get("name")
google_id = payload.get("google_id")
if user_email is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload")
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
return {"message": f"Hello, {user_name} ({user_email})! This is Google-protected data.", "google_id": google_id}
# --- Azure AD Protected Endpoint ---
@app.get("/azure-protected-data")
@requires_auth # This decorator from fastapi-microsoft-identity handles token validation
async def get_azure_protected_data(request: Request):
"""
An example endpoint protected by Azure AD.
Expects a Bearer token in the Authorization header issued by Azure AD.
"""
try:
# Optionally validate specific scopes
validate_scope(AZURE_SCOPE, request)
# Access token claims after successful validation
# The claims are available in request.state.user
claims = request.state.user
user_name = claims.get("name", "N/A")
user_email = claims.get("preferred_username", "N/A") # Or 'email'
tenant_id = claims.get("tid", "N/A")
return {
"message": f"Hello, {user_name} ({user_email})! This is Azure AD-protected data.",
"tenant_id": tenant_id,
"claims": claims # For debugging, shows all claims
}
except AuthError as e:
# fastapi-microsoft-identity raises AuthError for auth/authz issues
raise HTTPException(
status_code=e.status_code,
detail=e.detail,
headers={"WWW-Authenticate": "Bearer"}
)
except Exception as e:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
@app.get("/", response_class=HTMLResponse)
async def home():
return """
<html>
<head>
<title>FastAPI OAuth</title>
</head>
<body>
<h1>Welcome to FastAPI OAuth Demo</h1>
<p><a href="/auth/google/login">Login with Google</a></p>
<p>For Azure AD, you'd typically have a client application (e.g., SPA) that acquires the token and sends it to this API.
<br>
If you want to test the Azure AD protected endpoint, you can use a tool like Postman or fetch an access token from Azure AD
and include it in the 'Authorization: Bearer YOUR_AZURE_AD_TOKEN' header when calling '/azure-protected-data'.
</p>
<p><a href="/google-protected-data">Access Google Protected Data (after Google login)</a></p>
<p><a href="/azure-protected-data">Access Azure Protected Data (needs Azure AD Bearer Token)</a></p>
</body>
</html>
"""
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
.env file (updated)
GOOGLE_CLIENT_ID="YOUR_GOOGLE_CLIENT_ID"
GOOGLE_CLIENT_SECRET="YOUR_GOOGLE_CLIENT_SECRET"
JWT_SECRET_KEY="a-very-strong-and-random-secret-key-for-your-jwt"
SESSION_SECRET_KEY="another-long-random-string-for-session-middleware"
AZURE_TENANT_ID="YOUR_AZURE_TENANT_ID" # e.g., common or your tenant GUID
AZURE_CLIENT_ID="YOUR_AZURE_API_APP_ID" # Application (client) ID of your API app registration
AZURE_SCOPE="api://YOUR_AZURE_API_APP_ID/access_as_user" # The scope you defined in "Expose an API"
How to run (Azure AD):
Make sure your
.envfile has the correctAZURE_TENANT_ID,AZURE_CLIENT_ID, andAZURE_SCOPE. ReplaceYOUR_AZURE_API_APP_IDwith the actual Application (client) ID of your API app registration.Run the FastAPI app:
uvicorn main:app --reloadTo test the Azure AD protected endpoint (
/azure-protected-data):Unlike Google where FastAPI initiates the login, for Azure AD token validation, your FastAPI app is the Resource Server. This means a client application needs to obtain an access token from Azure AD first and then send it to your FastAPI API.
Method 1: Using Postman/Insomnia/curl:
You'll need to manually get an access token from Azure AD. This typically involves setting up an client application (e.g., a simple SPA or a Postman setup) that performs the Azure AD login.
Once you have an Azure AD access token, send a request to
http://localhost:8000/azure-protected-datawith theAuthorizationheader:Bearer YOUR_AZURE_AD_ACCESS_TOKEN.
Method 2 (For testing with Swagger UI):
If you registered a separate Azure AD application for your OpenAPI (Swagger) documentation and configured its redirect URI to
http://localhost:8000/oauth2-redirect, then you can use the "Authorize" button in the Swagger UI (/docs).You'll need to configure the
security_schemesin FastAPI'sOpenAPIobject for this to work seamlessly indocs. This is more advanced setup and often involvesfastapi-azure-authfor a comprehensive solution.
Example of manual token acquisition for testing (simplified, often done by a frontend):
If you were to acquire a token using a client application (e.g., a simple SPA or even a browser redirect for testing), the flow would be:
User clicks "Login with Azure AD" (on a frontend app).
Frontend redirects to Azure AD's authorization endpoint.
https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize?client_id={CLIENT_ID_OF_FRONTEND}&response_type=code&redirect_uri={REDIRECT_URI_OF_FRONTEND}&scope=openid profile {AZURE_SCOPE}
User logs in and consents.
Azure AD redirects back to
REDIRECT_URI_OF_FRONTENDwith anauthorization_code.Frontend exchanges this
codefor anaccess_tokenandid_tokenat Azure AD's token endpoint.Frontend then calls your FastAPI API, attaching the
access_tokenin theAuthorization: Bearerheader.
This setup provides a foundational understanding of how to integrate these authentication protocols. For production environments, consider:
Error Handling and Logging: More robust error handling and comprehensive logging.
Refresh Tokens: For long-lived sessions with Google and Azure AD.
Database Integration: Storing user information, linking Google/Azure IDs to your internal user IDs.
Role-Based Access Control (RBAC): Using roles/groups from ID tokens to control access to specific API endpoints beyond just authentication.
Custom Dependencies: Creating FastAPI dependencies to extract and validate user information from claims more cleanly.
CORS: If your frontend is on a different origin, you'll need CORS middleware.
Comments