Keycloak OIDC/OAuth2 authentication plugin for Litestar
Project description
litestar-keycloak
Keycloak authentication plugin for Litestar. OIDC/OAuth2 integration using Litestar's native plugin protocol, dependency injection, and guard system.
Features
- OIDC discovery and JWKS caching with automatic key rotation
- Bearer token validation (header or cookie)
- Realm and client role guards
- Scope-based access control
KeycloakUserinjection via Litestar DI- Optional login/callback/logout route group
- Async HTTP via aiohttp for token exchange and JWKS requests
Installation
pip install litestar-keycloak
Quick Start
from litestar import Litestar, get
from litestar_keycloak import KeycloakPlugin, KeycloakConfig, KeycloakUser
@get("/me")
async def me(current_user: KeycloakUser) -> dict:
return {
"sub": current_user.sub,
"username": current_user.preferred_username,
"roles": current_user.realm_roles,
}
app = Litestar(
route_handlers=[me],
plugins=[KeycloakPlugin(
KeycloakConfig(
server_url="https://keycloak.example.com",
realm="my-realm",
client_id="my-app",
)
)],
)
Any route that declares current_user: KeycloakUser automatically requires a valid Bearer token.
Guards
Restrict access by roles or scopes:
from litestar import get
from litestar_keycloak import require_roles, require_scopes
@get("/admin", guards=[require_roles("admin")])
async def admin_panel() -> dict:
return {"msg": "welcome, admin"}
@get("/reports", guards=[require_scopes("reports:read")])
async def reports() -> dict:
return {"msg": "here are your reports"}
Configuration
KeycloakConfig(
server_url="https://keycloak.example.com",
realm="my-realm",
client_id="my-app",
client_secret="secret", # confidential clients
token_location=TokenLocation.HEADER, # HEADER (default) or COOKIE
jwks_cache_ttl=3600, # JWKS cache lifetime in seconds
algorithms=("RS256",), # JWT signing algorithms
include_routes=False, # mount /auth/login, /callback, /logout
optional_audiences=frozenset({"my-service"}), # accept service tokens too
)
Full option list: docs/configuration.md.
When include_routes=True, the plugin mounts:
| Endpoint | Description |
|---|---|
GET /auth/login |
Redirect to Keycloak authorize |
GET /auth/callback |
Handle authorization code exchange |
POST /auth/logout |
End session (Keycloak + local) |
POST /auth/refresh |
Refresh access token |
Testing
Unit tests (no Keycloak required)
Test utilities live in tests/conftest.py: create_test_token() and MockKeycloakPlugin(). Use them in your tests (e.g. when running pytest from this repo, or import from conftest):
from tests.conftest import create_test_token, MockKeycloakPlugin
# Mint a fake JWT with arbitrary claims
token = create_test_token(sub="user-1", realm_roles=["admin"])
# Use MockKeycloakPlugin to skip real JWKS validation
app = Litestar(
route_handlers=[...],
plugins=[MockKeycloakPlugin()],
)
Integration tests (real Keycloak via testcontainers)
from testcontainers.keycloak import KeycloakContainer
kc = (
KeycloakContainer("quay.io/keycloak/keycloak:26.0")
.with_command("start-dev --import-realm")
.with_volume_mapping(
"tests/fixtures/realm-export.json",
"/opt/keycloak/data/import/realm-export.json",
"ro",
)
)
kc.start()
See tests/fixtures/realm-export.json for a pre-configured realm with test users and roles.
Service-to-service
To accept tokens from a service client (e.g. client_credentials), add its client ID to optional_audiences. Use the raw_token dependency to forward the caller's token to downstream APIs. See Service-to-service.
Documentation
- Guides: Configuration, Guards, OIDC routes, Testing. Build the site with
mkdocs build(ormkdocs serve). - Example app with docker-compose and smoke tests: examples/.
Dependencies
| Package | Purpose |
|---|---|
litestar[standard] ≥ 2.0 |
Web framework (plugin target) |
aiohttp |
Async HTTP for token/JWKS calls |
PyJWT[crypto] |
JWT validation |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file litestar_keycloak-0.1.0.tar.gz.
File metadata
- Download URL: litestar_keycloak-0.1.0.tar.gz
- Upload date:
- Size: 163.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96f8d1b16a34d83fc6acdee9aec3707a5cfe764d0851eda416c2ac34d5bfba21
|
|
| MD5 |
e51c2d0e22df5efd96f547d8be3e96bc
|
|
| BLAKE2b-256 |
86b65b36819bed0a0cbf5ac15d0b25a4091dd96a6b5b2055d7a081792799614f
|
Provenance
The following attestation bundles were made for litestar_keycloak-0.1.0.tar.gz:
Publisher:
publish.yml on smirnoffmg/litestar-keycloak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
litestar_keycloak-0.1.0.tar.gz -
Subject digest:
96f8d1b16a34d83fc6acdee9aec3707a5cfe764d0851eda416c2ac34d5bfba21 - Sigstore transparency entry: 1043067694
- Sigstore integration time:
-
Permalink:
smirnoffmg/litestar-keycloak@b0f218bc1b63bb3bbf7a5ff55fd3ab3b52c4500b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/smirnoffmg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b0f218bc1b63bb3bbf7a5ff55fd3ab3b52c4500b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file litestar_keycloak-0.1.0-py3-none-any.whl.
File metadata
- Download URL: litestar_keycloak-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1c3b3618a6de6d8ae0b0c5d089372f40f633d58c4bbada2838b16de32fd4dc9
|
|
| MD5 |
14a082471b96346a996eeca76c35a8a7
|
|
| BLAKE2b-256 |
ddeb605263bd116d920aafada38f46bcce260feb9867834a4d6a2ce8c0298f2f
|
Provenance
The following attestation bundles were made for litestar_keycloak-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on smirnoffmg/litestar-keycloak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
litestar_keycloak-0.1.0-py3-none-any.whl -
Subject digest:
b1c3b3618a6de6d8ae0b0c5d089372f40f633d58c4bbada2838b16de32fd4dc9 - Sigstore transparency entry: 1043067760
- Sigstore integration time:
-
Permalink:
smirnoffmg/litestar-keycloak@b0f218bc1b63bb3bbf7a5ff55fd3ab3b52c4500b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/smirnoffmg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b0f218bc1b63bb3bbf7a5ff55fd3ab3b52c4500b -
Trigger Event:
workflow_dispatch
-
Statement type: