Skip to main content

SPNEGO / Kerberos (HTTP Negotiate) authentication provider for FastAPI and Starlette

Project description

fastapi-spnego

SPNEGO / Kerberos (HTTP Negotiate) authentication for FastAPI and Starlette.

The one enterprise auth mechanism with no FastAPI library — until now. Where fastapi-ldap covers LDAP and Authlib covers OAuth2/OIDC, Kerberos/SPNEGO users have been told to bolt on Keycloak. This package fills that gap: a small, framework-idiomatic Negotiate provider you drop in as a dependency.

Status: alpha. The dependency, the optional ASGI middleware, and credential delegation are implemented and covered by unit tests. The real GSSAPI path is proven end-to-end against a containerized MIT KDC (docker compose run --rm test) — genuine kinit + Negotiate handshake, mutual auth, and delegation.

Install

pip install fastapi-spnego[gssapi]   # Linux/macOS; needs libkrb5-dev

Platform support: the server-side GSSAPI backend runs on Linux and macOS (where FastAPI is almost always deployed). Windows clients authenticate normally against it. A Windows/SSPI server backend is on the roadmap. The base package is pure-Python and imports anywhere; the gssapi extra is what requires system Kerberos libraries.

Use

from fastapi import Depends, FastAPI
from fastapi_spnego import SpnegoAuth, SpnegoIdentity

app = FastAPI()
spnego = SpnegoAuth()

@app.get("/whoami")
def whoami(identity: SpnegoIdentity = Depends(spnego)):
    return {"user": identity.username, "realm": identity.realm}

Configure via SPNEGO_ env vars (see fastapi_spnego/config.py):

export SPNEGO_HOSTNAME=app.example.com     # FQDN of the service principal
export SPNEGO_KEYTAB=/etc/app.keytab       # HTTP/app.example.com@REALM
export SPNEGO_ALLOW_DELEGATION=true        # capture forwarded client TGTs (optional)
export SPNEGO_ACCEPT_ANY_PRINCIPAL=true    # accept any SPN in the keytab (reverse proxies)

Deploying for real (keytab creation, browser SPNEGO allowlisting, reverse-proxy notes, troubleshooting) is covered in docs/deploying.md.

A bad or missing token is handled for you: no credentials → 401 with a WWW-Authenticate: Negotiate challenge; an invalid token → 403 (never a 500). Set SPNEGO_AUTO_ERROR=false for optional auth, where the dependency returns None instead of challenging.

Global middleware (alternative)

Prefer the Depends() above for most apps. If you'd rather apply Negotiate globally and read the identity off request.state (Flask before_request style), use the middleware:

from fastapi import FastAPI, Request
from fastapi_spnego import SpnegoMiddleware

app = FastAPI()
app.add_middleware(SpnegoMiddleware, exclude_paths=["/health", "/metrics"])

@app.get("/whoami")
def whoami(request: Request):
    identity = request.state.spnego_identity
    return {"user": identity.username}

Credential delegation

With SPNEGO_ALLOW_DELEGATION=true, when a client forwards (delegates) its TGT the server stores it in a per-user credentials cache and exposes the handle on the identity, so your app can act onward as that user:

from fastapi_spnego import ticket_lifetime, cleanup

identity.delegated_ccache             # "FILE:/tmp/fastapi_spnego_ccache/cache_alice_EXAMPLE.COM"
ticket_lifetime(identity.delegated_ccache)   # remaining seconds, or None if gone/expired
# use it: env KRB5CCNAME=<handle> for an onward Kerberos connection
cleanup(identity.delegated_ccache)    # remove the ccache on logout/teardown

Re-authentication refreshes the ccache automatically. Requires the SPN to be flagged trusted for delegation and the client to opt in (GSSAPI/SSPI-only; the GSSAPI backend supports this, pyspnego will not).

Design

  • A Depends(), not a global. Fits FastAPI's DI model; trivial to override in tests.
  • Pluggable backend. GSSAPI first (Linux/macOS, supports credential delegation); a pyspnego backend for Windows/SSPI is on the roadmap.
  • Non-blocking. GSSAPI calls run in a threadpool.
  • Just a provider. Returns a verified principal; your app owns users/sessions/RBAC.

Requirements were distilled from pgAdmin's production Kerberos implementation.

Development

This project uses uv for environment and dependency management.

uv sync                 # create .venv + install the base dev group
uv run pytest           # run the test suite
uv run ruff check .     # lint
uv run ruff format .    # format
uv run mypy fastapi_spnego

The base dev group is pure-Python and installs anywhere. To run the integration tests that exercise the real GSSAPI backend you also need the gssapi group, which requires system Kerberos headers (krb5-config on PATH, e.g. apt install libkrb5-dev):

uv sync --group gssapi

uv.lock is committed for reproducible dev/CI environments. It does not affect consumers, who install the published package via pip as usual.

End-to-end test against a real KDC

The unit tests use a fake backend and need no Kerberos. The real proof — an actual kinit + Negotiate handshake against the GSSAPI backend — runs in Docker, which stands up a throwaway MIT KDC, the app, and a client:

docker compose run --rm --build test   # KDC + app + integration suite
docker compose up --build app           # or: just serve on localhost:8000

This exercises the challenge, a successful handshake with mutual auth, and credential delegation. See docker-compose.yml and docker/.

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

fastapi_spnego-0.2.0.tar.gz (122.0 kB view details)

Uploaded Source

Built Distribution

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

fastapi_spnego-0.2.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_spnego-0.2.0.tar.gz.

File metadata

  • Download URL: fastapi_spnego-0.2.0.tar.gz
  • Upload date:
  • Size: 122.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastapi_spnego-0.2.0.tar.gz
Algorithm Hash digest
SHA256 63d0fb70755b9fdd8e2520b2467854c602e7aeba92db5588a6d93e1d666f3d68
MD5 8ae8253d00308e19f1a5978c0abf6894
BLAKE2b-256 b855bc10a4eee9ebe4943ed812f6df143f3109167e70e8f0fc16403cc673e91d

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_spnego-0.2.0.tar.gz:

Publisher: publish.yml on gvozdetsky/fastapi-spnego

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_spnego-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_spnego-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastapi_spnego-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3b9d369d2b01edbc75bc1831cc76af77a12eea37ce290ced9920747f92c53c62
MD5 10a9aba34fb426ba7ce830fc69d2a69c
BLAKE2b-256 959e269fd19891cb4c4182af4473f98e20d113f1e1c45ea196fa2b94409a2083

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_spnego-0.2.0-py3-none-any.whl:

Publisher: publish.yml on gvozdetsky/fastapi-spnego

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