SSO authentication using Keycloak and LDAP in your FastAPI application

To enable SSO authentication using Keycloak and LDAP in your FastAPI application, you need to integrate OAuth 2.0 / OpenID Connect (OIDC) authentication using Keycloak as the identity provider. Here’s a step-by-step guide:


1. How It Works

  1. Users attempt to access FastAPI
  2. FastAPI redirects users to Keycloak for authentication
  3. Keycloak authenticates users via LDAP
  4. Keycloak returns an OAuth 2.0 token to the FastAPI application
  5. FastAPI validates the token and grants access

2. Prerequisites

  • A FastAPI application
  • A running Keycloak server with LDAP federation configured (Follow the existing blog)
  • Keycloak realm and client set up for OAuth 2.0 authentication
  • Python 3.7+ and fastapi, httpx, and pyjwt installed

3. Configure Keycloak for FastAPI OAuth 2.0

Step 1: Create a Keycloak Client

  1. Log in to Keycloak Admin Console:
    👉 http://localhost:8080/admin
  2. Select your realm (or create one)
  3. Navigate to Clients → Click Create
  4. Set the following:
    • Client ID: fastapi-client
    • Client Protocol: openid-connect
    • Root URL: http://localhost:8000
    • Access Type: Confidential
  5. Click Save

Step 2: Configure Credentials

  1. Go to Clients → fastapi-client → Credentials
  2. Copy the Client Secret for later use

Step 3: Add Redirect URI

  1. Under the FastAPI client → Settings section:
    • Set Valid Redirect URIs to http://localhost:8000/login
    • Click Save

4. Implement SSO in FastAPI

Install Required Packages

pip install fastapi uvicorn python-dotenv httpx pyjwt

Create FastAPI Application

1️⃣ Define Configuration

Create a .env file:

KEYCLOAK_SERVER_URL=http://localhost:8080
KEYCLOAK_REALM=myrealm
KEYCLOAK_CLIENT_ID=fastapi-client
KEYCLOAK_CLIENT_SECRET=<your_client_secret>
REDIRECT_URI=http://localhost:8000/login

2️⃣ FastAPI Code for SSO Authentication

Create main.py:

import os
import httpx
import jwt
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2AuthorizationCodeBearer
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Keycloak config
KEYCLOAK_URL = os.getenv("KEYCLOAK_SERVER_URL")
REALM = os.getenv("KEYCLOAK_REALM")
CLIENT_ID = os.getenv("KEYCLOAK_CLIENT_ID")
CLIENT_SECRET = os.getenv("KEYCLOAK_CLIENT_SECRET")
REDIRECT_URI = os.getenv("REDIRECT_URI")

# OAuth 2.0 flow
oauth2_scheme = OAuth2AuthorizationCodeBearer(
    tokenUrl=f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/token",
    authorizationUrl=f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/auth"
)

app = FastAPI()

# Step 1: Redirect to Keycloak Login
@app.get("/auth")
async def login():
    auth_url = (
        f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/auth?"
        f"client_id={CLIENT_ID}&response_type=code&"
        f"scope=openid&redirect_uri={REDIRECT_URI}"
    )
    return {"login_url": auth_url}

# Step 2: Handle Callback and Exchange Code for Token
@app.get("/login")
async def callback(code: str):
    token_url = f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/token"
    
    data = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": REDIRECT_URI,
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
    }

    async with httpx.AsyncClient() as client:
        response = await client.post(token_url, data=data)
        token_response = response.json()

    if "access_token" not in token_response:
        raise HTTPException(status_code=400, detail="Failed to authenticate")

    return {"access_token": token_response["access_token"]}

# Step 3: Protect Routes with Token Verification
def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, options={"verify_signature": False})
        return {"username": payload["preferred_username"]}
    except jwt.PyJWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

@app.get("/protected")
async def protected_route(user: dict = Depends(get_current_user)):
    return {"message": "You have accessed a protected route!", "user": user}

5. Running the FastAPI Server

uvicorn main:app --reload --port 8000

6. Testing SSO Authentication

  1. Visit http://localhost:8000/auth in your browser
  2. Redirects to Keycloak login
  3. Login with an LDAP user
  4. Keycloak redirects back to FastAPI with an authorization code
  5. FastAPI exchanges the code for an access token
  6. Use the access token to access protected routes: curl -H "Authorization: Bearer <ACCESS_TOKEN>" http://localhost:8000/protected

Conclusion

You’ve successfully implemented SSO authentication in FastAPI using Keycloak and LDAP. Now, users can log in via Keycloak, which authenticates them against LDAP.

Next Steps

✅ Implement Role-Based Access Control (RBAC)
✅ Secure APIs with OAuth 2.0 scopes
✅ Deploy Keycloak & FastAPI on Docker/Kubernetes

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *