Repository navigation
feat: verify-only resource server mode with audience, scope, role and step-up guards - #21
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A verify-only mode for a Python API that only receives OpenID Provider access tokens (RFC 9068 JWTs from the API's
/oidc/sign) asAuthorization: Bearer. It needs the issuer and an audience, and nothing else: no cookie secret, no service secret, no auth routes.ResourceServer(issuer, audience, *, jwks_uri=None, http_client=None, confirm=None, clock=None): OpenID discovery (or a fixedjwks_uri), then RS256 verification with explicitalg,typ(at+jwt),kid,crit, keyuse/alg,iss,aud,exp/nbf(5s skew),sub,client_id, first-partytypand claim type checks. Acnftoken is refused unless theconfirmhook accepts it (DPoP readiness, feat: sender-constrained tokens with DPoP (RFC 9449) seamless-auth-api#512).VerifiedUserwithscopes,client_id,sid,org_id,acr,amr,auth_time,roles.require_scope,require_role(a port ofroleGrantsAccessfrom@seamless-auth/types) andrequire_step_up(RFC 9470insufficient_user_authenticationchallenge).RequireBearer(server, *guards)andadd_bearer_error_handler(app). Django:SEAMLESS_RESOURCE_SERVERsettings,@require_bearerwith@require_scope,@require_role,@require_step_upbeneath it, andbearer_user_of(request).JwksCachenow takes the full key set URL and keeps each key'suse/alg. The existing adapter passes the same URL it built before and its verification is unchanged.Why
Parity with the JS, Go and Rust adapters for services behind the OpenID Provider (fells-code/seamless-auth-api#387): a FastAPI or Django service configured with only an issuer URL and an audience can require a scope, a role, or a recent passkey on any route.
The status codes, bodies and
WWW-Authenticatestrings follow the shared verify-only spec. The tests run the shared signed vectors, copied byte for byte from fells-code/seamless-auth-server (packages/core/tests/fixtures/verify-only/vectors.json) intotests/data/verify_only_vectors.json: everyverify[]entry against the verifier, and everyrequests[]entry through FastAPI and through Django (sync and async views). Adapter-local tests cover discovery (issuer mismatch, httpjwks_uriunder an https issuer, failure is 401 not 500, one discovery per process, 5s retry), construction errors, malformed tokens and the confirmation hook.The conformance reference apps are unchanged: the conformance contract has no verify-only routes yet.
Closes #16
Checks
uv sync --lockeduv run ruff check .: All checks passeduv run ruff format --check .: 39 files already formatteduv run mypy: Success, no issues found in 14 source filesuv run pytest: 502 passed (230 new)