Implementing authentication with tokens for RESTful applications

One of the key principles of REST is that its stateless. This means that the server never keeps user state. In the context of security, this aspect has impacts when implementing security. This means that authentication hints must be sent and verified at each time.

In the following we will describe the different approaches to handle authentication for RESTful applications, the HTTP basic authentication and OAuth2. For the latter, we describe how to design the resources that manages security tokens within a RESTful application. In the past, StackMob provides a great sample of this within their plateform.

Basic authentication

HTTP provides a built-in authentication mecanism based on a username and a password. These hints are provided within the request using the header Authorization and formatted as described below:

Authorization: Base64(username:password)

Base64 simply means that the enclosed content is encoded using the base 64. We can also notice that the password can consist in a token to be more robust. We mean by token an UUID.

Following code described a sample request that uses HTTP basic authentication:

GET https://api.myapplication.com/{{entityType}}/(...)
Authorization: Basic aHR0cHdhdGNoOmY=
(...)

Restlet implements such authentication within its client support thanks to the class HttpBasicHelper. Its method formatResponse shows how to format the content of the header:

public void formatResponse(ChallengeWriter cw, ChallengeResponse challenge,
                      Request request, Series<Header> httpHeaders) {
    try {
        if (challenge == null) {
            throw new RuntimeException(
                "No challenge provided, unable to encode credentials");
        } else {
            CharArrayWriter credentials = new CharArrayWriter();
            credentials.write(challenge.getIdentifier());
            credentials.write(":");
            credentials.write(challenge.getSecret());
            cw.append(Base64.encode(credentials.toCharArray(),
                                              "ISO-8859-1", false));
        }
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(
            "Unsupported encoding, unable to encode credentials");
    } catch (IOException e) {
        throw new RuntimeException(
            "Unexpected exception, unable to encode credentials", e);
    }
}

To have a look at the complete content of the class, we can use this link.

The drawbacks of such approach are the following:

  • The secret key is always sent in the request.
  • The secret key is easily readable since the content of the header Authorization is encoded with Base64.
  • The secret token is always valid. There is no built-in support for validation and expiration.

As said in the name of the authentication, the latter is basic and should be used for simple scenarios. For more advanced and robust use cases, we should consider to use

Advanced token

The OAuth2 authentication mechanism is based on the following elements:

  • A resource to obtain temporary tokens based on the user credentials.
  • A resource to refresh temporary token validaties when they expire.
  • An internal authentication handler based on the provided tokens in the header Authorization.

Following figure describes the different elements how the flow to use them:

Lets dive now into more details about the resource that allows to obtain temporary tokens.

Getting temporary tokens

The first resource allows to obtain temporary security tokens that can be used to authenticate actual calls to RESTful applications. The following parameters are required to call the resource:

  • username: the username of the user.
  • password: the corresponding password of the user.
  • token_type: the expected token type.

The two first parameters are generally available within your account within the application you want to access.

Following code describes the content of the request to send by a REST client to obtain a temporary access token:

POST https://api.myapplication.com/user/accessToken
X-MyApplication-API-Key: myApiKey
(...)
{
  "username": "my username",
  "password": "my password",
  "token_type": "mac"
}

If the provided credentials are correct, the response will return the following hints:

  • access_token: contains the temporary access token. Its validity is determined by the field expires_in. If the
  • token_type: contains the kind of token returned. We will dive into the possible values in more details in the section below.
  • expires_in: provides the validity in seconds of the access token.
  • refresh_token: provides a token to refresh the access token if it has expired.
  • mac_key: the mac key to use to sign an authenticated request. This field is only used with token type mac and not bearer.
  • mac_algorithm: the encyption algorithm to use to sign the authenticated request. This field is only used with token type mac and not bearer.

Some additional fields specified to the remote application can be also present. They can correspond to hints about the current user that executes the request.

Here is the corresponding response for the request:

{
  "access_token": "vV6xEfVgQZv4ABJ6VZDHlQfCaqKgFZuN",
  "mac_key": "okKXxMWOEhnM78Rie02ZjWjP7eQqpp6V",
  "mac_algorithm": "hmac-sha-1",
  "token_type": "mac",
  "expires_in": 3600,
  "refresh_token": "nZSiH3L5K4febMlELguILucrWpjRud56",
  "myapplication": {
    "user": {
      "username": "my username",
      (...)
    }
  }
}

Lets focus now on the resource to refresh expired temporary tokens.

Refreshing temporaring tokens

As described in the previous section, the resource used to get temporary tokens also returns a refresh token. The latter can be used to obtain a new temporaty token when the expiration occurs. For such case, we dont have to send again the username and password. They are sent only once when calling the service described in the previous section.

The following parameters are required to call the resource:

  • refresh_token: the refresh token to use to obtain a new temporary access token when an old one expired.
  • grant_type: the grant type. In this case, the value is refresh_token.
  • token_type: the expected token type.
  • mac_algorithm: the encyption algorithm to use to sign the authenticated request. This field is only used with token type mac and not bearer.

Following code describes the content of the request to send by a REST client to obtain a new temporary access token when an old one expired:

POST https://api.myapplication.com/user/refreshToken
X-MyApplication-API-Key: myApiKey
(...)
{
  "refresh_token": "refreshToken",
  "grant_type", "refresh_token",
  "token_type": "mac",
  "mac_algorithm": "hmac-sha-1"
}

The corresponding response for the request is the same as the one for the resource that returns temporary tokens.

Supported token types

OAuth2 describes two common modes linked to the values that can be provided in the field token_type:

  • Bearer: in this case, an access token is generated and sent back to you. We can directly use it within the header Authorization. See this link for the specification.
  • Mac: in this case, an encrypted version of the access token is sent to the client side. The server side only has the knowledge of the true access token. This approach is more secure than the bearer one but more complicated to implement on the server side. See this link for the specification.

We took the sample of the OAuth2 Mac mode above. In the case of the Bearer mode, fields mac_key and mac_algorithm wont be returned in the response content when interacting the token resources. For more details, we can have a look at this link.

Now we obtained the temporary tokens, we can use them to authenticate our REST requests.

Authenticating with temporary tokens

With OAuth2, the hints to authenticate the request are provided within the header Authorization. Lets start with the approach bearer. With the latter, we can directly use the access token right after the word Bearer, as described in the following code:

GET https://api.myapplication.com/{{entityType}}/(...)
X-MyApplication-API-Key: myApiKey
Authorization: Bearer vV6xEfVgQZv4ABJ6VZDHlQfCaqKgFZuN
(...)

With the approach mac, things are a bit tricky since we need to sign the request and send the signature in addition in the header Authorization. In this case, the value of this header is structured with the following elements:

  • id: the attribute contains the access token
  • ts: the current unix timestamp
  • nonce: a random string
  • mac: the base64 encoded signature of the request

Following code describes a typically request with the approach mac:

GET https://api.myapplication.com/{{entityType}}/(...)
X-MyApplication-API-Key: myApiKey
Authorization: Mac id="vV6xEfVgQZv4ABJ6VZDHlQfCaqKgFZuN",
ts="1420462794", nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
(...)

For more details of the build of the value of this header in such case, we can have a look at the class HttpOAuthMacHelper and its method formatResponse:

See class HttpOAuthMacHelper.

public void formatResponse(ChallengeWriter cw,
                     ChallengeResponse challenge,
                     Request request, Series<Header> httpHeaders) {
    cw.append("id=\"");
    cw.append(challenge.getIdentifier());
    cw.append("\",ts=\"");
    cw.append((new Date()).getTime());
    cw.append("\",nonce=\"");
    String nonce = CryptoUtils.makeNonce(
                 String.valueOf(challenge.getSecret()));
    cw.append(nonce);
    cw.append("\",mac=\"");
    cw.append(String.valueOf(challenge.getSecret()));
    cw.append("\"");
}

To have a look at the complete content of the class, we can use this link.

This entry was posted in REST, Web API and tagged , , , , . Bookmark the permalink.

3 Responses to Implementing authentication with tokens for RESTful applications

  1. Pingback: Are there any security implications of identifiers in URL path elements? | DL-UAT

  2. Pingback: Login / authenticate with WebAPI2 | DL-UAT

  3. Pingback: Architecturing API keys and access tokens | DL-UAT

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s