Table of Contents

OAuth 2.0 Implementation for APIs

We should be able to provide a way for other applications to use our APIs by authenticating and authorizing through Oauth.

This should cover the following -

OAuth 2.0 Spec & discussion

There are 4 different types of token grant are available. We use two of them which are famous and applicable to our case.

1. Grant type - password

   +--------+                                  +---------------+
   |        |--(A)- Authorization Request ->   |  Authorization|
   |        |       (with username, password)  |   Server      |
   |        |<-(D)----- Access Token -------   |               |
   |        |                                  +---------------+
   | Client |
   |        |                                  +---------------+
   |        |--(E)----- API request ------>    |   Resource    |
   |        |           (With access token)    |    Server     |
   |        |<-(F)------ API response -------  |               |
   +--------+                                  +---------------+
   
   In our case both Resource server and Authorization server are crossbow app.

The following are the important points from our oauth implementation.

  1. The token exchange and authentication will happen over SSL so that the token security is not compromised.
  2. The access token is expired every 60 days.
  3. We do not use 'refresh_token' to regenerate access token, to keep the implementation simple. Every time a token is expired user has to enter his username and password with the client and get the access token generated.

Sample Oauth Request and Response

Request URI - https://api.crossbow.com/api/authentication/token

Parameters - client_id, client_secret, grant_type, username, password, format,

Except format all are mandatory.

The value of grant_type should be - passsword

The default value of format is xml.

Successful authentication response

1. XML -

  <oauth2-token>
  <access-token>6uJ0xn1mynyh9UZZ3gC46L8UPImLv6r9fsEWmz9T</access-token>
  <token-type>bearer</token-type>
  <expires-in>5183999</expires-in>
  </oauth2-token>

2. JSON -

{"oauth2_token":
  {"token_type":"bearer",
   "expires_in":5183999,
   "access_token":"WFfKQaElw1dvNggDK4eBuiyNbrcS2xajCDs2LI2p"
  }
}

Failed authentication Response

1. XML

<api>
  <response>
    <error>
      <description>invalid_user</description>
      <error-code>ERRR00005</error-code>
    </error>
  </response>
</api>

2. JSON

  {"api":
   "response":
     {"error":  
       {"description":"invalid_user","error_code":"ERRR00005"}
     }
  }

2. Grant type - auth_code

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
     
          In our case both Resource server and Authorization server are crossbow app.

Sample Oauth Requests and Response

STEP 1: Client app sends a request to authorize url of crossbow -

The Client application sends a request to the authorize url of crossbow.

Request URI - https://api.crossbow.com/api/authentication/oauth/authorize?response_type=code&client_id=<client_app_id>&redirect_uri=<client_app_redirect_uri>

This redirects user to a login page.

1. On successful login and authorize -

- The user will be redirected to <client_app_redirect_uri>?code=W25JoW2cktPurc7vpBaI

The client sends a request to the token url mentioned above and receives token.

The only difference is that the grant_type param value should be authorization_code when requesting for token.

2. On unsuccessful login and authorize -

The client will be redirected to <client_app_redirect_uri>?error=<error_description>

The most common error_desription will be access_denied

STEP 2: 1. Client app sends a request for access token-

The Client application sends a request to the token url of crossbow.

Request URI - https://api.crossbow.com/api/authentication/token

Parameters - client_id, client_secret, grant_type, username, password, format,

Except format all are mandatory.

The value of grant_type should be - authorization_code

The default value of format is xml.

The response for this call is same as the one we have above for password grant_type.

Implementation

Providing OAuth Service

The service provision for Oauth is developed by inspiring from the plugin - https://github.com/pelle/oauth-plugin

This gem does not cover the complete flow but it can be used base and the tweaks can be made to incorporate it with our app flow.

Prerequisites

Note -

One more alternative explored was - https://github.com/ThoughtWorksStudios/oauth2_provider

It has a cleaner design but we are not using it as it only supports version 2-09 of OAuth 2.0 spec.

Consuming OAuth service (for clients)

The Oauth plugin (https://github.com/pelle/oauth-plugin) has some code which can be tweaked to implement a client for the Oauth service.

In addition to this we can also use the following ruby based libraries to implement clients-

https://github.com/intridea/oauth2

https://github.com/aflatter/oauth2-ruby

Database Design

The following tables are needed to store the details of the clients and tokens.

Table name - client_applications

Column_name type Description
id integer primary key
name string name of the client application
key string unique client identifier
secret integer unique client secret
url string The home page url of the client app
callback_url string The default call back url to which the redirection should happen after authorizing.
support_url string The support page url of the client if any. This is optional
company_id integer foreign key for companies table
status integer used to determine if the client is active or not
action integer used to determine if the client is approved, active or rejected
activated_at date time The time when the client app is activated
created_at date_time created date
updated_at date_timeupdated date

Table name - oauth_tokens

Column_name type Description
id integer primary key
user_id inetger id of user
client_application_id id client id which is requesting the access. (Foreign key)
type string Type of the token. Useful if we maintain multiple types of tokens(Ex- OAuth 2.0, Oauth 2.1). For now, it has one value.
token string unique token for user
secret string unique secret for user
callback_url string client app's call back url for this access token
verifier string Not used for now
scope string Useful when we have different types of access privileges for tokens. Not used now.
expires_at date_time time when the token expires
created_at date_time created date
updated_at date_timeupdated date

Table name - oauth_nonces

(Note - We do not use this table at this moment as we don't refresh tokens. But this is created to maintain the code consistency.)

Column_name type Description
id integer primary key
nonce string
timestamp integer
created_at date_time created date
updated_at date_timeupdated date