Skip to main content

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_claims does 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_session raises above 4096 bytes rather than returning a cookie the browser will silently discard.
  • verify_token does not check aud by default. Keycloak puts account there for a public client's access token and names the client in azp.
  • 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

Metadata

Release files for caselaw-auth-server 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for caselaw-auth-server 0.3.0
File Size Uploaded
caselaw_auth_server-0.3.0.tar.gz 11.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for caselaw-auth-server 0.3.0
File Interpreter ABI Platform
caselaw_auth_server-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 22.0 kB

Release files / caselaw_auth_server-0.3.0.tar.gz

Download URL caselaw_auth_server-0.3.0.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f1ef2e812452c1e746b4c75157e199c4a4680b53cb29cef739ccde0cc697452b
BLAKE2b-256 checksum
How to use checksums
c59fd0b273320428ea5d3df393b3bae78055d61e9498c2f3652efc6b42c517c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / caselaw_auth_server-0.3.0-py3-none-any.whl

Download URL caselaw_auth_server-0.3.0-py3-none-any.whl
Size 10.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d796e36faf1ddb797e8800002208ba6a9c18839afc7b84a52d2770109cf3e487
BLAKE2b-256 checksum
How to use checksums
6abb224b809ec8b661ac520ae04a042c042a027123b1de033465442667c66da1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page