Client Credentials
Table of Contents
This page defines the service architecture pattern Client Credentials in the pattern language. A service authenticates with its own credentials and receives a token for itself, for work that belongs to the service and to no caller. In ORE Studio every service logs in to IAM with its database account at startup and renews the token before it expires.
1. Also known as
- Client credentials grant, in RFC 6749, section 4.4.
- Service identity, service token, and
svc_nats, the names ORE Studio uses.
2. Context
A service does work that no person asked for: it loads its caches at startup, runs a feed, answers a timer, or calls another service for data that is global or that the service owns. No caller token exists for this work.
3. Problem
How does a service authenticate when it acts on its own behalf, with no caller?
4. Forces
- The service needs a token every other service accepts.
- The identity must be the service's, so its permissions are the service's and an audit row names the service.
- The service has no tenant and no party, so it must not be used to read data that row-level security scopes by them.
- A token that expires during the service's life must be renewed without a person.
5. Solution
Each service has an account in IAM. At startup, after it has subscribed its own
subjects, it logs in with that account and receives a token. A token provider
in the service caches the token and renews it before it expires. Every call the
service makes as itself carries that token in the Authorization header.
Figure 1: Client Credentials: the service logs in as itself after startup, and its token provider renews the token before it expires.
Source: [[./pattern_client_credentials.puml][pattern_client_credentials.puml]]. Regenerate with
plantuml -tpng doc/knowledge/service_architecture_patterns/pattern_client_credentials.puml.
The provider is a small state machine. It logs in only after the service's own subjects exist, renews before the token expires, and backs off while IAM is unreachable. A refused login is final: it means the account or the password is wrong.
Figure 2: Client Credentials: the token provider waits for the service's subscriptions, logs in, renews at 80% of the lifetime or on token_expired, and backs off while IAM is unreachable.
Source: [[./pattern_client_credentials_states.puml][pattern_client_credentials_states.puml]]. Regenerate with
plantuml -tpng doc/knowledge/service_architecture_patterns/pattern_client_credentials_states.puml.
6. Failure handling
| Concern | What the pattern does |
|---|---|
| Errors | A login refused by IAM is a configuration error: the account or its password is wrong. The service logs it and does not start the work that needs the token. |
| Timeouts | The login is a request with a timeout. A service that cannot reach IAM at startup retries with back-off. |
| Retries | The provider renews at 80% of the lifetime. A call answered token_expired forces a renewal and is retried once. |
| Idempotency | A login is safe to repeat; each one returns a new token. |
| Observability | Each renewal is logged with the new expiry. A refused login is an error with the account name. |
7. Pitfalls
- Tenant data read with the service's identity. The service has no party, so row-level security returns no rows and no error. The result looks like "no data". The FX quote check met this, as Detect and correct reversed FX spot quotes records. Use Token Relay for a caller's data.
- A login before the service's subjects exist. A service that mints a token against its own subjects before it subscribes them waits for a reply nobody sends. See Service Bootstrap Phases.
- Wide service permissions. A service account that holds every permission turns a compromised service into a compromised platform. Give each account only what its own work needs.
8. Security
The service's password is a long-lived secret, held in its configuration. Its token acts for the system tenant, so its permissions must be narrow. A leaked token is bounded by its lifetime. A leaked password is not bounded, and rotating it is the remedy.
9. Resulting context
- Benefits
- Background work and startup work authenticate like any caller. The audit trail names the service.
- Liabilities
- The identity has no tenant and no party. Work that must act in a tenant needs another pattern.
10. In ORE Studio
ores::iam::client::make_service_token_providerlogs in with the service's database account and renews the token at the refresh threshold.ores::nats::service::nats_clientwraps it, and the service keeps one instance,svc_nats, for its own calls.- A step service proves itself to the run token exchange with this identity, as Run grants and run tokens states.
- The scheduler's trigger of a report uses this identity, as Scheduling and workflows states.
- Anatomy of a Service shows the idiom, and JWT Token Refresh is the plan that introduced the renewal.
11. Related patterns
- Access Token — the token this pattern obtains.
- Token Relay — the alternative when the data belongs to a caller.
- Token Exchange — uses this token as the actor's proof.
12. Sources
- RFC 6749, OAuth 2.0, section 4.4, Client Credentials Grant.
- Sam Newman, Building Microservices, second edition, O'Reilly, 2021, chapter 11, "Security" — service-to-service authentication.
13. See also
- Service architecture patterns — the structure note that orders this pattern language, and where to read this page in it.