OAuth 2.0
OAuth 2.0
Section titled “OAuth 2.0”Standards
Section titled “Standards”- RFC 6749 – OAuth 2.0 Authorization Framework
- RFC 7636 – Proof Key for Code Exchange (PKCE)
- RFC 8628 – Device Authorization Grant
- RFC 7662 – Token Introspection
- RFC 7009 – Token Revocation
- RFC 7523 §2.2 – JWT Profile for OAuth 2.0 Client Authentication
- RFC 7517 – JSON Web Key Sets
- RFC 8414 – Authorization Server Metadata
- RFC 9449 – OAuth 2.0 Demonstrating Proof of Possession (DPoP), opt-in
- RFC 9700 – OAuth 2.0 Security Best Current Practice
Available Flows
Section titled “Available Flows”| Flow ID | Name | Description |
|---|---|---|
authorization_code |
Authorization Code | Standard redirect-based authorization |
authorization_code_pkce |
Authorization Code + PKCE | Authorization code with code verifier/challenge |
client_credentials |
Client Credentials | Machine-to-machine issuance with independent selectors for client_secret_basic or private_key_jwt authentication and Bearer or DPoP access-token protection |
refresh_token |
Refresh Token | Token renewal without re-authorization |
implicit |
Implicit Grant (Legacy) | RFC 6749 §4.2: access token in the redirect fragment, no refresh token. RFC 9700 §2.1.2 says clients SHOULD NOT use it |
device_code |
Device Authorization | RFC 8628 grant for TVs, CLIs, and other input-constrained devices; person authorizes on a second device |
token_introspection |
Token Introspection | Validate and inspect active tokens (RFC 7662) |
token_revocation |
Token Revocation | Invalidate tokens (RFC 7009) |
The implicit grant is implemented for the public public-app client so the fragment response can be compared with authorization code + PKCE. RFC 9700 §2.1.2: “Clients SHOULD NOT use the implicit grant.” The authorization server returns access_token and token_type in the redirect fragment and does not issue a refresh token. Confidential clients receive unauthorized_client. grant_type=implicit is not accepted at the token endpoint.
Resource Owner Password Credentials (grant_type=password) is not implemented. RFC 9700 §2.4: “The resource owner password credentials grant MUST NOT be used.” Use authorization code + PKCE instead.
Demo Scenarios
Section titled “Demo Scenarios”- Authorization Code Flow Demo – Complete redirect flow with consent
- PKCE Flow Demo – PKCE challenge/verifier exchange
- Client Credentials Demo – Independently select shared-secret or browser-held
private_key_jwtauthentication and Bearer or DPoP token protection - Token Refresh Demo – Refresh grant with token rotation
- Implicit Grant Demo – Public client receives an access token in the redirect fragment; no refresh token
- Device Authorization Demo – Device displays a user_code; Looking Glass opens the Protocol Showcase sign-in window at
/oauth2/device
Endpoints
Section titled “Endpoints”| Path | Methods | Purpose |
|---|---|---|
/oauth2/authorize |
GET, POST | Authorization endpoint (response_type=code or token) |
/oauth2/device/authorize |
POST | RFC 8628 device authorization endpoint |
/oauth2/device |
GET, POST | RFC 8628 verification URI (user enters user_code) |
/oauth2/token |
POST | Token endpoint |
/oauth2/introspect |
POST | Token introspection |
/oauth2/revoke |
POST | Token revocation |
/oauth2/demo/users |
GET | List demo users |
/oauth2/demo/clients |
GET | List demo clients |
/oauth2/demo/caep/revoke-subject |
POST | Demo CAEP subject revocation (SSF receiver; not RFC 7009) |
/.well-known/oauth-authorization-server/oauth2 |
GET | RFC 8414 authorization server metadata |
/oauth2/demo/clients/machine-client-pkjwt/jwks |
POST | Register the demo client’s public JWKS |
private_key_jwt client authentication
Section titled “private_key_jwt client authentication”The Client Credentials Looking Glass flow can authenticate with a signed JWT instead of a shared client secret. Select private_key_jwt in the flow configuration, run the flow, then choose client assertion in the token inspector to inspect the real JWT sent to the token endpoint. Open the Client Credentials flow.
The browser generates an RS256 key with WebCrypto. Its private CryptoKey is
non-extractable and never leaves the client; only the public JWK is registered
with the demo authorization server. The start-demo response returns a 256-bit
owner capability; full session access, WebSocket streaming, and public-key
registration require it. Registration is active-session-only and atomically
one-shot. It creates the real session-isolated client_id (there is no seeded
private_key_jwt client), expires that registration after 10 minutes, and
returns the authorization server’s exact token endpoint. Split deployments
therefore use the same aud value the server validates, and concurrent
demonstrations cannot replace each other’s keys. The server also supports
registered ES256 (P-256) and EdDSA (Ed25519) client keys.
ProtocolSoup applies this deterministic RFC 7523 profile:
client_idis required in the request body and must exactly equal bothissandsub.audmust contain the exact configured token endpoint URL. A trailing slash changes the value and fails validation.iat,exp, andjtiare required; optionalnbfis enforced. RFC 7519 fractional NumericDate values retain nanosecond precision. The assertion lifetime is at most 300 seconds, with 60 seconds of clock-skew tolerance.jtiis single-use through the complete acceptance window, including the 60-second expiration-skew allowance. Development and tests use an in-memory reservation store. Demo and production deployments require shared Redis and perform one atomicSET NXreservation keyed by a hash of(client_id, jti); production Redis connections must userediss://. Replay-store failures fail closed withserver_error; assertion validation failures continue to use genericinvalid_clientresponses.- Allowed algorithms are RS256, ES256, and EdDSA. The registered key type must
be RSA, EC P-256, or Ed25519 respectively. If
key_opsis present it must permitverify, and the client registration must selectprivate_key_jwt. RSA moduli must be odd and at least 2048 bits; exponents must be odd, at least 3, and safely representable by the verifier. - Static JWKS keys are checked before an optional HTTPS
jwks_uri. Remote retrieval bypasses environment proxies, rejects IANA special-use IPv4 and IPv6 addresses during both DNS validation and dialing, applies one 3-second deadline to DNS, connection, TLS, and response reading, rejects redirects, caps responses at 64KB, caches for 10 minutes, coalesces concurrent initial and forced fetches, and rate-limits refreshes caused by unknownkidvalues. Unsupported or malformed unrelated remote keys are ignored when at least one usable verification key remains. - Static, remote, and demo JWKS registrations reject every private JWK member:
d,p,q,dp,dq,qi,oth, andk. Rejected registration captures redact those values before Looking Glass persistence. - Assertion validation failures return the same
invalid_clientdescription. Specific reasons appear only in owner-visible Looking Glass history.
This method is intentionally scoped to client_credentials. JWT Bearer
authorization grants (RFC 7523 §2.1), client_secret_jwt, mTLS, and
certificate-in-header key delivery are separate mechanisms and are not enabled
by this flow.
Sender-constrained tokens (RFC 9449 DPoP)
Section titled “Sender-constrained tokens (RFC 9449 DPoP)”The token endpoint accepts an optional DPoP proof header
(htm=POST, htu the exact /oauth2/token URL). When present and valid,
the issued access token is bound to the proof’s key: it carries a cnf.jkt
claim (the RFC 7638 thumbprint of the proof’s public key) and the response’s
token_type is DPoP instead of Bearer. Absent that header, every existing
Bearer flow is unchanged – DPoP is opt-in, never mandatory, on this endpoint.
- For the
authorization_codegrant, a DPoP-bound access token issued to a public client also binds the issued refresh token to the same key (RFC 9449 Section 5). A subsequentrefresh_tokenrequest from that client must re-present a matching proof; a mismatched or missing proof is rejected withinvalid_grant. A refresh token issued without DPoP does not gain binding on refresh even if a proof is later presented. A confidential client’s refresh token is never bound this way, even when the token request that issued it carried a valid proof: it is already sender-constrained by its client authentication credentials, per the spec’s own carve-out – only its access token getscnf.jkt. - The
DPoPheader field itself must not repeat: a request carrying more than one is rejected outright rather than silently using the first one and ignoring the rest. - Proof validation rejects
alg: none, symmetric algorithms, ajwkheader carrying private key material, anhtu/htmmismatch, a stale or futureiat(60-second window), and a replayedjti– replay-store outages fail the request closed withserver_error, never open. - A server-provided nonce challenge (
DPoP-Nonceresponse header,use_dpop_nonceerror) is available but off by default, enabled viaSHOWCASE_DPOP_NONCE_REQUIRED. See Environment Variables. - Only JWT access tokens can be bound. Opaque/reference access token binding is a separate mechanism this platform does not implement.
- The RFC 8414 metadata endpoint lists the accepted DPoP proof algorithms
under
dpop_signing_alg_values_supported(RFC 9449 Section 5.1).
Run the Client Credentials flow in Looking Glass and select DPoP under
Access-token protection to see a real browser-generated ES256 key produce a
proof. The resulting bound token is rendered distinctly (amber, lock icon) from
a plain Bearer token in the token inspector. Client authentication is a separate
selector, so all four real combinations of client_secret_basic or
private_key_jwt with Bearer or DPoP can be inspected without switching flows.
RFC 8414 requires an HTTPS issuer. Because protocol routes are mounted at the
origin root, SHOWCASE_BASE_URL must be a pathless HTTPS origin in production
(for example https://as.example, not https://as.example/base or a trailing
slash). The metadata endpoint returns 503 when it cannot derive that issuer.
Loopback HTTP remains available for the executable local demo, but it is not
published as RFC 8414 metadata.
What To Validate
Section titled “What To Validate”- PKCE code_challenge and code_verifier alignment
- Token claims:
iss,sub,aud,exp,iat,scope - Introspection response:
active,token_type,scope. Resource servers may authenticate by presenting the same access token asAuthorization: Bearer(RFC 7662 §2.1). - Revocation: subsequent introspection returns
active: false - Device code: polling interval,
authorization_pendingvsslow_down - private_key_jwt: assertion claims, signature algorithm/key binding, and the replay-protection event
- DPoP: proof claims (
htm,htu,iat,jti), bound token’scnf.jkt,token_type: DPoP, and refresh-token binding surviving rotation