User Authentication
Accessing Platform 6 products as a user requires an access token granted using OAuth 2.0. This guide explains in detail how user authentication works in P6.
Overview¶
One of the main goals of OAuth is allowing a client application (a client in OAuth2 terms) to authenticate a user to REST API providers (the resource providers) without having to capture the user’s credentials.
The client should never store the credentials of the user, only the access token and the refresh token - if available - delivered following the OAuth dance.
The access token has a short time to live (in minutes), and the refresh token can be used by the client to get a new access token delivered for the user. The refresh token has a much longer time to live (in days). If it also expires, the whole dance should be restarted from the start.
In summary, the dance is as follows:
Initial authorization grant:
- The client calls the authorize endpoint on the login server using its credentials (
client_id
,client_secret
andredirect_uri
). - The login server replies with a
302
redirecting to a login page. - The client displays the login page to the user.
- The user enters their credentials (username and password) on the login page and submits them to the login server.
- The login server replies with an authorization code, and the login form redirects to the client
redirect_uri
, passing the authorization code as a parameter. - The client calls the login server’s token endpoint using the authorization code to retrieve the user access token and refresh token (if any).
Refresh token grant:
- The client calls the token endpoint on the login server passing the refresh token and
grant_type
ofrefresh_token
as parameters. - The login server replies with a new access token.
OAuth2 stakeholders¶
Login server¶
The login server is the only server delivering access and refresh tokens.
The server is found at login.amalto.io
. The IP address may change, but the server name is fixed.
The login server listens to HTTP requests on its 443
port only.
Client¶
A client consumes services provided by resource providers on behalf of the user.
A client is identified to the login server by a triplet:
- client ID (
client_id
) - secret (
client_secret
) - redirect URI (
redirect_uri
)
The redirect URI is part of the authentication and is validated by the login server.
It is also the URI redirected to by the login page with the authorization code passed as a query parameter called code
.
User¶
The user is the final consumer of the services.
A user authorizes a client to consume services on resource providers (e.g. to call their REST APIs) on its behalf. The access token holds this authorization; the refresh token provides the possibility to the client to get a new access token without having the user re-enter her/his credentials.
A user is identified to the login server by a username and a password.
Resource provider¶
A resource provider (basically a P6 instance) exposes its services for the client’s consumption.
Resource providers expose a REST API.
When a client issues a REST call to a resource provider, it is expected to provide an HTTP Authorization
header,
starting with the word Bearer
, followed by a space and followed by an access token:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiAiaHR0cDovL2FtYWx0by5jb20iLCA...
The access token will be validated by the resource provider.
If it is absent or invalid, the resource provider will return a 401
.
Authorization is associated to the access token in the form of scopes.
When the client calls a service on the resource provider, the latter verifies that the user identified by the access
token has the appropriate scopes to authorize the request to complete.
When that is not the case, the resource provider will reply with a 403
.
Resource providers support CORS
and can answer Cross-Origin
requests.
Initial authorization grant in detail¶
1 - Authorize endpoint call¶
The client calls the authorize endpoint on the login server using its credentials (client_id
, client_secret
and redirect_uri
).
This is an HTTP GET
call to https://login.amalto.io/oauth2/authorize
passing client credentials as query parameters
in addition to a query parameter called response_type
with the value set to code
.
Example using curl
curl -v "https://login.amalto.io/oauth2/authorize?client_id=myClientId&client_secret=myClientSecret&redirect_uri=http://localhost:8080/receiveAuthCode&response_type=code"
The login server will reply with a 302
and the location header will contain the URL of the login page.
< HTTP/1.1 302 Found
< Date: Tue, 23 Jun 2015 08:51:10 GMT
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Headers: origin, authorization, content-type, accept
< Location: https://login.amalto.io/p6auth?code=3c870b0b43ce6675077d39cd24fdaad3&realm=b2&cctx=%2F
< Content-Length: 0
In case of an error, the location will be that of the redirect URI augmented with two query parameters:
error
: which provides an error codeerror_description
: a human-readable description of the error
< HTTP/1.1 302 Found
< Date: Wed, 24 Jun 2015 13:19:15 GMT
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Headers: origin, authorization, content-type, accept
< Location: http://localhost:8080/receiveAuthCode?error_description=Client+authentication+failed+%28e.g.+unknown+client%2C+no+client+authentication+included%2C+or+unsupported+response+type%29.&realm=b2&error=unauthorized_client
< Content-Length: 0
2 - User login¶
The client should display the page indicated in the location header above by calling the full URL including the query parameters.
The user should then enter its credentials (username and password) and hit the submit button.
When doing so, the login page will issue a POST
to the login server.
Using curl the POST
would be something like:
curl -d "uname=myusername&pw=mypassword&code=3c870b0b43ce6675077d39cd24fdaad3&realm=b2" https://login.amalto.io/oauth2/authorize-cont
The login server will reply with a 200
and will pass a JSON containing the authorization code and optionally, the redirect_uri
:
{
"code": "aze4a57edf5h",
"redirect_uri": "http://localhost:8080/receiveAuthCode"
}
The login page will then call the client redirect URI, passing the code
as a query parameter; using curl:
curl "http://localhost:8080/receiveAuthCode?code=aze4a57edf5h"
3 - Retrieving the access token and refresh token¶
Once the client is called on its redirect URI, it should recover the authorization code passed as the code
query parameter and issue a call to the login server to get access to the tokens.
The call is FORM POST
call to the token endpoint where the client passes:
- its 3 credentials,
- the authorization code in the
code
parameter, - a
grant_type
parameter with value fixed toauthorization_code
Using curl:
curl -d "client_id=myClientId&client_secret=myClientSecret&redirect_uri=http://localhost:8080/receiveAuthCode&code=aze4a57edf5h&grant_type=authorization_code" https://login.amalto.io/oauth2/token
The server will respond with a 200
and a JSON:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiAiaHR0cDovL2FtYWx0by5jb20iLCAic3ViIjogInByb3h5dGVzdHMiLCAiYXVkIjogWyJw...",
"refresh_token": "iOiAiaHR0cDovL2FtYWx0by5jb20iLCAic3ViIjogI",
"scope": "demo:counters:summary p6auth:user:write",
"expires_in": 600
}
The only mandatory field is access_token
. Other fields may not be provided by the login server.
scope
is a space-separated list of the authorizations granted to this access token.
expires_in
is the time to live in seconds of the access token. After that period, the refresh_token
should be used to recover a new access token.
From now on, on all calls to the resource providers REST API, the client should insert an Authorization
header of typeBearer
in its HTTP requests, i.e.
GET https://proxy.amalto.com/apis/v2/counters/summary?baseUrl=https://demo.platform6.com/p6
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiAiaHR0cDovL2FtYWx0by5jb20iLCAic3ViIjogInByb3h5dGVzdHMiLCAiYXVkIjogWyJw...
Host: proxy.amalto.com
Refresh token grant¶
When the access token expires, a new request to a resource provider will return a 401
.
When a refresh token is available, the client should use the refresh token to get a new access token then replay the original request to the resource provider using the new access token.
The client should keep this process transparent to the user.
To refresh a token, the client issues a FORM POST
request to the login server token endpoint passing:
- its 3 credentials,
- the refresh token in the
refresh_token
parameter, - a
grant_type
parameter with value fixed torefresh_token
A curl request would look like:
curl -d "client_id=myClientId&client_secret=myClientSecret&redirect_uri=http://localhost:8080/receiveAuthCode&refresh_token=iOiAiaHR0cDovL2FtYWx0by5jb20iLCAic3ViIjogI&grant_type=refresh_token" https://login.amalto.io/oauth2/token
Note
Although the redirect_uri
is never called, it is considered an authentication parameter and must be valid.
The server will respond with a 200
and a JSON:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpPU0UifQ.eyJpc3MiOiAiaHR0cDovL2FtYWx0by5jb20iLCAic3ViIjogInByb3h5dGVzdHMiLCAiYXVkIjogWyJw...",
"expires_in": 600
}
The only mandatory field is access_token
. Other fields may not be provided by the login server.
expires_in
is the time to live in seconds of the access token.
After that period, the refresh_token
should be used once again to recover a new access token.