One-Time Authorization Code for REST APIs in WSO2 Identity Server
- Johann Nallathamby
- Director - Solutions Architecture - WSO2
Photo by Mikhail Nilov
Authorizing the caller’s security context in an API workflow
WSO2 Identity Server provides many identity management workflows and password management workflows out of the box, e.g., self-registration, user invitations, password recovery, etc. However, it is not unusual to come across a situation where the workflow capabilities provided out of the box in the product, are not sufficient to fulfill your business requirement.
In such situations, users would generally prefer to take one of the following alternative courses of action, listed in ascending order of complexity:
- Combining a couple of existing REST APIs in a specific sequence to produce the expected workflow.
- Implementing custom REST APIs, and combining them with existing REST APIs in a specific sequence, to produce the expected workflow. The custom REST APIs may or may not invoke WSO2 Java services in the backend. The custom REST API will also be hosted in WSO2 Identity Server.
The user experience will most likely need to be bespoke on top of the customized backend.
One of the cross-cutting security requirements in all API workflows is ensuring the caller’s security context is the same across the workflow. In other words, how do we ensure that the caller who is invoking the current REST API is the one and the same who invoked the previous REST API?
For the built-in API workflows, this requirement is already addressed. For instance, if we take a look at the admin-initiated forced password reset workflow, it consists of two separate REST APIs; the first one is to initiate sending a verifier and the second one is to present the verifier and update the password. The “confirmationCode” parameter is used as the verifier to authorize the caller’s security context in the “updatePassword” operation. Similarly, we need a generic mechanism to engage verifiers to any custom API workflow in WSO2 Identity Server.
The means by which we are going to solve the above problem is using One-Time-Authorization-Code (OTAC) verifiers. Using OTAC for authorizing API access isn’t something new. This idea has inspirations borrowed from the very popular OAuth 2.0 suite of standards that addresses delegated access control for APIs. In OAuth 2.0, the “authorization code” is an intermediate code that is used to represent the authorization grant given by the “resource owner” to the “client,” issued at the “authorization endpoint” and verified at the “token endpoint”. The “authorization code” is in fact a time-bound one-time code. Similarly, “OAuth 2.0 Threat Model and Security Considerations” (RFC 6819), recommends techniques like using short expiration times, one-time usage, and use explicitly defined scopes for audience and tokens for “access tokens”.
OTACs are equally applicable to secured APIs as much as they are to open APIs. Open APIs don’t enforce authentication, however, authorization that is not based on an authenticated subject is still a possibility. Secured APIs could also need OTACs because API authentication only asserts who the caller is. However, it doesn’t assert anything more about the caller’s context.
In terms of implementing OTACs, using the “JSON-Web-Token” (JWT) standard is advantageous as it helps to build a stateless OTAC implementation, meaning that you don’t need to worry about having a mechanism in place to clean up inactive OTACs like stored procedures.
Sample user story: consumer onboarding workflow
In order to understand this problem and its requirements better, let’s look at a sample user story. The sample user story we will use is a consumer onboarding workflow.
Suppose we want to compose a consumer onboarding workflow that is going to consist of the following 4 components:
- Initiate with Invitation workflow
- Email address verification
- Mobile number verification
- Set password
As you may have already guessed, WSO2 Identity Server doesn’t have a single REST API that supports the above onboarding workflow out of the box. However, it provides multiple REST APIs that implement parts of the above workflow. For instance, step 1 can be achieved with “Invitation workflow”. Step 2 can be achieved by including the e-mail address verification option in the invitation workflow. Step 3 and step 4 can be achieved with “admin-initiated force password reset” API. Hence, our natural reaction is to ask whether we can combine these REST APIs in a particular sequence to achieve our end-to-end workflow requirement.
As discussed before, the Invitation workflow with the email verification option is a distinct workflow from the admin-initiated forced password reset workflow. Hence, there is no built-in verifier that is returned in the response from step 2, passed in the request, and verified in step 3. The challenge we face now is, how do we ensure that the caller who is invoking step 3 is the one and the same who invoked step 2?
Hence, we are faced with the prospect of introducing a new verifier to the API workflow that is going to be composed of these two REST APIs.
- Add a new interceptor to the REST API that will intercept the response of step 2 and insert an OTAC to the response as a custom header.
- Add a new interceptor to the REST API that will intercept the request of #3 and verify the OTAC coming in a customer header.
The benefit of using headers to transport the OTAC is that it decouples the security contract from the business API contract. You can find the implementation of OTAC for WSO2 Identity Server here.