Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FastAPI Keycloak Integration

Overview

This project demonstrates how to integrate Keycloak authentication with a FastAPI application.

Prerequisites

  • Python 3.8+
  • Keycloak server running
  • FastAPI and dependencies installed

Project Structure

.
├── main.py           # FastAPI application entry point
├── settings.py       # Keycloak configuration settings
├── auth.py           # Authentication utilities
├── pyproject.toml    # Project dependencies
└── README.md         # This file

Setup with uv

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 sync

Configuration

Set 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>

Usage

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_data

To 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 response

To 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."}

Running the Server

To run the dev server

fastapi dev main.py

To run the server without reload

fastapi run main.py

License

MIT

About

Implementation of oauth2 authentication in a FastAPI application with keycloak

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages