rustauth-oauth-provider 0.3.0

OAuth 2.1 and OpenID Connect provider support for RustAuth.
Documentation
# OAuth Provider Upstream Test Mapping

> Parity notes: [`crates/rustauth-oauth-provider/UPSTREAM.md`](../UPSTREAM.md) — server closeout June 2026.

Reference: `reference/upstream-src/1.6.9/repository/packages/oauth-provider`.

| Upstream area | Rust coverage | Notes |
| --- | --- | --- |
| Options/config defaults | `oauth_provider_uses_upstream_default_scopes_grants_and_expirations` | Covers default scopes, claims, expirations, grants, and storage mode. |
| Config validation | `oauth_provider_rejects_client_registration_scopes_not_in_server_scopes`, `oauth_provider_rejects_refresh_token_without_authorization_code_grant`, `oauth_provider_rejects_short_pairwise_secret`, `oauth_provider_rejects_hashed_client_secrets_without_jwt_plugin` | Rust errors are typed config errors instead of TS runtime exceptions. |
| Schema | `oauth_provider_contributes_plural_snake_case_schema` | Physical DB names intentionally use plural snake_case tables and snake_case fields. |
| Metadata | `metadata_endpoint_returns_oidc_server_metadata`, `metadata_endpoint_advertises_custom_claims_supported`, `oauth_authorization_server_returns_oidc_metadata_when_openid_enabled`, `apply_jwt_metadata_defaults_fills_advertised_fields` | OIDC discovery, oauth-auth-server ≡ openid-config when `openid`, JWKS/alg from separate `jwt` plugin, cache-control. |
| Dynamic Client Registration | `dynamic_registration_creates_confidential_client_and_hashes_secret`, `dynamic_registration_cannot_enable_rp_initiated_logout`, `dynamic_registration_uses_default_scopes_and_configured_secret_expiration`, `dynamic_registration_confidential_client_secret_does_not_expire_by_default`, `dynamic_registration_rejects_invalid_client_metadata` | DCR public JSON names stay OAuth-compatible. Stored secret is hashed/encrypted, not returned from DB. Default scopes, secret expiration, auth method/grant/response validation, `skip_consent` rejection, and post-logout redirect validation follow upstream oauth-provider behavior. |
| Client credentials grant | `client_credentials_token_returns_bearer_token_and_persists_opaque_token`, `client_credentials_uses_default_scopes_when_client_has_no_scopes`, `token_endpoint_rejects_expired_client_secret` | Covers opaque access token persistence, upstream `clientCredentialGrantDefaultScopes` fallback for DB clients with no stored scopes, and expired confidential client secret rejection. |
| Authorization code grant | `authorization_code_flow_issues_access_and_refresh_tokens` | Covers authorize redirect, code exchange, access token, refresh token. |
| PKCE | `authorization_code_flow_enforces_pkce_s256_for_public_clients`, `authorization_code_flow_enforces_upstream_pkce_policy_for_confidential_clients` | Public clients require S256 PKCE. Confidential clients require PKCE by default, may opt out with `require_pkce=false`, and must still use PKCE for `offline_access`. Plain PKCE and partial PKCE parameters are rejected. |
| Refresh rotation | `refresh_token_grant_rotates_and_revokes_previous_refresh_token` | Covers refresh token rotation and revoked timestamp. |
| JWT/JWKS id_token | `openid_authorization_code_issues_signed_id_token_and_jwks` | Uses `rustauth-plugins::jwt` when enabled. |
| JWT access token resource audience | `resource_parameter_issues_jwt_access_token_with_oauth_claims`, `resource_array_issues_jwt_access_token_with_multiple_audiences`, `resource_form_repeated_issues_multi_audience_and_invalid_json_resource_is_rejected`, `resource_parameter_rejects_unconfigured_audience` | Covers single, JSON array, and repeated form `resource`, `aud`, `azp`, `scope`, invalid JSON resource shape, and invalid audience rejection. |
| Pairwise subjects | `pairwise_subject_is_stable_by_sector_and_used_for_userinfo_and_introspection`, `pairwise_registration_requires_single_redirect_sector` | Covers stable per-sector subject, different subjects across sectors, and same-sector DCR validation including port. |
| Prompt handling | `authorize_prompt_none_*`, `authorize_prompt_none_returns_account_selection_required_when_needed`, `authorize_prompt_none_returns_interaction_required_for_post_login`, `authorize_json_accept_returns_redirect_payload_instead_of_302`, `authorize_success_redirect_includes_iss_parameter`, … | `prompt=none`, `shouldRedirect` errors, SPA JSON redirect, RFC 9207 `iss`, continue flow. |
| Request URI / PAR resolver | `authorize_resolves_request_uri_parameters`, `authorize_rejects_unallowed_scope_and_request_uri_client_mismatch` | Supports upstream-style `request_uri` resolution before authorize validation, rejects client mismatch, and validates authorize scopes. No pushed authorization endpoint is added. |
| Consent persistence | `consent_helpers_persist_update_delete_and_match_scopes`, `consent_endpoint_accepts_rejects_and_continue_without_flag_is_rejected`, `consent_endpoint_accepts_subset_and_rejects_unrequested_scope`, `consent_management_endpoints_enforce_owner_session`, `update_consent_rejects_scopes_not_allowed_for_client`, `update_consent_without_scopes_preserves_existing_scopes` | Covers grant scope matching, reference-aware upsert/delete, accept, reject, narrowed accepted scopes, unrequested consent scope rejection without consuming the pending request, continue-without-flag rejection, ownership, allowed scope validation, and partial update preservation. |
| Introspection | `introspect_and_revoke_require_valid_client_authentication`, `introspect_and_revoke_respect_token_type_hint`, `pairwise_subject_is_stable_by_sector_and_used_for_userinfo_and_introspection` | Requires valid client auth, respects `token_type_hint`, and returns pairwise `sub` for opaque tokens. |
| Revocation | `introspect_and_revoke_*`, `revoke_endpoint_returns_empty_body_on_success` | Client auth, token_type_hint, empty body on success. |
| Token HTTP | `token_endpoint_sets_no_store_cache_headers`, `refresh_token_grant_rejects_scope_not_in_original_grant` | `no-store` / `no-cache`; refresh scope narrowing. |
| Userinfo | `userinfo_returns_claims_by_explicit_openid_profile_and_email_scopes`, `pairwise_subject_is_stable_by_sector_and_used_for_userinfo_and_introspection` | `given_name`/`family_name` with `profile`; pairwise `sub`. |
| RP-initiated logout | `rp_initiated_logout_rejects_invalid_id_token_hint`, `rp_initiated_logout_deletes_session_and_redirects_to_registered_uri` | Covers `id_token_hint`, session deletion, registered logout redirect, and state. |
| Client ownership/admin guardrails | `client_management_endpoints_reject_cross_user_ownership`, `client_reference_owns_clients_and_flows_into_tokens`, `client_privileges_can_deny_client_crud_actions`, `cached_trusted_clients_reject_manual_update_delete_and_rotate`, `cached_trusted_clients_reuse_cached_db_client_on_later_reads`, `rotate_secret_rejects_public_clients`, `update_client_preserves_omitted_fields`, `update_client_rejects_invalid_scope`, `update_client_rejects_token_auth_method_changes` | User-facing client management endpoints reject cross-user access, support reference-owned clients, enforce `client_privileges`, reject manual mutation of `cached_trusted_clients`, cache trusted DB clients in-memory for later reads, preserve partial updates, validate merged metadata, keep auth method immutable, and prevent rotating secrets for public clients. |
| Public prelogin | `public_client_prelogin_requires_allow_flag_and_signed_oauth_query` | Requires `allow_public_client_prelogin` and validates upstream-style signed `oauth_query` before exposing public client metadata. |
| Custom token hooks | `custom_id_token_claims_and_token_response_fields_are_added`, `custom_access_and_userinfo_claims_are_added` | Covers custom ID token, JWT/opaque access token introspection, userinfo claims, and custom token response fields while preventing standard token response field overrides. |
| Scope/token customization | `scope_expirations_use_shortest_matching_scope`, `prefixes_and_custom_generators_are_applied_without_storing_prefixes`, `format_refresh_token_wraps_returned_token_and_decodes_refresh_grant`, `custom_store_hash_callbacks_are_used_for_client_secrets_and_tokens` | Covers scope-specific access token lifetime, generated client IDs/secrets/access/refresh tokens, public prefixes, custom refresh-token formatting/decoding, and custom hash callbacks for client secrets and token storage. |
| MCP server-side helpers | `mcp_helpers_return_metadata_challenge_and_validate_bearer_tokens` | Covers metadata, challenge header value, active bearer validation, and inactive invalid tokens. |
| Query serialization | `authorize_prompt_none_returns_login_required_without_session`, `authorize_prompt_none_returns_consent_required_without_grant`, `consent_endpoint_accepts_rejects_and_continue_without_flag_is_rejected`, `continue_requires_matching_prompt_flag_and_rechecks_consent` | Rust tests assert state preservation through redirects and stored verification state rather than porting TS `URLSearchParams` helper directly. |
| Timestamps | `authorization_code_flow_issues_access_and_refresh_tokens`, `refresh_token_grant_rotates_and_revokes_previous_refresh_token`, `consent_helpers_persist_update_delete_and_match_scopes` | Covers expiry/revocation/update timestamps through observable DB records. |
| Runtime URL and verification validation | `dynamic_registration_rejects_unsafe_redirect_urls`, `dynamic_registration_allows_https_loopback_and_custom_scheme_redirects`, `authorization_code_flow_requires_active_session_and_user_before_tokens` | Covers server-side URL safety and stored authorization-code verification behavior through endpoint contracts. |