caselaw-auth-server
Server-side OIDC for Python products, interchangeable with the
caselaw-auth npm package's
/server entry point.
A session cookie sealed by either implementation unseals in the other, byte for
byte. Both are written against packages/contract/contract.json, and both load
packages/contract/conformance/cases.json at test time — which is what keeps
them from drifting.
pip install caselaw-auth-server
Why
caselaw-auth/server is TypeScript, and half this estate is not: caselaw-access
is FastAPI and citations-api is a Python HTTP server. Without a Python
implementation, those two would have stayed on browser-side sessions purely
because of the language their backend happens to be written in — with the
refresh token in localStorage, where page script can read it.
Usage
from caselaw_auth_server import create_server_auth, create_pkce_pair, random_token
auth = create_server_auth(
issuer=os.environ["AUTH_ISSUER"], # .../realms/caselaw
client_id=os.environ["AUTH_CLIENT_ID"],
redirect_uri=os.environ["AUTH_REDIRECT_URI"],
session_secret=os.environ["AUTH_SESSION_SECRET"],
client_secret=os.environ.get("AUTH_CLIENT_SECRET"), # confidential clients
)
Start a sign-in:
verifier, challenge = create_pkce_pair()
state = random_token()
# state and verifier must survive the round trip and stay unreadable by page
# script — a short httpOnly cookie, not anything the browser can see.
url = auth.authorization_url(state=state, code_challenge=challenge)
Complete it:
tokens = auth.exchange_code(code=code, code_verifier=verifier)
claims = auth.verify_token(tokens["access_token"])
session = auth.session_from_claims(claims, id_token=tokens.get("id_token"))
cookie = auth.seal_session(session)
Read it on any request — an HMAC check, no network call:
session = auth.unseal_session(request.cookies.get("caselaw_session"))
if not session or "admin" not in session["roles"]:
raise Forbidden()
End it. id_token_hint is what makes this a real single sign-out:
auth.end_session_url(id_token=session.get("idToken"), return_to=site)
Mapping to the TypeScript package
Method names are idiomatic per language. Session keys are camelCase in both, because they are wire format rather than API surface: renaming them per language would break the property the whole contract exists to guarantee.
| TypeScript | Python |
|---|---|
createServerAuth(config) |
create_server_auth(...) |
authorizationUrl(options) |
authorization_url(...) |
exchangeCode(options) |
exchange_code(...) |
verifyToken(token, options) |
verify_token(token, ...) |
rolesFromClaims(claims) |
roles_from_claims(claims) |
sessionFromClaims(claims, options) |
session_from_claims(claims, ...) |
sealSession(session, name) |
seal_session(session, name) |
unsealSession(value) |
unseal_session(value) |
cookieOptions(maxAge, options) |
cookie_options(max_age, ...) |
endSessionUrl(options) |
end_session_url(...) |
createPkcePair() |
create_pkce_pair() |
Errors are typed here rather than string-matched: InvalidToken,
AuthBackendUnavailable and SessionTooLarge, all under AuthError. The split
between the first two is deliberate — collapsing them sends users to
re-authenticate during an outage, which cannot help and doubles the load on the
thing already failing.
Behaviour worth knowing
session_from_claimsdoes not keep the access token. Where one is genuinely needed, put it in a cookie of its own; a token in a cookie leaks with the cookie.- The session carries its own TTL, not the token's few minutes.
seal_sessionraises above 4096 bytes rather than returning a cookie the browser will silently discard.verify_tokendoes not checkaudby default. Keycloak putsaccountthere for a public client's access token and names the client inazp.- JWKS is cached and retried once; a token that is itself invalid is never retried.
Tests
pip install -e ".[dev]"
pytest
The suite loads the shared conformance cases by relative path. Running it from a checkout of this repository is therefore required — the cases are not vendored into the package.
Related
- caselaw-auth — the realm, themes, and both implementations
- docs/SERVER_SIDE_AUTH.md — the full walkthrough
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 caselaw_auth_server-0.3.0.tar.gz.
File metadata
- Download URL: caselaw_auth_server-0.3.0.tar.gz
- Upload date:
- Size: 11.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1ef2e812452c1e746b4c75157e199c4a4680b53cb29cef739ccde0cc697452b
|
|
| MD5 |
6673883eb848d4bff18418abc5ca81d5
|
|
| BLAKE2b-256 |
c59fd0b273320428ea5d3df393b3bae78055d61e9498c2f3652efc6b42c517c2
|
Provenance
The following attestation bundles were made for caselaw_auth_server-0.3.0.tar.gz:
Publisher:
publish-python.yml on MaastrichtU-BISS/caselaw-auth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
caselaw_auth_server-0.3.0.tar.gz -
Subject digest:
f1ef2e812452c1e746b4c75157e199c4a4680b53cb29cef739ccde0cc697452b - Sigstore transparency entry: 2503141872
- Sigstore integration time:
-
Permalink:
MaastrichtU-BISS/caselaw-auth@7ec5897e8e83bb41aac7831b6bbb8fa006f5d5dd -
Branch / Tag:
refs/tags/python-v0.3.0 - Owner: https://github.com/MaastrichtU-BISS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@7ec5897e8e83bb41aac7831b6bbb8fa006f5d5dd -
Trigger Event:
push
-
Statement type:
File details
Details for the file caselaw_auth_server-0.3.0-py3-none-any.whl.
File metadata
- Download URL: caselaw_auth_server-0.3.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d796e36faf1ddb797e8800002208ba6a9c18839afc7b84a52d2770109cf3e487
|
|
| MD5 |
d28dffce15f36df3df373feffb16f996
|
|
| BLAKE2b-256 |
6abb224b809ec8b661ac520ae04a042c042a027123b1de033465442667c66da1
|
Provenance
The following attestation bundles were made for caselaw_auth_server-0.3.0-py3-none-any.whl:
Publisher:
publish-python.yml on MaastrichtU-BISS/caselaw-auth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
caselaw_auth_server-0.3.0-py3-none-any.whl -
Subject digest:
d796e36faf1ddb797e8800002208ba6a9c18839afc7b84a52d2770109cf3e487 - Sigstore transparency entry: 2503142038
- Sigstore integration time:
-
Permalink:
MaastrichtU-BISS/caselaw-auth@7ec5897e8e83bb41aac7831b6bbb8fa006f5d5dd -
Branch / Tag:
refs/tags/python-v0.3.0 - Owner: https://github.com/MaastrichtU-BISS
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@7ec5897e8e83bb41aac7831b6bbb8fa006f5d5dd -
Trigger Event:
push
-
Statement type: