Table of Contents

Client credentials

A service calls an API as itself, with no user involved. It authenticates to the token endpoint with its own credentials and gets an access token whose subject is the client. The client is the demo host's machine, authenticating with HTTP Basic (client_secret_basic): the header is machine:secret, Base64-encoded.

Follows: RFC 6749 ยง4.4, RFC 9068 (JWT access tokens).

Recorded from the demo host (src/Fdyay.IdentityServer.Host) by the ClientCredentialsFlow test on every CI run. A value in braces, such as {access_token_1}, is one that differs on every run; the same placeholder is the same value wherever it appears. See how these pages are made.

sequenceDiagram
    participant Client
    participant AuthorizationServer as Authorization Server
    Client->>AuthorizationServer: POST /connect/token
    AuthorizationServer-->>Client: 200 OK

1. The client asks for a token

For the api scope, which belongs to the api-resource API, so that is the token's audience.

Client โ†’ Authorization Server

POST /connect/token HTTP/1.1
Authorization: Basic bWFjaGluZTpzZWNyZXQ=
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&scope=api

Authorization Server โ†’ Client

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Cache-Control: no-store, no-cache, max-age=0
Pragma: no-cache

{
  "access_token": "{access_token_1}",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "api"
}

{access_token_1} decoded โ€” the header, then the payload; the signature is not shown:

{
  "alg": "RS256",
  "kid": "{key_id_1}",
  "typ": "at+jwt"
}
{
  "aud": [
    "api-resource"
  ],
  "iss": "http://localhost",
  "iat": {iat},
  "nbf": {iat},
  "exp": {iat + 3600},
  "jti": "{jti_1}",
  "client_id": "machine",
  "scope": "api"
}