Service-to-service (Client Credentials + Introspection)¶
This cookbook demonstrates a common machine-to-machine pattern:
- Service A (client) obtains an access token using the Client Credentials grant.
- Service B (resource server) validates incoming requests by calling RFC
7662 token introspection (
POST /oauth/introspect). - Service B enforces a required scope (e.g.
read).
In this repository, Service B is a tiny example app located at
examples/resource-server-node/ and is deployed in KIND via
k8s/components/resource-server/.
Architecture¶
flowchart LR
A[Service A\n(client)] -->|POST /oauth/token\nclient_credentials| AS[OAuth2 Server]
A -->|GET /protected\nAuthorization: Bearer ...| B[Service B\n(resource server)]
B -->|POST /oauth/introspect| AS
Why introspection?
- It’s straightforward to implement.
- It works even when the access token is opaque (or when you want revocation to take effect immediately).
- It centralizes validation rules in the authorization server.
Run it on KIND (automated)¶
The extended KIND E2E script provisions:
- Postgres + migrations
oauth2-serverresource-server(example)
It then:
- registers a test OAuth2 client
- mints an access token (
grant_type=client_credentials) - verifies that
resource-server: - returns 401 without a token
- returns 200 with a valid token
- returns 401 again after revocation
Run:
bash scripts/e2e_kind_extended.sh
If you want to keep the cluster around for debugging:
bash scripts/e2e_kind_extended.sh --keep-cluster --keep-namespace
How the resource server validates tokens¶
At a high level, Service B does:
- Parse the
Authorization: Bearer <token>header - Call:
POST /oauth/introspect
Content-Type: application/x-www-form-urlencoded
token=<token>&client_id=<id>&client_secret=<secret>
- Require
active=true - Require a scope (defaults to
read)
See examples/resource-server-node/server.js for the full implementation.
Notes and production guidance¶
- Cache introspection responses for a short TTL to reduce load on the auth server (but consider revocation requirements).
- Use sensible timeouts and retries when calling
/oauth/introspect. - If you need maximum performance, consider local JWT validation (but ensure your key distribution / rotation story is solid).