Skip to content

docs(oauth): document step-up claims and parameters in the OpenAPI spec - #21121

Draft
StaberindeZA wants to merge 1 commit into
mainfrom
fxa-12864-docs
Draft

docs(oauth): document step-up claims and parameters in the OpenAPI spec#21121
StaberindeZA wants to merge 1 commit into
mainfrom
fxa-12864-docs

Conversation

@StaberindeZA

Copy link
Copy Markdown
Contributor

Because

  • The step-up work in FXA-12763 shipped acr_values / max_age on the authorization endpoints and acr / auth_time / amr on introspection, but the generated OpenAPI reference does not mention any of it. The /v1/introspect example response is stale relative to the Joi schema.
  • RPs read that reference via https://mozilla.github.io/ecosystem-platform/api, which is pulled daily from the deployed swagger.json. Anything not annotated here is invisible to them.
  • acr and amr were added to the introspect response schema without .description(), so they render bare.

This pull request

  • shared/descriptions.ts — adds acr, amr, authTime constants; expands acrValues (only AAL2 is recognised, other tokens ignored) and maxAge (five-second leeway, measured against the session's most recent authentication event). Fixes an assuarance typo in the existing acrValues text.
  • oauth-server-api.ts — step-up notes on GET/POST /v1/authorization and POST /v1/token; /v1/introspect notes plus acr / auth_time / amr in the example response; errno 170 added to the error table, where it was missing alongside the pre-existing 119 and 120.
  • introspect.js — wires the bare acr and amr Joi keys to the new description constants.

Two things the notes state explicitly, because both are easy to get wrong and neither was written down:

  • A refresh_token grant produces a token with no acr / auth_time, and that token still introspects as active: true — so a check that only reads active will not notice the elevation is gone.
  • auth_time is in seconds while iat / exp on /v1/introspect are in milliseconds. Intentional and retained for back-compat, but a ~1000x trap.

Issue that this pull request solves

Closes: FXA-12864

Checklist

Put an x in the boxes that apply

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Key files/areas to focus on: the wording in shared/descriptions.ts, since those strings are the RP-facing contract.
  • Suggested review order: descriptions.tsoauth-server-api.tsintrospect.js.
  • Risky or complex parts: none functionally — the only non-comment change is attaching .description() to two existing Joi keys, which does not alter validation. lib/routes/oauth/{introspect,authorization,index}.spec.ts and lib/oauth/grant.spec.ts pass (89 tests).

Other information (Optional)

Overlaps with #21103. An earlier revision of this branch also edited OAUTH_AUTHORIZATION_POST in oauth-api.ts. #21103 rewrites the same block and does it better — it correctly notes the unmet_authentication_requirements redirect comes from the hosted UI rather than the endpoint, and scopes it to prompt=none. That hunk has been dropped here, so this branch no longer touches oauth-api.ts and the two should merge cleanly in either order. The prompt=none behaviour is mirrored in the /v1/ notes for consistency, which reads as forward-looking until #21103 lands.

The prose half of FXA-12864 is mozilla/ecosystem-platform#803.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings August 27, 2026 21:26
@StaberindeZA
StaberindeZA requested a review from a team as a code owner August 27, 2026 21:26
@StaberindeZA
StaberindeZA marked this pull request as draft August 27, 2026 21:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Documents OAuth step-up parameters, claims, errors, and token behavior in the generated OpenAPI reference.

Changes:

  • Expands shared descriptions for step-up parameters and claims.
  • Adds step-up guidance and examples to OAuth endpoints.
  • Annotates introspection claim schemas.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/fxa-auth-server/docs/swagger/shared/descriptions.ts Defines RP-facing claim and parameter descriptions.
packages/fxa-auth-server/docs/swagger/oauth-server-api.ts Updates endpoint notes, errors, and examples.
packages/fxa-auth-server/lib/routes/oauth/introspect.js Attaches descriptions to introspection claims.
Suppressed comments (4)

packages/fxa-auth-server/docs/swagger/oauth-server-api.ts:97

  • This documents prompt=none as already redirecting with unmet_authentication_requirements, but the linked #21103 that adds this behavior is still open and blocked; the current settings flow routes errno 170 to an interactive challenge. Block this PR on #21103 or qualify/remove this claim until that change lands so the deployed OpenAPI reference does not advertise unavailable behavior.
      retrying. Where it cannot challenge — the RP also sent \`prompt=none\` — the UI instead
      redirects to the registered \`redirect_uri\` with
      \`error=unmet_authentication_requirements\`.

packages/fxa-auth-server/docs/swagger/oauth-server-api.ts:134

  • This documents prompt=none as already redirecting with unmet_authentication_requirements, but the linked #21103 that adds this behavior is still open and blocked; the current settings flow routes errno 170 to an interactive challenge. Block this PR on #21103 or qualify/remove this claim until that change lands so the deployed OpenAPI reference does not advertise unavailable behavior.
      retrying. Where it cannot challenge — the RP also sent \`prompt=none\` — the UI instead
      redirects to the registered \`redirect_uri\` with
      \`error=unmet_authentication_requirements\`.

packages/fxa-auth-server/docs/swagger/oauth-server-api.ts:138

  • The claim distribution omits amr from ID tokens, although generateIdToken copies grant.amr into the ID-token claims and the integration test asserts it. This contrast with introspection makes the new RP-facing documentation misleading; distinguish the three token surfaces explicitly.
      The resulting grant carries \`acr\` and \`auth_time\` on the ID token and the JWT access
      token, and \`acr\`, \`auth_time\` and \`amr\` via the \`/v1/introspect\` endpoint. These are not carried by
      refresh tokens, so an elevated authentication does not survive a token refresh.

packages/fxa-auth-server/docs/swagger/oauth-server-api.ts:101

  • The claim distribution omits amr from ID tokens, although generateIdToken copies grant.amr into the ID-token claims and the integration test asserts it. This contrast with introspection makes the new RP-facing documentation misleading; distinguish the three token surfaces explicitly.
      The resulting grant carries \`acr\` and \`auth_time\` on the ID token and the JWT access
      token, and \`acr\`, \`auth_time\` and \`amr\` via the \`/v1/introspect\` endpoint. These are not carried by
      refresh tokens, so an elevated authentication does not survive a token refresh.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

accessType:
'If specified, a value of `offline` will cause the connecting client to be granted a refresh token alongside its access token.',
acr:
'The authentication context class reference reached by the session that produced this grant, as a string of the form `AAL2`. Reflects the assurance level actually achieved, which may be higher than the level requested.',
Comment on lines +87 to +91
**Step-up authentication.** A client may require the user to have completed a second factor,
or to have authenticated recently, by supplying \`acr_values\` and/or \`max_age\`
([RFC 9470](https://datatracker.ietf.org/doc/html/rfc9470) section 5). \`acr_values=AAL2\`
requires an authenticator assurance level of 2; \`AAL2\` is the only value recognized and any
other value in the list is ignored. \`max_age\` bounds, in seconds, how old the session's most
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants