Implementing Keycloak with Python FastAPI & PostgreSQL for Secure Authentication
Introduction
Authentication and authorization are at the heart of any modern web application. Instead of reinventing the wheel with custom auth systems, developers increasingly rely on proven, open-source Identity and Access Management (IAM) solutions like Keycloak. In this article, we’ll walk through integrating Keycloak with a Python FastAPI application using PostgreSQL as the database. Our focus will be on security best practices, scalable architecture, and professional coding standards.
Why Keycloak?
Description: Keycloak is an Open Source Identity and Access Management solution that supports Single Sign-On (SSO), OAuth2, OpenID Connect (OIDC), and more. It provides:
Using Keycloak ensures fewer security vulnerabilities, faster development, and better compliance with modern security standards like OAuth 2.0 and OpenID Connect.
System Architecture Overview
Description: Our setup will follow this architecture:
Flow:
Setting up Keycloak
Description: Before coding, ensure Keycloak is running. You can use Docker for a quick start.
Docker Command:
docker run -d --name keycloak \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
-p 8080:8080 \
quay.io/keycloak/keycloak:25.0.1 start-dev
Steps in Keycloak Admin Console:
FastAPI Project Setup
Description: We’ll create a FastAPI application that connects to PostgreSQL and validates JWT tokens from Keycloak.
Install dependencies:
pip install fastapi uvicorn python-keycloak psycopg2-binary SQLAlchemy python-jose
Folder Structure:
app/
├── main.py
├── config.py
├── database.py
├── auth/
│ ├── keycloak_utils.py
│ ├── dependencies.py
└── models.py
Connecting to PostgreSQL
Description: We’ll use SQLAlchemy for ORM and psycopg2 as the driver.
# database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os
DB_URL = os.getenv("DATABASE_URL", "postgresql://user:password@localhost:5432/fastapi_db")
engine = create_engine(DB_URL)
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()
Security Tip:
Recommended by LinkedIn
Integrating Keycloak in FastAPI
Description: We’ll use python-keycloak to interact with Keycloak’s API and python-jose for token validation.
# auth/keycloak_utils.py
from keycloak import KeycloakOpenID
import os
KEYCLOAK_SERVER = os.getenv("KEYCLOAK_SERVER", "http://localhost:8080/")
KEYCLOAK_REALM = os.getenv("KEYCLOAK_REALM", "fastapi-realm")
KEYCLOAK_CLIENT_ID = os.getenv("KEYCLOAK_CLIENT_ID", "fastapi-client")
KEYCLOAK_CLIENT_SECRET = os.getenv("KEYCLOAK_CLIENT_SECRET", "your-client-secret")
keycloak_openid = KeycloakOpenID(
server_url=f"{KEYCLOAK_SERVER}realms/{KEYCLOAK_REALM}",
client_id=KEYCLOAK_CLIENT_ID,
realm_name=KEYCLOAK_REALM,
client_secret_key=KEYCLOAK_CLIENT_SECRET,
)
Token Validation Middleware
Description: This middleware checks for the Bearer token and validates it.
# auth/dependencies.py
from fastapi import Depends, HTTPException, status
from jose import JWTError, jwt
from .keycloak_utils import keycloak_openid
def get_current_user(token: str):
try:
options = {"verify_aud": False}
decoded_token = keycloak_openid.decode_token(token, key=keycloak_openid.public_key(), options=options)
return decoded_token
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials"
)
Example Protected Route
Description: This endpoint requires a valid Keycloak-issued token.
# main.py
from fastapi import FastAPI, Depends
from auth.dependencies import get_current_user
app = FastAPI()
@app.get("/secure-data")
def secure_data(user=Depends(get_current_user)):
return {"message": f"Hello {user['preferred_username']}, secure content here!"}
Testing:
Obtain an access token from Keycloak:
curl -X POST "http://localhost:8080/realms/fastapi-realm/protocol/openid-connect/token" \
-d "client_id=fastapi-client" \
-d "client_secret=YOUR_SECRET" \
-d "grant_type=password" \
-d "username=youruser" \
-d "password=yourpass"
curl -H "Authorization: Bearer <ACCESS_TOKEN>" http://localhost:8000/secure-data
Screenshots:
Admin panel login:
Security Best Practices
Description: To maintain a high-security standard:
Conclusion
Description: By integrating Keycloak with FastAPI and PostgreSQL, you get a scalable, secure, and standards-compliant authentication system without reinventing the wheel. This approach keeps your application flexible, future-proof, and enterprise-ready.
#FastAPI #Keycloak #OAuth2 #OpenIDConnect #PythonDevelopment #PostgreSQL #APISecurity #JWT #SingleSignOn #BackendDevelopment #PythonTips #WebSecurity #Authentication #IdentityManagement #DevSecOps