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.

pattern_client_credentials.png

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.

pattern_client_credentials_states.png

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_provider logs in with the service's database account and renews the token at the refresh threshold.
  • ores::nats::service::nats_client wraps 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

12. Sources

13. See also

Emacs 29.3 (Org mode 9.6.15)