oAuth authentication

This feature allows the platform to play the OAuth2 provider or client role. OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 supersedes the work done on the original OAuth protocol created in 2006. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. This specification and its extensions are being developed within the IETF OAuth Working Group..

Protocol description

We are not going to explain in detail the OAuth2 protocol, for a quick introduction into OAuth2 please refer to this document, which is nicer to read than the full OAuth2 specification. The platform is able to play as a provider or as a client:

OAuth2 client role

The platform can relay the authentication process into an external authority (Google, LinkedIN, Twitter, etc).

OAuth2 provider role

The platform can authenticate and validate trusted applications and users (Quobis manager, Quobis collaborator, admin profiles, etc).

Protocol flow

+--------+                               +---------------+
|        |--(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 ---|               |
+--------+                               +---------------+

This figure depicts the interaction between the different roles. The process of obtaining the grant is defined in four variants:

  • authorization code

  • implicit grant

  • resource owner password credentials

  • client credentials

We do support all them four:

Authorization Code Grant

+----------+
| Resource |
|   Owner  |
|          |
+----------+
     ^
     |
    (B)
+----|-----+          Client Identifier      +---------------+
|         -+----(A)-- & Redirection URI ---->|               |
|  User-   |                                 | Authorization |
|  Agent  -+----(B)-- User authenticates --->|     Server    |
|          |                                 |               |
|         -+----(C)-- Authorization Code ---<|               |
+-|----|---+                                 +---------------+
  |    |                                         ^      v
 (A)  (C)                                        |      |
  |    |                                         |      |
  ^    v                                         |      |
+---------+                                      |      |
|         |>---(D)-- Authorization Code ---------'      |
|  Client |          & Redirection URI                  |
|         |                                             |
|         |<---(E)----- Access Token -------------------'
+---------+       (w/ Optional Refresh Token)

Implicit Grant

+----------+
| Resource |
|  Owner   |
|          |
+----------+
    ^
    |
    (B)
+----|-----+          Client Identifier     +---------------+
|         -+----(A)-- & Redirection URI --->|               |
|  User-   |                                | Authorization |
|  Agent  -|----(B)-- User authenticates -->|     Server    |
|          |                                |               |
|          |<---(C)--- Redirection URI ----<|               |
|          |          with Access Token     +---------------+
|          |            in Fragment
|          |                                +---------------+
|          |----(D)--- Redirection URI ---->|   Web-Hosted  |
|          |          without Fragment      |     Client    |
|          |                                |    Resource   |
|     (F)  |<---(E)------- Script ---------<|               |
|          |                                +---------------+
+-|--------+
  |    |
 (A)  (G) Access Token
  |    |
  ^    v
+---------+
|         |
|  Client |
|         |
+---------+

Resource Owner Password Credentials

+----------+
| Resource |
|  Owner   |
|          |
+----------+
    v
    |    Resource Owner
    (A) Password Credentials
    |
    v
+---------+                                  +---------------+
|         |>--(B)---- Resource Owner ------->|               |
|         |         Password Credentials     | Authorization |
| Client  |                                  |     Server    |
|         |<--(C)---- Access Token ---------<|               |
|         |    (w/ Optional Refresh Token)   |               |
+---------+                                  +---------------+

Client Credentials

+---------+                                  +---------------+
|         |                                  |               |
|         |>--(A)- Client Authentication --->| Authorization |
| Client  |                                  |     Server    |
|         |<--(B)---- Access Token ---------<|               |
|         |                                  |               |
+---------+                                  +---------------+

Setting a oAuth2 provider

Since the need of securing the accesses to our REST APIs, we set up an OAuth2 provider in the SippoAS to control those accesses. The goal of using OAuth2 is to provide these key features:

  • User Authentincation: authenticate the users who use the API

  • Resource profiles: restrict access to specific resources depending on user’s profile

The platform plays three roles of the OAuth2 authorization framework:

  • Resource Owner: the platform itself will grant or not access to the resources

  • Resource Server: we also are who host the resources

  • Authorization Server: the platform will also be responsible of issuing the tokens

Implementation

The platform OAuth2 provider [oauth2provider] exposes a REST API that uses PassportJS to enforce the access restrictions through a wrapper added in the [wiface] service. So the services provided are limited by a security profile. In addition, the oauth2orize library provides the framework for deploying an OAuth2 server.

The configuration of a service involves initializing it in the wac.ini file and some new sections to be added to the “servicename”.toml. As the other services, OAuth2Provider has its section in the wac.ini file:

[oauth2provider]

and his own oauth2provider.toml file describing its configuration:

[oauth2provider]
 wiface = public
 maxTokens = 0
 accessTokenExpiration = 3600
 refreshTokenExpiration = 1209600

This is the explanation for each value:

  • wiface - Default: public. The interface to add the endpoints to.

  • maxTokens - Default: 0 (unlimited). The maximum simultaneous tokens issued per user. Could be used to establish the max number of endpoints for a single user.

  • accessTokenExpiration - Default: 3600 (1h) Number of seconds an access token is valid for. An access token is needed for the client to access the service.

  • refreshTokenExpiration - Default: 1209600 (2w) Number of seconds a refresh token is valid for. A refresh token is used to obtain an access token without client credentials input.

Note

  • While in maxTokens 0 stands for unlimited, in accessTokenExpiration and refreshTokenExpiration 0 means instant expiration, which would make the service useless

  • Also make sure the selected wiface has defined a secure port. This service will refuse to work on plain HTTP.

Setting a oAuth2 client

This service provides other services the ability to register OAuth2 clients so they can make use of third party services that require the OAuth2 protocol to be used for authentication and authorization. When the OAuth2 client service starts, it first registers the callback URL (named internally redirect_URI) into the wiface given in the configuration file.

That callback will be sent to the OAuth2 provider so it knows where we are listening for their requests. In addition, the callback URL (redirect_uri) will probably need to be registered in advance into the provider (this is the case for Google, where no random redirect_uri are allowed).

Once the callback URL is set up, and the OAuth2 provider is aware of our callback URL, the service is ready to receive new client registration requests.

Token validation validateAccessToken()

Triggered by a login process, it validates an access token against the given provider service. It receives two arguments, both of them of type string:

  • The provider name to validate the access token against to.

  • The access token to validate.

The return value is of type promise which resolves with the token information or rejects with an error. The first thing done is to check for the providers name . If the provider is not configured validation is rejected, otherwise it extracts the necessary information from the provider for validation. The token is then validated against the provider and if the response succeeds and has no errors the function returns correctly and login continues.

Authorization token storage saveToken()

This method is the responsible of storing the authorized tokens and associated information into the credentials storage of the SippoAS for later usage. We keep the tokens in our database so subsequent requests to the provider’s services doesn’t need the user to authenticate each time. Only when the token expires we will show again the authentication process. When the authorization information is stored, an event is fired so the services that where waiting for the OAuth2 process can react and start using the third party services.

Configuration

The service requires two configuration steps: it needs to know the SippoAS interface it has to be attached to and the path for the providers JSON files. It is configured through the wac.ini file. A sample configuration may be:

[oauth2client]
wiface = public;  #the interface to add the endpoints to. Required.
secure = true;   #listen for secure connections at specified wiface. Defaults to false.
providers = config/oauth2/providers # path to a directory with JSON files for each available OAuth2 provider.

Obtaining an OAuth2 token

Some times, for testing, development or administration purposes, we may need to obtain an OAuth2 token from the platform (OAuth2 provider) in order to access its REST APIs. The easiest way to do so is to execute an special HTTP request as we were an authorized client asking for such a token. The following parameters are required:

  • A valid user credentials (from authdb)

  • A registered OAuth2 client

  • Any HTTP client (we’ll be using the generally available curl)

This is a one step process (given the requirements are satisfied). We have to execute this HTTP request to the POST /sapi/o/token endpoint:

1 POST http://wac:8001/sapi/o/token HTTP/1.1
2 Content-Type: application/json; charset=utf-8
3
4 {
5     "grant_type": "password",
6     "username": "our_valid_username",
7     "password": "our_valid_password"
8 }

To make it easier to read, we have used the form urlencoded format as you can see in the cURL command:

1 % curl -d "grant_type=password&username=xxxxxxx&password=xxxxxx" -X POST https://wac:8001/sapi/o/token
2 {
3     "access_token":"abf3073ab081731f542edc2c2c89d5cd92db3dd9697326b7b00b7a9",
4     "refresh_token":"6774659d347164f04f66135d3f2736fc74c75edd0c49ffe11918f21",
5     "expires_in":3599,
6     "token_type":"Bearer"
7 }

And we can see the response with the token we want.