RFC compliance matrix
Every standard the library cites in its code, mapped to the package that implements it and the option or feature that gates it. Read the status column first (see the legend below), then the parenthesis: it names what is and is not covered.
Status legend
full implements the OP-facing surface the library claims for that spec end-to-end.
partial implements the parts the OP needs; some optional sections are out of scope by design.
planned in the spec list, not landed yet.
out out-of-scope; structurally not the library's concern.
refused deliberately rejected (e.g. alg=none).
These labels describe implementation coverage, not OpenID Foundation certification. A full label does not override requirements outside this library's stated scope; the exceptions in each row still apply.
OIDC core / discovery
| Standard | Status | Where |
|---|---|---|
| OpenID Connect Core 1.0 | partial (response_type=code only) | op/, internal/authorize, internal/tokenendpoint, internal/userinfo, internal/sector |
| OpenID Connect Discovery 1.0 | partial (metadata endpoint is implemented) | internal/discovery |
| OpenID Connect Dynamic Client Registration 1.0 | partial (core flow and registration-metadata checks are enforced) | internal/registrationendpoint |
| OpenID Connect RP-Initiated Logout 1.0 | full | internal/endsession |
| OpenID Connect Back-Channel Logout 1.0 | full | internal/backchannel |
| OpenID Connect Prompt Create 1.0 | full (prompt=create is accepted when LoginFlow.Registration is configured and advertised in prompt_values_supported) | internal/authorize, internal/authn, internal/discovery |
| OpenID Connect Front-Channel Logout 1.0 | out (iframe / third-party-cookie signalling is intentionally not shipped; use Back-Channel Logout) | — |
| OpenID Connect Session Management 1.0 | out (third-party-cookie-dependent; back-channel preferred) | — |
| OpenID Connect CIBA Core 1.0 | partial (poll delivery only; ping / push deferred to v2+) | internal/ciba, internal/cibaendpoint, op.WithCIBAGrant |
- OpenID Connect Core 1.0: Aggregated and Distributed claim types §5.6.2 are not emitted; pairwise sub §8.1 is supported through
op.WithPairwiseSubject. See "Out of scope by design" below. - OpenID Connect Discovery 1.0: With the default ES256,
id_token_signing_alg_values_supportedomitsRS256, which Discovery requires; an OP built withop.WithSigningAlgorithm(op.AlgRS256)advertisesRS256 - OpenID Connect Dynamic Client Registration 1.0: Enforced:
sector_identifier_urifetch,application_type=web/=nativeredirect rules, JWKs / pairwise / response-type cross-checks, PUT reserved-field rejection,post_logout_redirect_urisround-trip, and the five JWE alg/enc encrypted-response families.client_secretis intentionally omitted fromGET /register/{id}responses,software_statementis not accepted
OAuth 2.0 core RFCs
| RFC | Status | Where / option |
|---|---|---|
| RFC 6749 OAuth 2.0 Framework | partial (authorization-code, refresh-token, and client-credentials surfaces; implicit and password grants are intentionally not implemented) | op/, internal/authorize, internal/tokenendpoint |
| RFC 6750 Bearer Token Usage | partial (OP-issued bearer tokens and OP-hosted resource endpoints such as UserInfo / introspection) | internal/tokens, internal/userinfo, internal/introspectendpoint |
| RFC 6819 Threat Model & Security Considerations | partial (security guidance applied across the OP; not a standalone protocol surface) | whole codebase |
| RFC 7009 Token Revocation | full (gated by feature.Revoke) | internal/revokeendpoint |
| RFC 7521 Assertion Framework | partial (private_key_jwt client authentication and the JWT bearer authorization grant) | internal/clientauth, internal/assertiongrant |
| RFC 7523 JWT Bearer Assertions for Client Auth and Authorization Grants | partial (private_key_jwt) | internal/clientauth, internal/assertiongrant, internal/tokenendpoint |
| RFC 7591 Dynamic Client Registration | partial (enabled by op.WithDynamicRegistration; software_statement is rejected with invalid_software_statement) | internal/registrationendpoint |
| RFC 7592 DCR Management | partial (read / update / delete) | internal/registrationendpoint |
| RFC 7636 PKCE | full (only S256; plain refused) | internal/pkce |
| RFC 7662 Token Introspection | full (gated by feature.Introspect; an active refresh token reports no token_type, so a resource server cannot mistake it for an access token) | internal/introspectendpoint |
RFC 7800 Confirmation Methods (cnf) | full | internal/dpop, internal/mtls, internal/tokens |
| RFC 8252 OAuth 2.0 for Native Apps | partial (OP-side native redirect / loopback hardening; client-app behaviour is out of scope) | internal/registrationendpoint, internal/authorize |
| RFC 8414 Authorization Server Metadata | full | internal/discovery |
| RFC 8485 Vectors of Trust | partial (consumed via ACR/AAL mapping) | op/aal.go, op/acr.go |
| RFC 8628 Device Authorization Grant | full (gated by op.WithDeviceCodeGrant) | internal/devicecode, internal/devicecodeendpoint, op/devicecodekit |
| RFC 8693 OAuth 2.0 Token Exchange | full (gated by op.WithTokenExchangeGrant) | internal/customgrant/tokenexchange |
| RFC 8705 OAuth 2.0 mTLS Client Auth & Cert-Bound Tokens | full (feature.MTLS wires certificate-bound access tokens, mtls_endpoint_aliases, and tls_client_auth / self_signed_tls_client_auth client authentication at every client-authenticating endpoint) | internal/mtls |
| RFC 8707 Resource Indicators | partial (canonicalisation and client allow-list enforcement across authorize / token / device / CIBA) | internal/resourceindicator, internal/authorize, internal/tokenendpoint, internal/devicecodeendpoint, internal/cibaendpoint |
| RFC 8725 JWT Best Current Practices | full (alg allow-list, type checks) | internal/jose |
| RFC 9068 JWT Profile for Access Tokens | partial (JWT issuance uses the OP's single algorithm, ES256 by default) | internal/tokens |
| RFC 9101 JAR (JWT-Secured Authorization Request) | full (gated by feature.JAR) | internal/jar |
| RFC 9126 PAR (Pushed Authorization Requests) | full (gated by feature.PAR) | internal/parendpoint |
| RFC 9207 OAuth 2.0 Authorization Server Issuer Identifier | full | internal/authorize (iss parameter on the response) |
RFC 9396 Rich Authorization Requests (authorization_details) | full (gated by op.WithAuthorizationDetailTypes) | internal/authorizationdetails, op/authorization_details.go |
| RFC 9449 DPoP | full incl. §8 nonce flow (gated by feature.DPoP) | internal/dpop, op.WithDPoPNonceSource |
| RFC 9470 OAuth 2.0 Step Up Authentication Challenge | full (OP honours acr_values / max_age reauthentication via ACR rules) | op/rule.go (RuleACR), op/stepup.go |
| RFC 9700 OAuth 2.0 Security Best Current Practice | partial (OP-side BCP posture, including refresh-token rotation with replay cascade per §2.2.2) | whole codebase |
| RFC 9701 JWT Response for OAuth 2.0 Token Introspection | full (signed JWT default; JWE-wrapped per client introspection_encrypted_response_alg / _enc metadata) | internal/introspectendpoint, internal/jose |
| RFC 9728 OAuth 2.0 Protected Resource Metadata | full (gated by op.WithProtectedResources; served at /.well-known/oauth-protected-resource with the issuer stamped into authorization_servers) | internal/protectedresource, op/protected_resource.go |
- RFC 6750 Bearer Token Usage: General RS challenge behaviour belongs to resource servers
- RFC 7009 Token Revocation: Revoking a refresh token revokes its whole rotation chain however long it has grown, plus the grant's access tokens; the user's other refresh chains on the same client stay usable
- RFC 7521 Assertion Framework: The SAML bearer grant and
client_secret_jwtare intentionally not implemented - RFC 7523 JWT Bearer Assertions for Client Auth and Authorization Grants: An assertion with an empty or over-long
jtiis rejected, and a client JWKS fetch fault answers 503 instead ofinvalid_client. Theurn:ietf:params:oauth:grant-type:jwt-bearergrant is implemented for assertions from explicitly trusted issuers, and every assertion is single-use byjti.client_secret_jwtis not implemented and is rejected at registration withinvalid_client_metadata - RFC 7591 Dynamic Client Registration: A client record carrying both
jwksandjwks_uriis refused on every surface, as §2 forbids the pair - RFC 7592 DCR Management: PUT omission resets to server defaults rather than deleting fields, and the response only re-emits
client_secreton anone→ confidential auth-method upgrade or an explicit rotation request - RFC 8628 Device Authorization Grant:
slow_downladder persisted atomically withLastPolledAt; redemption records astore.Grant, so revocation and pairwise/userinforeach the tokens;op/devicecodekitships the brute-force gate and aRevokehelper that cascades under the grant and, givenDeps.Grants, deletes the grant record - RFC 8693 OAuth 2.0 Token Exchange:
actchain mandatory whenever actor differs from subject, nesting the subject_token's own chain up to five levels; issued tokens sit under the subject_token's grant, so revoking it revokes them; cnf rebinding to the request's verified DPoP / mTLS; a requestedscopeoutside the client's registered scopes is refused withinvalid_scope - RFC 8707 Resource Indicators: Built-in grants currently narrow most issuance paths to a single resource value
- RFC 9068 JWT Profile for Access Tokens: §2.1 requires RS256 support, which an OP built with
op.WithSigningAlgorithm(op.AlgRS256)meets; the verifier requiresjtionly when the revocation strategy keys on it, so with strategyNoneit accepts tokens without the §2.2 required claim - RFC 9396 Rich Authorization Requests (
authorization_details): Validated at/auth,/par,/token, persisted with each authorization code, refresh chain and access token so a later authorization cannot change them, echoed on JWT access tokens and introspection, advertised in discovery - RFC 9470 OAuth 2.0 Step Up Authentication Challenge:
op.StepUpChallengebuilds the resource-serverWWW-Authenticatechallenge the embedder's RS returns - RFC 9700 OAuth 2.0 Security Best Current Practice: Resource-server and client-side requirements remain with embedders
IETF drafts
| Draft | Status | Where |
|---|---|---|
OAuth 2.0 Grant Management (draft-ietf-oauth-grant-management) | partial (gated by op.WithGrantManagement) | internal/grantmgmtendpoint, op/grant_management.go |
Identity Assertion JWT Authorization Grant (ID-JAG) (draft-ietf-oauth-identity-assertion-authz-grant, draft-06) | partial (resource authorization server role: redeeming an ID-JAG through the jwt-bearer grant is supported) | internal/assertiongrant, internal/customgrant/tokenexchange |
OAuth Client ID Metadata Document (draft-ietf-oauth-client-id-metadata-document, draft-02) | partial (gated by op.WithClientIDMetadataDocuments) | internal/cimd, op/cimd.go |
- OAuth 2.0 Grant Management (
draft-ietf-oauth-grant-management):grant_management_action/grant_idhonoured, query / revoke endpoint mounted,grant_idon the token response, discovery advertisement. Tracks an IETF draft — surface may change on a draft update - Identity Assertion JWT Authorization Grant (ID-JAG) (
draft-ietf-oauth-identity-assertion-authz-grant, draft-06): Identity provider role: issuing an ID-JAG through token exchange is supported. An ID-JAG is signed with the OP's issuing algorithm. With the default ES256 the draft's mandatory-to-implement RS256 is not met and a resource AS that implements only RS256 rejects it; an OP built withop.WithSigningAlgorithm(op.AlgRS256)signs ID-JAGs with RS256. Experimental; tracks an IETF draft, so the surface may change on a draft update - OAuth Client ID Metadata Document (
draft-ietf-oauth-client-id-metadata-document, draft-02): An HTTPS URLclient_idis resolved to a fetched metadata document, fornoneandprivate_key_jwtclients usingauthorization_codeandrefresh_token. Confidential shared-secret and mTLS clients are not supported, and a changed document does not revoke existing grants. Experimental, opt-in; tracks an IETF draft, so the surface may change on a draft update. The MCP authorization specification cites draft-00
Shared Signals (transmitter)
All rows describe the transmitter side only; the OP does not receive events from other transmitters. Enable it with op.WithSharedSignals; see Shared Signals.
| Specification | Status | Where / option |
|---|---|---|
| OpenID Shared Signals Framework 1.0 | partial (transmitter metadata, stream create / read / update / replace / delete, stream status, verification, push and poll delivery) | internal/ssf, op.WithSharedSignals |
| OpenID CAEP 1.0 | partial (session-revoked and credential-change only) | internal/ssf, op.SessionRevoked, op.CredentialChange |
| OpenID RISC 1.0 | partial (account-disabled, account-enabled, account-purged and credential-compromise) | internal/ssf, op.AccountDisabled, op.AccountEnabled, op.AccountPurged, op.CredentialCompromise |
| RFC 8417 Security Event Token | full (issuing side: typ: secevent+jwt, one event per token, no sub and no exp) | internal/ssf |
| RFC 8935 Push-Based SET Delivery | full (transmitter side, with retry and SSRF-guarded delivery) | internal/ssf |
| RFC 8936 Poll-Based SET Delivery | full (transmitter side, including long polling) | internal/ssf |
| CAEP Interoperability Profile 1.0 | partial (the transmitter requirements are met except §2.6, which asks for RS256 signing) | internal/ssf |
- OpenID Shared Signals Framework 1.0:
add_subject/remove_subject,inactivity_timeoutandmin_verification_intervalare not implemented; the metadata advertisesdefault_subjects: "ALL", meaning every subject that holds a grant for the receiver's client - OpenID RISC 1.0: Experimental: the published RISC text is still a draft, so this surface may change in a minor release
- CAEP Interoperability Profile 1.0: SETs are signed with the OP's single issuing algorithm: ES256 by default, which does not meet §2.6, and RS256 when
op.WithSigningAlgorithm(op.AlgRS256)is set
JOSE family
| RFC | Status | Where |
|---|---|---|
| RFC 7515 JWS | partial (compact JWS surfaces used by JWT / JAR / JARM / DPoP / client assertions; general JSON serialization is not exposed) | internal/jose |
| RFC 7516 JWE | partial — closed allow-list (RSA-OAEP-256 / ECDH-ES{,+A128KW,+A256KW} × A{128,256}GCM) | internal/jose, op.WithEncryptionKeyset |
| RFC 7517 JWK | partial (JWK Set publication and client JWKS consumption for supported asymmetric key types; symmetric oct keys are not accepted for signing) | internal/jwks |
| RFC 7518 JWA | partial — issuance uses one algorithm per OP, ES256 by default or RS256 through op.WithSigningAlgorithm | internal/jose |
| RFC 7519 JWT | partial (signed / encrypted JWT surfaces used by OIDC and OAuth extensions; unsecured JWTs are refused) | internal/jose |
| RFC 7638 JWK Thumbprint | full (used by DPoP cnf.jkt) | internal/dpop |
RFC 8037 Edwards-curve DSA / EdDSA | partial (Ed25519; Ed448 not enabled) | internal/jose |
- RFC 7516 JWE: Inbound JWE request_object (JAR / PAR §6.1), outbound JWE id_token, JWT-shape userinfo, JARM authorization response, and RFC 9701 introspection response wired.
RSA1_5refused (CVE-2017-11424 padding oracle);RSA-OAEP-384/512,dir, symmetric-onlyA*KWdeferred to v2+ - RFC 7518 JWA: Verification accepts
RS256,PS256,ES256,EdDSA. HS* andnonerefused
FAPI family
The FAPI2Baseline Go identifier retains the former Baseline name. The final specification is FAPI 2.0 Security Profile. The OFCS results cited here come from the suite's FAPI 2.0 Final test plans (and the FAPI-CIBA ID1 plan); they are a regression run, not a certification, and do not establish conformity with every requirement of the final specifications. Under FAPI2Baseline and FAPI2MessageSigning the library accepts only the issuer identifier as a string in the private_key_jwt aud (§5.3.2.1(8)) and does not rotate refresh tokens (§5.3.2.1(9)); other profiles keep the wider aud set and rotate.
| Profile | Status | Switch |
|---|---|---|
| FAPI 2.0 Security Profile | partial (PAR, PKCE and sender-constrained tokens are implemented; this switch also requires JAR as a library choice) | op.WithProfile(profile.FAPI2Baseline) |
| FAPI 2.0 Message Signing | partial (JAR and JARM are implemented; the final specification permits separate signing profiles and inherits the Security Profile requirements) | op.WithProfile(profile.FAPI2MessageSigning) |
| FAPI 1.0 Advanced | out | — (use FAPI 2.0) |
| FAPI-CIBA | partial (library preset: poll mode, JAR, DPoP or mTLS, a 10-minute access-token TTL ceiling, requested_expiry ≤ 600 s, and an access-token revocation path) | op.WithProfile(profile.FAPICIBA) |
| OpenID iGov High | out | — |
- FAPI 2.0 Security Profile: See the note above and OFCS.
- FAPI-CIBA: The historical ID1 plan uses mTLS; the demo selects it explicitly. The 60-minute request-object age limit is a library constraint; see OFCS.
The profile enumeration also carries two profiles that are not FAPI profiles. profile.OAuth21, the default when no profile is declared, is the OAuth 2.1 / RFC 9700 posture and adds PKCE on every authorization-code request, including confidential clients. profile.OIDCCore declares the OpenID Connect Core 1.0 shape, PKCE optional for confidential clients, for legacy relying parties; it cannot be combined with another profile. See Declaring a security profile.
Other RFCs the library cites
| RFC | Use |
|---|---|
| RFC 1918 | Private-network deny-list for back-channel logout SSRF defense |
| RFC 2045 | Case-insensitive media-type comparison for request-object typ |
| RFC 2606 | Reserved example domains in tests / examples |
| RFC 3986 | URI parsing |
| RFC 4122 | UUIDv4 generation |
| RFC 4226 | HOTP building block used by the TOTP authenticator |
| RFC 4514 | DN handling for mTLS subject DN |
| RFC 4647 | Language-tag lookup when selecting a locale bundle |
| RFC 4648 | Base64url encoding |
| RFC 5280 | X.509 cert validation |
| RFC 5321 | SMTP address length bounds for email OTP inputs |
| RFC 6238 | TOTP authenticator |
| RFC 6265 | Cookie syntax |
| RFC 6711 | Authentication Context Class Reference values registry |
| RFC 6761 | Special-use domain names: the development issuer hosts WithAllowInsecureOutboundForDev accepts |
| RFC 6838 | Media-type suffix matching (+json) for fetched documents |
| RFC 7230 / 7231 / 7232 / 7235 | HTTP/1.1 (now superseded by RFC 9110) |
| RFC 7239 | Forwarded header parsing for trusted-proxy handling |
| RFC 7807 | application/problem+json (selected error paths) |
| RFC 8017 | RSA-PSS / RSA-OAEP algorithm references through JOSE |
| RFC 8141 | URN handling for PAR request_uri values |
| RFC 8176 | AMR values registry |
| RFC 8259 | JSON |
| RFC 9110 | HTTP semantics |
| RFC 9111 | HTTP caching: freshness lifetime of a fetched Client ID Metadata Document |
| RFC 9325 | TLS recommendations; op.FAPITLSConfig keeps TLS 1.3 enabled alongside the FAPI TLS 1.2 cipher list |
| RFC 9493 | iss_sub subject identifiers in Shared Signals events |
Out of scope by design
A handful of OIDC Core / OAuth surfaces are intentionally not implemented. The library tracks each one as a row with status: out-of-scope in the scenario catalog (test/scenarios/catalog/<feature>.yaml) so the policy is auditable alongside the tests that pin everything else.
response_typeiscodeonly. Implicit (id_token,id_token token), hybrid (code id_token, ...), andresponse_type=noneare not issued. RFC 9700 §2.1.2 deprecates the implicit grant; FAPI 2.0 mandates code. Discovery advertisesresponse_types_supported: ["code"].fragmentresponse mode is not wired. Withcode-only issuance there is nothing to put in the URL fragment.queryandform_postare both implemented (the latter renders an auto-submitting HTML form per OIDC Core Form Post Response Mode 1.0); whenfeature.JARMis on, the four*.jwtvariants are also wired. Discovery advertisesresponse_modes_supported: ["query", "form_post"]by default and appends*.jwtmodes when JARM is enabled.- Aggregated and Distributed claim types (OIDC Core §5.6.2) are not emitted. Only Normal claims are produced; the
_claim_names/_claim_sourceskeys never appear in tokens or UserInfo responses. client_secret_jwtis refused at registration. Useprivate_key_jwtinstead. The HMAC-shared-secret JWT profile is rejected withinvalid_client_metadata: token_endpoint_auth_method client_secret_jwt is not supported.- JWE alg / enc allow-list is closed. The default set is
RSA-OAEP-256+ECDH-ES{,+A128KW,+A256KW}for key-wrap andA{128,256}GCMfor content.WithSupportedEncryptionAlgscan narrow but not extend.RSA1_5is permanently rejected (CVE-2017-11424);RSA-OAEP-384/RSA-OAEP-512,dir, and symmetric-onlyA*KWare deferred to v2+. - CIBA push and ping delivery modes are not implemented. Discovery advertises
backchannel_token_delivery_modes_supported: ["poll"]exclusively so a client cannot negotiate them. - Custom-grant handlers cannot supply refresh-token values. A handler that wants refresh issuance sets
CustomGrantResponse.IssueRefreshToken; the OP mints and persists the credential through its ownRefreshTokenStore, preserving lineage, rotation, replay cascade, and DPoP / mTLS binding. If the client is not registered forrefresh_token, the access-token response still succeeds andcustom_grant.refresh_droppedrecords the omission.
Out of scope (intentional)
Not every RFC in the OAuth / OIDC sphere is the OP's responsibility. The library deliberately doesn't ship support for the following — they belong to the resource server, the client SDK, or other layers.
| RFC / Spec | Status | Notes |
|---|---|---|
| RFC 9421 — HTTP Message Signatures | out | Resource-server (API protection) concern, not OP. |
- RFC 9421 — HTTP Message Signatures: The OP-side equivalents are JAR (RFC 9101) for signed authorization requests, JARM for signed authorization responses, and DPoP (RFC 9449) for proof-of-possession on
/tokenand/userinfo. RS-side HTTP signing is the embedder's responsibility.
Verification
The list is grepped from the live source under op/ and internal/. You can audit it yourself:
git clone https://github.com/libraz/go-oidc-provider.git
cd go-oidc-provider
grep -rhoE 'RFC [0-9]+' op/ internal/ | sort -uThe tables above follow the output of that command: standards the library implements get their own rows, and incidental references are collected under "Other RFCs the library cites".