Intermediate

Protecting an API as a resource server

Accept bearer and DPoP tokens, validate them, return standard errors, request step-up authentication, and publish metadata.

The resource server is the API that receives access tokens. It is where OAuth turns into actual access decisions, and where many integration mistakes happen.

Receiving the token

RFC 6750 defines how a bearer token is presented:

MethodExampleGuidance
Authorization headerAuthorization: Bearer mF_9.B5f-4.1JqMUse this.
Form bodyaccess_token=… in a POST bodyOnly in limited cases.
Query parameter?access_token=…Avoid: leaks through logs, history, and referrers.

DPoP-bound tokens use Authorization: DPoP <token> plus a DPoP proof header. A resource server that supports both must not accept a DPoP-bound token presented as a plain bearer token.

Validation steps

  1. Extract the token from the expected scheme.
  2. Validate it: locally as a JWT (signature, iss, aud, exp, typ) or through introspection. See JWT and token validation and self-contained and opaque tokens.
  3. Check sender constraint if present (cnf matches the DPoP key or client certificate).
  4. Check scopes or authorization_details for the operation.
  5. Apply business authorization on the specific object. See authorization in APIs.

Audience is essential. Accept only tokens whose aud identifies this API. Clients can request audience-restricted tokens with the resource parameter defined in RFC 8707.

Standard error responses

SituationHTTP statusWWW-Authenticate
No token401Bearer realm="api" (no error code)
Malformed request400Bearer error="invalid_request"
Invalid, expired, or revoked token401Bearer error="invalid_token"
Token lacks the required scope403Bearer error="insufficient_scope", scope="orders.write"
Authentication too weak or too old401Bearer error="insufficient_user_authentication", acr_values="…" (RFC 9470)

Standard errors let generic client libraries react correctly: refresh the token, ask for more scope, or trigger step-up.

Step-up authentication (RFC 9470)

Some operations need stronger or more recent authentication than the current token reflects. The resource server responds:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_user_authentication",
  error_description="A phishing-resistant authentication is required",
  acr_values="phr", max_age="300"

The client starts a new authorization request with those acr_values and max_age, obtains a new token whose acr and auth_time satisfy the requirement, and retries. The API decides what is sufficient; the authorization server performs the authentication.

Advertising requirements

Publish Protected Resource Metadata (RFC 9728) and reference it with the resource_metadata parameter in WWW-Authenticate. Clients can then discover the trusted authorization servers, supported scopes, and whether DPoP is required.

Operational practices

  • Cache JWKS and introspection results appropriately; never cache a positive introspection beyond the token’s exp.
  • Do not log tokens; log jti, client_id, and sub instead.
  • Apply rate limits per client and per subject.
  • Strip any identity headers from incoming requests at the edge, so only verified data reaches services.
  • Fail closed when keys or the introspection endpoint are unavailable.

References

Knowledge is better when it is shared.Improve this page

Type to search the entire handbook.