Two way OTP authentication¶
This section covers the API for the Two way OTP authentication module.
Introduction¶
The two way OTP authentication module is an integration module with the portal which acts as an Identity Provider (IdP). The concept used for this authentication module is to have two simple one time passwords (OTP) of 6 digits. There is two way communication involved which makes the two combined codes a strong authentication method. The two way OTP authentication module should be configured as a custom IdP in the Onegini Token Server admin console.
Authentication flow¶
The basic flow contains three steps. The first step is triggered by the end-user (on their mobile device). This end-user wants to enroll their mobile device (login to the mobile application). In the first step the user is given a code (client code), which must be entered in a web-based portal for end-users. Normally the user would use a laptop to browse to the web-based portal or use their mobile device browser to browse to the portal.
In the second step the user needs to fill in the client code (that was generated in the first step). They need to enter it on a specific page on the web-based portal. An API call will be made from the portal to the Token Server in order to transfer the client code to the Token Server. This API call must contain the client code and the user id of the user that is logged in into the portal. The result of this API call is a code (the response token). The portal needs to present this code to the end-user.
The last step is that the end-user must enter this response token in the web page served by the Token Server authentication module. When the user has done so the mobile device and user can be linked together by the Token Server. This concludes the two way OTP authentication module.
Generation of the client code¶
The client code is used to correlate a user action on the enrollment module with the API call made by the portal. The client code is a six digit unique string. A web page (provided by the Token Server) displays this code to the end-user, see the templates section. As the Token Server has no session management a cookie is set in the users' browser to link it to the enrollment transaction. The transaction has a default timeout of five minute. The cookie (and transaction timeout) settings can be set by the Token Server (cookie) properties.
Create Response Token¶
An API is provided so that the portal can request a response token when the user entered their client code in the portal. The network infrastructure should be set up in such a way that the API can only be reached by the portal which is located in the internal network. Basic authentication is used to provide a basic level of security on the API.
Request token (client code) endpoint: POST /oauth/api/v1/two-way-otp/request-token
Parameter | Description |
---|---|
user_id | Identifier of the user |
client_code | The code that was shown to the user by the enrollment module |
Example request
POST /oauth/api/v1/two-way-otp/request-token HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Host: example.invalid
Connection: close
Content-Length: 62
{
"user_id": "theIdOfTheUser",
"client_code": "123456"
}
When the two way authentication module was able to find the corresponding transaction a 200 OK HTTP response will be send which contains a JSON body with a response token.
Attribute | Description |
---|---|
token | The token the user needs to enter on the mobile device to link it on the Token Server |
Example response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"token": "12345"
}
When the authentication module fails because the user cannot use one of the scopes that is configured for the client, a JSON response body is returned with a code and a redirect URI. This redirect URI can be an endpoint where the user can read more information why this scope is not available.
Attribute | Description |
---|---|
error | A short description what went wrong |
redirect_uri | The URI the user can be sent to in case this error occurs |
Example response
{
"error": "Scope X not available for user",
"redirect_uri": "https://example.com/scope-x-not-available"
}
When the authentication module was not able to provide a token an HTTP error response is used to provide the error details.
Http error code | Description |
---|---|
400 Bad Request | One of the required parameters in the request is missing, empty or invalid. |
403 Forbidden | The provided user_id does not have sufficient rights to access the scopes of the application. |
404 Not Found | No corresponding enrollment transaction was found. The provided client code is invalid or the transaction is expired. |
410 Gone | The state of the transaction is invalid, a token was already generated for this transaction. |
500 Internal Server Error | Something else went wrong |
The error message contains a JSON body with a short description of the error.
Example error response body
{
"error": "No transaction found for specified client code."
}
Entering the Response Token¶
Once the API call has been made and a response token is generated the token can be entered in the web page delivered by the authentication module of the Token Server. The user need to enter the response token in the appropriate input field on this web page. The Token Server uses the same web page to both display the client code and the input field of the response token.
To check if the user already created a response token (that is, entered the client code in the portal) an AJAX call can be made (from the web page that the Token Server displays) to the Token Server.
This AJAX call can be used to hide the input field for the response token. Sometimes users get confused by the code and the input field and they enter the client code into the input field for the response code.
Endpoint: GET /oauth/two-way-otp/enrollment/generated
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"generated": "GENERATED"
}
The generated
attribute has one of the following values:
GENERATED
: the user has entered the client code in the portal. The form can be submitted.NOT_GENERATED
: the user has not yet entered the client code in the portal. The form should not be submitted.SESSION_NOT_FOUND
: the Token Server cannot find Two Way OTP information for this request.
The user needs to enter the response token on the web page before they can submit the response code. The entered response token will be validated and if the response token is valid the user is authenticated (or linked to the client). The user has a maximum of three attempts to validate the response token. When he fails to do so the process must be started from the first step again: fetch a new client code and enter that in the portal again.
Templates¶
A set of Thymeleaf templates is available for the two way OTP authentication module. The templates can be customized as long as the below displayed predefined set of variables and messages are used.
Enrollment¶
File name: two-way-otp-enrollment.html
This template provides the user with a client code and the form to enter the response token that is shown on the portal. The template is responsible to display the client code, the code is given in the client code variable.
<h2 th:text="${clientCode}">_123456</h2>
Element | Description |
---|---|
${clientCode} | Variable that contains the client code. |
${csrfToken} | Variable that contains the csrf token. |
Another responsibility is to send a POST request with the entered response token.
Example form to post the response token
<form th:action="@{/two-way-otp/enrollment}" method="POST">
<input type="hidden" th:value="${csrfToken}" name="csrf_token"/>
<input type="text" id="id_token" name="id_token"/>
<input type="submit" value="Continue"/>
<a th:href="@{/two-way-otp/enrollment/cancel}">Cancel</a>
</form>
Element | Description |
---|---|
@{/two-way-otp/enrollment} | Endpoint to post the token validation request. |
@{/two-way-otp/enrollment/cancel} | Endpoint to restart the enrollment process and generate a new client code. |
The template should have the possibility to display error messages.
Example to display error messages
<div class="alert alert-error" th:if="${message}" id="messageBox">
<span th:text="#{${message}}">_Message</span>
</div>
Element | Description |
---|---|
#{${message}} | The message variable contains a message key that represents an error message in the message property file. |
The authentication module uses some predefined message keys to communicate errors to the template. These messages should be made available in the messages property file.
Message key | Description |
---|---|
twoWayOtp.enroll.error.invalidToken | The token provided is invalid. |
twoWayOtp.enroll.error.transactionState | The state of the transaction was invalid, in order to be able to enter a token the client code should be entered in the portal first. |
Failure without recovery¶
File name: two-way-otp-dead-end.html
When there is no transaction available the Token Server is not able to redirect the user back to the client / app. A page with instructions will be shown to the user on how to continue.
Too many failed attempts¶
File name: two-way-otp-max-attempts.html
After a number of failed attempts the transaction is invalidated and the user should restart the flow. This template should provide a button to restart the flow.
Example link to restart the flow
<a th:href="@{/two-way-otp/enrollment/cancel}">Restart authentication</a>
Element | Description |
---|---|
@{/two-way-otp/enrollment/cancel} | Endpoint to restart the enrollment process and generate a new client code. |
Events¶
Event id | Description |
---|---|
TWO_WAY_OTP_CREATED | Successfully created a token via the portal API. |
TWO_WAY_OTP_CREATION_FAILED_INVALID_TRANSACTION_STATE | Failed to create a token via the portal API due to an invalid transaction state. |
TWO_WAY_OTP_CREATION_FAILED_TRANSACTION_NOT_FOUND | Failed to create a token via the portal API because the transaction could not be found by the specified client code. |
TWO_WAY_OTP_CREATION_FAILED_INVALID_REQUEST | Failed to create a token via the portal API due to an invalid request. |
TWO_WAY_OTP_CREATION_FAILED_FORBIDDEN_SCOPES | Failed to create a token via the portal API because the user is not allowed to use the scopes for the client (e.g. no subscription). |
TWO_WAY_OTP_VALIDATED | Successfully validated a token. |
TWO_WAY_OTP_VALIDATION_FAILED_INVALID | Failed to validate a token because an invalid token value was provided. |
TWO_WAY_OTP_VALIDATION_FAILED_INVALID_MAX_ATTEMPTS_REACHED | Failed to validate a token because an invalid token value was provided. Due to the fact the maximum number of attempts was reached the transaction was invalidated. |
TWO_WAY_OTP_VALIDATION_FAILED_INVALID_TRANSACTION_STATE | Failed to validate a token because the transaction was not in the correct state. |
TWO_WAY_OTP_VALIDATION_FAILED_TRANSACTION_NOT_FOUND | Failed to validate a token because the transaction could not be found. |
TWO_WAY_OTP_VALIDATION_FAILED_INVALID_CSRF_TOKEN | Failed to validate a token because the cross side request forgery (CSRF) token was incorrect. |