Skip to main content

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
  • KeycloakUser injection 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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

litestar_keycloak-0.1.0.tar.gz (163.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

litestar_keycloak-0.1.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

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

Hashes for litestar_keycloak-0.1.0.tar.gz
Algorithm Hash digest
SHA256 96f8d1b16a34d83fc6acdee9aec3707a5cfe764d0851eda416c2ac34d5bfba21
MD5 e51c2d0e22df5efd96f547d8be3e96bc
BLAKE2b-256 86b65b36819bed0a0cbf5ac15d0b25a4091dd96a6b5b2055d7a081792799614f

See more details on using hashes here.

Provenance

The following attestation bundles were made for litestar_keycloak-0.1.0.tar.gz:

Publisher: publish.yml on smirnoffmg/litestar-keycloak

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file litestar_keycloak-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for litestar_keycloak-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b1c3b3618a6de6d8ae0b0c5d089372f40f633d58c4bbada2838b16de32fd4dc9
MD5 14a082471b96346a996eeca76c35a8a7
BLAKE2b-256 ddeb605263bd116d920aafada38f46bcce260feb9867834a4d6a2ce8c0298f2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for litestar_keycloak-0.1.0-py3-none-any.whl:

Publisher: publish.yml on smirnoffmg/litestar-keycloak

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page