2 March 2019

OAuth 2.0 Token Exchange

by mo


In this post I want to discuss the process of the OAuth 2.0 token exchange and token rotation.

OAuth 2.0 describes two different types of tokens.

  1. Access Token: used for accessing a protected resource.
  2. Refresh Token: can be exchanged for a new access token.

I think an example might be useful here. Let’s say that we are building a strength training mobile application. This application wants to access a users Moogle Fit API data and submit new data to the Moogle Fit API.

In this scenario, the mobile app wants to make API calls to the Moogle Fit API to read data for a specific user, and insert new data for a specific user.

In order for the client to make API calls to the Moogle Fit API it needs to gain access to a token that will give it access to read/create data on behalf of me (mo).

Before OAuth 2.0, one mechanism to achieve this might have been to capture my credentials directly in the mobile application and use them to make API calls to the Moogle Fit API. There are problems with this approach. Most of them rooted with the need to have access to my credentials. Read the introduction in RFC-6749 to get a better understanding of this.

OAuth 2.0 makes it possible for the mobile application to get an access_token that represents a user (mo) without needing direct access to the users credentials. The user (mo) also has the benefit of deciding what parts (scopes) of the resource server API that the user wants to give the client access to.

  • Client: mobile application
  • Resource Server: Moogle Fit API
  • Authorization Server: Moogle OAuth server
  • Resource Owner: mo

Refresh Token Usage

    +--------+                                           +---------------+
    |        |--(A)------- Authorization Grant --------->|               |
    |        |                                           |               |
    |        |<-(B)----------- Access Token -------------|               |
    |        |               & Refresh Token             |               |
    |        |                                           |               |
    |        |                            +----------+   |               |
    |        |--(C)---- Access Token ---->|          |   |               |
    |        |                            |          |   |               |
    |        |<-(D)- Protected Resource --| Resource |   | Authorization |
    | Client |                            |  Server  |   |     Server    |
    |        |--(E)---- Access Token ---->|          |   |               |
    |        |                            |          |   |               |
    |        |<-(F)- Invalid Token Error -|          |   |               |
    |        |                            +----------+   |               |
    |        |                                           |               |
    |        |--(G)----------- Refresh Token ----------->|               |
    |        |                                           |               |
    |        |<-(H)----------- Access Token -------------|               |
    +--------+           & Optional Refresh Token        +---------------+

Access Token

The purpose of the access token is to allow clients to access a protected resource scoped to the privileges defined by the token.

The access_token represents a subject (mo), and audience (mobile application) an issuer (OAuth authorization server) and an expiration.

To simplify this example I am going to skip the initial exchange of a grant for a token. There are several different types of grant types that can be used by a client to get an access token.

Once a client gets an access_token it can now make API calls to the resource server (Moogle Fit API). The resource server can check the claims associated with the token to see if the token is authorized to access the protected resource.

Refresh Token

An access_token can expire. When an access_token expires a client can exchange a refresh_token to gain a new access_token and refresh_token.

The purpose of the refresh_token is to allow a client to get a new access_token and refresh_token pair. Once a refresh_token is used it cannot be re-used.

Examples

Let’s define some API endpoints in the fictitious example.

Authorization Server

Refresh Token Grant: This endpoint is used by a client to exchange a refresh_token for a new access_token and refresh_token.

Request:

POST /token HTTP/1.1
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

Response:

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

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
}

Resource Server (Moogle Fit API)

GET /api/body_weight/: returns the resource owners body weight over time.

Request:

GET /api/body_weight/
Authorization: Bearer access_token
Accept: application/json
Content-Type: application/json

Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "body_weight": "200", "unit": "lbs", "created_at": "2015-01-01T00:00:00+00:00" },
  { "body_weight": "210", "unit": "lbs", "created_at": "2016-01-01T00:00:00+00:00" },
]

Conclusion

An access_token decouples a resource owners credentials from the authorization that it is delegating to a client to access protected resources from a resource server. A refresh_token can be used by a client to gain a new access_token and refresh_token.

The exchange process can be triggered when an access_token expires or is revoked.

security