Phase 2: OAuth 2.1 RFC compliance - #13
Open
manish-wekan wants to merge 1 commit into
Open
Conversation
Add PKCE (RFC 7636) as a standalone, fully-tested utility module — not wired into a local authorization-code exchange endpoint, since nitrostack is an OAuth resource server and never issues tokens itself in either SDK. Expand OAuthService: cache JWKS clients and introspection results (TTL-based), check the introspection endpoint before JWKS to match the TypeScript SDK's precedence, and validate the token's audience claim (RFC 8707) on both validation paths instead of only the JWKS one. Remove the fallback that treated any bearer token as valid when neither JWKS nor an introspection endpoint was configured. Unconfigured now means reject, matching the TypeScript reference, which has no such fallback. Expand the discovery server: full RFC 8414 authorization-server metadata instead of a 3-field stub, and a Dynamic Client Registration (RFC 7591) endpoint using the same simplified static-credential variant the TypeScript SDK ships — opt-in, hands back pre-configured credentials, no per-client storage. Add AuthContext.aud so guard code can see which audience a token was issued for, normalized to a list since the claim is legal as either a string or a list. tests/test_oauth.py grows from 1 test to 19, including a named regression test for the removed mock-fallback and coverage for the new caches, audience checks, discovery document shape, and registration gating.
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.
Closes the RFC-compliance gaps in
nitrostack/auth/oauth.pytracked as Phase 2 of the modernization plan.Added
nitrostack/auth/pkce.py, a standalone, fully-tested utility module (verifier/challenge generation, verification, format validation). Not wired into a local authorization-code exchange endpoint: nitrostack is an OAuth resource server, never an authorization server, in either SDK — it validates incoming tokens but never issues them. The TypeScript reference confirms this scope.audclaim is now checked against the configured resource on both validation paths. Previously only the JWKS path enforced this (via PyJWT internally); the introspection-endpoint path had no check at all, meaning a token issued for a different resource would have been silently accepted./.well-known/oauth-authorization-servernow serves all commonly-required fields instead of 3.nitrostack/auth/oauth_module.py, aPOST /oauth/v2/registerendpoint. This is the same simplified, static-credential variant the TypeScript SDK ships (opt-in, hands back pre-configuredclient_id/client_secret, no per-client storage), not full multi-tenant DCR — matches what TS actually does, not the plan file's more elaborate wording.AuthContext.aud— surfaces the audience claim to guard/tool code, normalized to a list.Changed
OAuthServiceconfigured with neitherJWKS_URInorOAUTH_INTROSPECTION_ENDPOINTtreated any bearer token as valid — a misconfigured production deployment would silently accept everything. It now returnsactive: False, matching the TypeScript SDK, which has no such fallback. Has its own named regression test (test_unconfigured_service_rejects_by_default) so this can't silently regress back.Testing
tests/test_oauth.pygrows from 1 test to 19 (pytest tests/test_oauth.py -v— all passing), covering PKCE round-trips and boundary cases, audience validation on both paths, the mock-fallback regression, RFC 8414 required-field coverage, DCR gating (disabled by default, requires both an opt-in flag and a configured client id), and both caches (JWKS client construction count, token-result reuse, TTL expiry).Full suite (
test_basic,test_tasks— 45 passed,test_initial_tool,test_production,test_transports,test_widget_metadata,test_tool_input_schema,test_cli— 59 passed) — zero regressions.examples/flight_booking_server.pystill imports and executes cleanly, matching its pre-change baseline. Manually verified the discovery server's actual wire output withcurlagainst/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource.