OAuth 2.0 & OpenID Connect (Part 3) - Client Credentials Flow

OAuth 2.0 & OpenID Connect (Part 3) - Client Credentials Flow

Introduction

This is the third post in a series where I write about OAuth 2.0 & OpenID Connect. In this article we are going to have a look at the client credentials flow.

Part 0 - Terminology
Part 1 - An Introduction
Part 2 - Authorization Code Flow + PKCE
Part 3 - Client Credentials Flow
Part 4 - Device Authorization Flow
Part 5 - OpenID Connect Flow

This type of flow was introduced with RFC 6749 and is sometimes referred to as two-legged OAuth flow.

It is commonly used for server-to-server interactions that must run in the background, without immediate interaction of a user, where the client is typically a daemon service or a website. It's a much simpler flow then the others we have encountered so far.

The client credentials flow permits a confidential client to use its own credentials, instead of impersonating a user, to authenticate when calling another web service.

As an example think of a website (client) that likes to enrich it's content with a weather forecast provided by a protected weather service API (resource server). There is no human involved, when the website pulls that data.

Let's have a look at the sequence diagram.

Sequence Diagram

This is what the flow looks like. It's pretty basic compared to the authorization code flow, isn't it? 😎

OAuth 2.0 - Client Credentials Flow

Step 1 - Authentication

The client initiates the flow by authenticating with the authorization servers token endpoint.

It does so by sending a POST request of which the body is protected with TLS in transit. The client_id and client_secret attributes are getting send in the header as a base64 encoded string (HTTP Basic Authentication, RFC 2617).

Authorization Servers like Microsofts Identity Platform can also accept certificates instead of a shared secret.

This is what an authentication request would look like:

POST /oauth2/token HTTP/1.1
Host: www.auth-server.com
Accept: application/json
Cache-Control: no-cache
Authorization: Basic eW91clfaWQ6eW91cl9jbGllbnRfc2VjcmV09jbGllbnR
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
scope=https://graph.microsoft.com/.default

It further passes two parameters along with it, which are grant_type and scope where the latter is optional.

Parameter Description
grant_type Must be set to client_credentials to indicate the grant type
scope The level of access to get an access token for

Step 2 - Credential Validation

The authorization server validates the client_id and the client_secret, which implies that the client needs to be registered with the authorization server beforehand.

Step 3 - Access Token Response

If the credentials are valid the authorization server immediatly returns an access token. Please note that the access token response does not include a refresh_token.

As an example this is what an access token response could look like.

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

 {
   "access_token":"eyJraWQiOiJ[...]",
   "token_type":"Bearer",
   "expires_in":3600,
 }

Step 4 - Requesting Data

The client requests the protected resource by presenting the access token in the authorization header.

GET /weatherforecast
Host: api.weather-service.com

Authorization: Bearer eyJraWQiOiJ[...]

Step 5 - Validating & Response

After the resource server successfully validated the access token via the authorization servers introspection endpoint (or a cached public key) it will reply with the requested data.

Key take-aways

  • The client credentials flow is used for server-to-server interaction
  • The flow doesn't involve any user interaction (besides the one-time registration process done by an admin).
  • Since client authentication is used as the authorization grant, no additional authorization request is needed.
  • The authorization server will immediately return an access token upon successful authentication.