This project demonstrates how to integrate Keycloak authentication with a FastAPI application.
- Python 3.8+
- Keycloak server running
- FastAPI and dependencies installed
.
├── main.py # FastAPI application entry point
├── settings.py # Keycloak configuration settings
├── auth.py # Authentication utilities
├── pyproject.toml # Project dependencies
└── README.md # This file
This project uses uv for fast Python package management.
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv syncSet up your Keycloak connection details in .env.local file:
KEYCLOAK_REALM=<keycloak-realm>
KEYCLOAK_BASE_URL=<keycloak-base-url>
KEYCLOAK_CLIENT_ID=<keycloak-implicit-client-id>This is a sample example, which will show the current connected user, you can access it at /, if the user is not authenticated it will be redirected to keycloak login page:
@app.get("/")
async def home(request: Request):
# Extract user data every time the route is hit
user_data = get_current_user_data(request)
# If no user, you might want to redirect to login
if not user_data:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user_dataTo logout you can use this route /logout
@app.get("/logout")
async def logout(request: Request):
# 1. Get the ID Token (needed for Keycloak to skip the 'Confirm Logout' page)
# If you aren't storing id_token separately, you might use the auth_token
# if it's an ID Token, or just omit the hint (user will have to click 'Logout' manually).
id_token = request.cookies.get("id_token")
# 2. Define your app's landing page after logout
# Ensure this URL is added to "Valid Post Logout Redirect URIs" in Keycloak Client settings
post_logout_url = str(request.base_url)
# 3. Construct Keycloak Logout URL
keycloak_logout_base = f"{settings.keycloak_realm_url}/protocol/openid-connect/logout"
params = {
"client_id": settings.keycloak_client_id,
"post_logout_redirect_uri": post_logout_url
}
if id_token:
params["id_token_hint"] = id_token
logout_url = f"{keycloak_logout_base}?{urllib.parse.urlencode(params)}"
# 4. Create response that redirects to Keycloak
response = RedirectResponse(url=logout_url)
# 5. Reset/Clear local cookies
# Note: 'path' must match the path used when the cookie was set (usually "/")
response.delete_cookie(key="auth_token", path="/", httponly=True)
response.delete_cookie(key="id_token", path="/", httponly=True)
return responseTo use an unprotected route you can use this example:
@app.get("/unprotected")
async def unprotected_route(request: Request):
return {"message": "This route is unprotected and does not require authentication."}To run the dev server
fastapi dev main.pyTo run the server without reload
fastapi run main.pyMIT