Skip to main content

Client Credentials Flow

The OAuth2 client credentials grant is for server-to-server access with no interactive user. A client authenticates at the token endpoint with a signed JWT client assertion and receives an access token directly. There is no client_secret.

All requests go to the authorization server's token endpoint (https://auth.jlr-vcdp.com/realms/public/protocol/openid-connect/token), not the API gateway.

What the resulting token can access is fixed by how the client was configured when its credentials were created (vehicles and categories for owners, registered vehicles for fleets) - you do not request scopes here.

It is used in two situations on this platform:

  • MQTT streaming - every persona. Connecting to the real-time stream always uses a client-credentials token, supplied as the MQTT connection password. Streaming does not use DPoP.
  • REST API - fleet operators. B2B fleet operators access their own registered vehicles' data via the REST API using a client-credentials token (with a DPoP proof on each request, like all REST calls).

Request a token​

First build a client assertion JWT. Then call the token endpoint. The only difference between a token for REST and a token for streaming is whether you include a DPoP proof.

For the REST API (DPoP-bound)​

Include a DPoP proof so the token is bound to your key pair:

curl -X POST https://auth.jlr-vcdp.com/realms/public/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "DPoP: YOUR_DPOP_PROOF_JWT" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=YOUR_SIGNED_ASSERTION_JWT"

For MQTT streaming (no DPoP)​

No DPoP proof is needed because the stream does not use DPoP:

curl -X POST https://auth.jlr-vcdp.com/realms/public/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=YOUR_SIGNED_ASSERTION_JWT"

Response​

{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "DPoP",
"expires_in": 3600
}

Client-credentials tokens typically have no refresh token - when the token expires, request a new one with a freshly signed assertion. See Tokens & Refresh.

Using the token​

  • REST API: send Authorization: DPoP <access_token> plus a fresh DPoP proof on each request. See REST API.
  • MQTT streaming: supply the token as the password when connecting your MQTT client. See Streaming.

Keep your private key safe​

The security of this flow rests on your private key - the one whose public certificate you uploaded during credential creation. Store it in a secret manager or HSM, never commit it to source control, and never ship it in a browser or mobile client. The client credentials grant is for trusted backends only.

Next steps​