This appendix brings together extended code listings that show how the book’s individual snippets fit into complete OAuth 2.0 and OpenID Connect workflows. It assembles client, authorization server, and resource server logic into end-to-end sequences, highlighting request construction, credential handling, token lifecycle management, and security checks. The examples span the authorization code grant, bearer and proof-of-possession (PoP) tokens, token introspection and revocation, dynamic client registration, and user identity handling via ID tokens and a UserInfo endpoint.
On the client side, the listings demonstrate building an authorization request with a CSRF-mitigating state value, validating the state on return, and exchanging the authorization code for an access token using form-encoded parameters and HTTP Basic client authentication. They show fetching a protected resource with a Bearer token, handling missing or invalid tokens, and performing a refresh token grant to recover from expiry while updating stored tokens and scope. They also illustrate ID token processing: parsing and verifying a JWS with the server’s key, checking issuer and audience, and enforcing issued-at and expiration times before using the claims.
On the server and resource sides, the code validates client IDs and redirect URIs at the authorization endpoint, records pending requests, and issues authorization codes upon user approval. The token endpoint authenticates the client, validates grants, issues access and refresh tokens, and stores them for later lookup. Additional endpoints implement token introspection (with protected resource authentication and rich metadata in the response), token revocation (authenticated by the client), and dynamic client registration with strict validation of metadata, grant and response types, and redirect URIs. Middleware illustrates extracting tokens from headers, body, or query and resolving them from storage, while the UserInfo endpoint returns claims according to granted scopes. A PoP example shows verifying a signed token, binding it to the HTTP method, host, and path, and tying it to an introspected access token for stronger sender-constrained protection.
FAQ
What does the client’s /authorize route do, and why is the state parameter important? (Listing 1)
The route builds an authorization request URL to the authorization server with response_type=code, client_id, redirect_uri, and a freshly generated state value, then redirects the user-agent there. The state value is used to correlate the response and protect against CSRF attacks; it must be validated on the callback.How does the callback handler validate the response and exchange the code for a token? (Listing 2)
It first checks for an error parameter, then validates that the returned state matches the one sent. It posts grant_type=authorization_code, the code, and redirect_uri to the token endpoint with client authentication (HTTP Basic) and Content-Type application/x-www-form-urlencoded. On success, it parses the JSON body and stores the access_token; otherwise it renders an error.How does the client call a protected resource with the access token, and how are failures handled? (Listing 3)
The client includes the token in the Authorization: BearerHow is access token refresh implemented on the client, and when is it triggered? (Listing 4)
On a failed resource call, if a refresh_token is available, the client sends grant_type=refresh_token with the refresh_token to the token endpoint using client authentication. If successful, it updates access_token (and refresh_token if rotated) and the scope, then retries the resource call. If refresh fails or no refresh_token exists, it shows an error.Where does the resource server accept access tokens from, and which method is preferred? (Listing 5)
It tries, in order: Authorization header with Bearer, request body field access_token, then query parameter access_token. The Authorization header is the recommended method; sending tokens in the query is discouraged due to logging and leak risks.How does the resource server validate and attach a token to the request context? (Listing 6)
After extracting the token, it looks it up in storage (nosql.where('access_token', inToken)). If found, it attaches the token record to req.access_token and calls next(); otherwise it logs that no match was found and continues. In a production system you would also check token expiry, scope, and revocation.What checks does the authorization endpoint perform before showing the approval page? (Listing 7)
It validates client_id maps to a known client and that redirect_uri exactly matches a registered value. If valid, it generates a short-lived reqid, stores the original request parameters under that key, and renders an approval page. Unknown clients or mismatched redirect URIs result in errors.How are authorization codes issued and redeemed securely? (Listings 8 and 9)
- On approval, if response_type=code, the server generates a code, stores it alongside the original request (codes[code] = { request }), and redirects back with code and state.- At the token endpoint, the client authenticates, the server verifies grant_type=authorization_code, finds the code, checks client_id matches the one that initiated the request, burns the code (delete), and issues a Bearer access token. Invalid codes or client mismatches return invalid_grant.
How are token introspection and revocation implemented, and who can call them? (Listings 11 and 12)
- Introspection: A protected resource authenticates to the AS, submits the token, and receives an active boolean plus metadata (iss, aud, sub/username, scope, client_id) if found; otherwise active=false. Only registered resources (with credentials) can introspect.- Revocation: The client authenticates to the AS and asks to revoke a token. The server removes the token for that client and returns 204 No Content. Only the client that owns the token can revoke it.
How does OpenID Connect support work here (UserInfo and ID token verification)? (Listings 14 and 15)
- UserInfo endpoint: Requires the openid scope. It returns user claims limited to the scopes granted (e.g., profile, email, address, phone).- ID token processing: The client verifies the JWT’s signature, issuer (iss), audience (aud includes the client_id), and timestamps (iat/exp). Only if all checks pass is the ID token accepted and its claims used.
OAuth 2 in Action ebook for free