Chapter 8: Securing Backend APIs — Bearer Tokens, Scopes, and Service-to-Service
This is Part 8 of a chapter-by-chapter walkthrough of my book OpenID: Modern Identity for Developers and Architects. In the previous chapter we built a working login. Chapter 8 turns to the harder problem most teams forget until it bites them: the APIs sitting behind that login.
8.1 — Bearer Tokens: Simplicity With Sharp Edges
An access token presented in the Authorization: Bearer <token> header is the standard way a client talks to your API. The name is the design: whoever bears the token gets access. No challenge, no proof-of-possession, no handshake. That simplicity is why bearer tokens dominate — and why DPoP and mTLS (Chapter 5) exist as upgrades when "whoever holds it" is too permissive.
Validating a bearer token isn't optional, and it isn't just "the header is present." For JWT access tokens, you verify signature, issuer, audience, expiry, and required scopes before the request gets anywhere near your business logic. For opaque tokens, you call the provider's introspection endpoint (covered below). Either way: no valid token, no request.
Authorization header, not in cookies. Mixing them up is how APIs get hit by CSRF that shouldn't have been possible. The header-vs-cookie distinction is a security feature; preserve it.8.2 — Scope Design: The Difference Between "Access" and "Least Privilege"
Scopes are the mechanism that turns "the user is authorized" into "the user is authorized for this specific operation." A token with a single broad write scope is a rubber stamp. A token with orders:read, orders:write, and profile:read expresses an actual permission model.
Chapter 8 walks through hierarchical scope naming (resource.subresource.action), where to draw the lines between scopes, and the tradeoff between granularity (safer, more complex) and simplicity (easier to reason about, leakier). The principle that matters: request the minimum scopes you need, check them at every API boundary, and version them carefully because deprecating a scope is slow work.
8.3 — Token Introspection: When Local Validation Isn't Enough
Local JWT validation is fast and scales well, but it has one flaw: a revoked JWT is still valid until it expires. For high-stakes operations — money movement, permission changes, data export — you often want the provider's current opinion, not the token's past opinion.
The Token Introspection endpoint (RFC 7662) is how you ask. Your API POSTs the token and gets back active: true/false plus the current claim set. Slower than local validation, but authoritative.
A pragmatic pattern: local JWT validation for most endpoints, introspection for sensitive ones, and a revocation list (Redis, usually) for recently-revoked tokens so you catch the in-flight compromises without an extra network hop.
8.4 — Service-to-Service: Auth Without a User
Backend APIs don't just serve end-users; they call other APIs. Those calls need identity too, and OIDC/OAuth 2.0 give you three main options:
- Client Credentials — simplest. A service has a
client_idandclient_secretand trades them for an access token. Works everywhere, gives up the least information in an audit trail. - JWT Bearer Assertions — a service signs a JWT with its private key asserting its identity, and exchanges it for an access token. No pre-shared secret; strong key-based identity.
- mTLS — transport-layer mutual authentication. Strongest, hardest to operate, best for network-zone boundaries.
Most mature systems use a mix — Client Credentials for benign internal calls, JWT assertions or mTLS for trust boundaries. The common mistake is using one mechanism everywhere and pretending that makes the system "uniform."
What Chapter 8 Sets Up
By the end of Chapter 8 you should know exactly how to validate an access token at your API edge, how to design scopes that express real permissions rather than vibes, when to reach for introspection vs. local validation, and which service-to-service mechanism fits which boundary. Everything from here on — SPAs, mobile, zero trust, FAPI — builds on a solid API-edge implementation.
Next up — Chapter 9: SPA and Mobile Patterns. We leave the server-side comfort zone and confront the hostile environments of the browser (any JavaScript can read anything JavaScript can read) and the mobile device (where your code is shipped to attackers). PKCE, BFF, native app patterns, refresh token rotation done right.
Sho Shimoda
I share and organize what I’ve learned and experienced.カテゴリー
タグ
検索ログ
Development & Technical Consulting
Working on a new product or exploring a technical idea? We help teams with system design, architecture reviews, requirements definition, proof-of-concept development, and full implementation. Whether you need a quick technical assessment or end-to-end support, feel free to reach out.
Contact Us