Skip to main content

Keycloak authentication backend for FastAPI

Project description

Keycloak Authentication Backend for FastAPI

Provides Starlette/FastAPI Authentication backend modules for Keycloak.

Install

pip install fastapi-auth-keycloak

Examples

from fastapi import FastAPI, HTTPException, Request, status
from fastapi_auth_keycloak import KeycloakUser, KeycloakAuthBackend
from starlette.datastructures import Secret
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware

backend = KeycloakAuthBackend(
    url="https://my-keycloak.com/",
    realm="my-realm",
    client_id="70a82a5a-b671-4acb-9ecf-b5dcce0305e3",
    client_secret=Secret("<client-secret>"),
    audience="my_aud", # This can be a list of accepted audiences, or an empty list for any
    # authentication_required=False, <- Set this to allow unauthenticated requests; defaults to `True`
)

app = FastAPI()
app.add_middleware(AuthenticationMiddleware, backend=backend)

@app.get("/user/name")
def get_current_user_identity(request: Request):
    return request.user.display_name

@app.get("/privileged/area")
def get_privileged_data(request: Request):
    if not request.auth.has_role(client="alpha-app", role="super-user"):
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "User not authenticated.")

    return {"OMG TOP SECRET"}

@app.get("/no-homers")
def get_no_homers_data(request: Request):
    if request.user.groups is not None and "/homers/simpson" in request.user.groups:
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "User not authenticated.")

    return {"Welcome Homer Glumplich!"}

UMA Authorization

This module supports using User-Managed Access (UMA) 2.0 Grant for OAuth 2.0 Authorization to authorize access to resources via the KeycloakAuthCredentials object, provided via Request.auth.

If the user's JWT does not currently authorize them to access the specified resource and scope(s) if provided, the authorize method will throw an HTTP 401 response with a WWW-Authenticate header to indicate to the client that they should obtain a UMA 2.0-compliant Requesting Party Token (RPT, of type urn:ietf:params:oauth:grant-type:uma-ticket) to be authorized to access the resource. See the specification for details.

from fastapi import FastAPI, HTTPException, Request, status
from fastapi_auth_keycloak import KeycloakUser, KeycloakAuthBackend
from starlette.datastructures import Secret
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware

backend = KeycloakAuthBackend(
    url="https://my-keycloak.com/",
    realm="my-realm",
    client_id="70a82a5a-b671-4acb-9ecf-b5dcce0305e3",
    client_secret=Secret("<client-secret>"),
    audience="my_aud",
)

app = FastAPI()
app.add_middleware(AuthenticationMiddleware, backend=backend)

@app.get("/user/name")
def get_current_user_identity(request: Request):
    return request.user.display_name

@app.get("/privileged/area")
def get_privileged_data(request: Request):
    # Assert user is authorized
    request.auth.authorize(resource_name="privileged_data", scope="privileged_data:read")
    return {"What privilege!"}

You can also authorize by a specific Resource Id if you have it:

@app.get("/privileged/area/{id}")
def get_privileged_data(request: Request, id: str):
    request.auth.authorize_by_id(resource_id=id, scope="privileged_data:read")
    return {f"Looks like you are allowed to see area {id}!"}

FastAPI-Auth also provides a UMAAuthorize class that can be used as a FastAPI dependency to authorize endpoint resources:

from fastapi import Depends
from fastapi_auth_keycloak.uma import UMAAuthorized
from typing_extensions import Annotated

@app.post("/privileged/area")
def add_privileged_data(
    authorized: Annotated[UMAAuthorize, Depends(UMAAuthorize("privileged_data", "privileged_data:write"))]
):
    # The dependency has already asserted the user is authorized, so you can jump straight to your endpoint logic.
    # You can also access the user and auth objects from the injected object:
    user_id = authorized.user.identity
    scopes = authorized.auth.scopes

If you need to check other Keycloak-specific (e.g., not OAuth2 or UMA2 standard) claims, you can instead use the KeycloakUMAAuthorize dependency:

from fastapi import Depends
from fastapi_auth_keycloak import KeycloakUMAAuthorized
from typing_extensions import Annotated

@app.post("/privileged/area")
def add_privileged_data(
    authorized: Annotated[KeycloakUMAAuthorized, Depends(KeycloakUMAAuthorized("privileged_data", "privileged_data:write"))]
):
    # Also check if a user has a specific client role:
    if authorized.auth.has_role(client="my_realm_client", role="my_client_role"):
        # Do other stuff
        ...

Basic JWT

This library also provides an Auth Backend for barebones JWTs:

from fastapi import FastAPI, HTTPException, Request, status
from fastapi_auth_keycloak import PublicKey
from fastapi_auth_keycloak.jwt import JWTUser, JWTAuthBackend
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware

backend = JWTAuthBackend(
    algorithms=["RS256"],
    audience="my_aud", # This can be a list of accepted audiences, or an empty list for any
    key=PublicKey("<public key>"),
    # authentication_required=False, <- Set this to allow unauthenticated requests; defaults to `True`
)

app = FastAPI()
app.add_middleware(AuthenticationMiddleware, backend=backend)

@app.get("/user/identity")
def get_current_user_identity(request: Request):
    return request.user.identity

Contributing

This package utilizes Poetry for dependency management and pre-commit for ensuring code formatting is automatically done and code style checks are performed.

git clone https://github.com/Daveography/fastapi-auth-keycloak.git fastapi-auth-keycloak
cd fastapi-auth-keycloak
pip install poetry
poetry install
poetry run pre-commit install
poetry run pre-commit autoupdate

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

fastapi_auth_keycloak-0.8.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

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

fastapi_auth_keycloak-0.8.0-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_auth_keycloak-0.8.0.tar.gz.

File metadata

  • Download URL: fastapi_auth_keycloak-0.8.0.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for fastapi_auth_keycloak-0.8.0.tar.gz
Algorithm Hash digest
SHA256 e570f07d14d7c58f82c5ae9d6966c107a0f6a9d026635ca68fcd59cfa9dabd24
MD5 3c286f2d80a8f06f87a7584bff3e7edf
BLAKE2b-256 99a90793347da307e59c6fd4146712a6f91827550deb7a37f8762f6060d5bc42

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_auth_keycloak-0.8.0.tar.gz:

Publisher: publish.yaml on Daveography/fastapi-auth-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 fastapi_auth_keycloak-0.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_auth_keycloak-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 60e6832c60553d5f800d6940fad490386d05f5178df6455c19225e09420123bb
MD5 096cd1acde69633eb5761944bb1e0dac
BLAKE2b-256 2c6ca208f4051e591f674dd269892351209e46f1d799c50b7e50af139531fe48

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_auth_keycloak-0.8.0-py3-none-any.whl:

Publisher: publish.yaml on Daveography/fastapi-auth-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