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) — genuinekinit+ 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)
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:
identity.delegated_ccache # e.g. "FILE:/tmp/fastapi_spnego_ccache/cache_alice_EXAMPLE.COM"
# use it: env KRB5CCNAME=<handle> for an onward Kerberos connection
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
pyspnegobackend 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
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 fastapi_spnego-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_spnego-0.1.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7961909a2b0a81caade341e3a6fc1f36de1a69812873ea8d5623cb20caab8992
|
|
| MD5 |
ef63d31d4bed6582e32d3dc10692370a
|
|
| BLAKE2b-256 |
7cac64204eeac85f553f449ed359208668761a3f0e094eb69bf788dd0b7ef435
|
Provenance
The following attestation bundles were made for fastapi_spnego-0.1.0.tar.gz:
Publisher:
publish.yml on gvozdetsky/fastapi-spnego
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_spnego-0.1.0.tar.gz -
Subject digest:
7961909a2b0a81caade341e3a6fc1f36de1a69812873ea8d5623cb20caab8992 - Sigstore transparency entry: 2105833572
- Sigstore integration time:
-
Permalink:
gvozdetsky/fastapi-spnego@b27c7b0c35feba0dd805239ffe3f07fd9601ddb7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gvozdetsky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b27c7b0c35feba0dd805239ffe3f07fd9601ddb7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fastapi_spnego-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_spnego-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ee7db095248fe71ac4614d2a2e4a7cb79fa078488bd93e7616a2358047f7cf3
|
|
| MD5 |
5808b42df70bf71e0da3812dd3cb5294
|
|
| BLAKE2b-256 |
deade6a3510ee96b1848d9ffffecd31392df6786a7b2213813e2353efeabd66a
|
Provenance
The following attestation bundles were made for fastapi_spnego-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on gvozdetsky/fastapi-spnego
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapi_spnego-0.1.0-py3-none-any.whl -
Subject digest:
5ee7db095248fe71ac4614d2a2e4a7cb79fa078488bd93e7616a2358047f7cf3 - Sigstore transparency entry: 2105833671
- Sigstore integration time:
-
Permalink:
gvozdetsky/fastapi-spnego@b27c7b0c35feba0dd805239ffe3f07fd9601ddb7 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gvozdetsky
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b27c7b0c35feba0dd805239ffe3f07fd9601ddb7 -
Trigger Event:
push
-
Statement type: