Authentication in REST services using JSON Web Tokens with Outsystems
OAuth, in its various versions, is the current standard for authentication in REST services, and something that we, as users, are familiar to use everyday, when using our Facebook or Google accounts to login elsewhere. But the conventional OAuth authentication flow is driven towards an end-user, where he grants directly access to his account’s features to an application, third-party or not.
In some integration scenarios, where a single sign-on is expected, this extra validation step per user must be removed from the authentication flow, so the user seamlessly accesses the account. In this case it’s not the end user that’s suppose to authenticate in the service, but the application itself. This has been an issue in public REST services, specially at enterprise level, and the way many have started to solve it is by integrating JSON Web Tokens, or JWT, in their OAuth authentication.
In a nutshell, JWT is a signed and base64 encoded JSON token based on two name-value pair structures, known as claims. The first structure, the header, contains claims that form the token’s metadata: like the type of token or, more important, the signing algorithm used.
The second is the payload, it contains all the token data in a set of claims. This can include the reserved claims defined by the RFC standard, that define who issued the token and more, some of which are mandatory, but also an arbitrary list of custom claims set by the application.
The third part of the token is the signature: the header and the payload combined are signed with a symmetric key (e.g. HMAC) or a private/public key pair (e.g. RSA), which will be used by the server to validate the authenticity of the token.
All this is just a brief overview of the format of the token and what it contains, for more details follow the links below that has a more in depth explanation of how JWT works, and it includes some fully functional samples.
Before creating the token
To properly invoke a REST service that requires JWT first of all you need to read its documentation, to create an application and configure it for using JWT. This seems redundant but each service has it’s own implementation details, so to build the token some information is needed in advance:
- supported signing algorithms
- required values for reserved claims like audience (aud), subject (sub) or issuer (iss), that probably need to have a known value related with the service’s configuration
- list of additional claims defined by the service to beincluded in the token, this can be an internal id or code, which may be mandatory or not
- also needed, at a later stage, is the way to build the REST request with the newly created token, which will be included as a parameter in the authentication request
Knowing the supported algorithms we can prepare the signing information to create the token. In theory JWT supports both symmetric or asymmetric algorithms, but not all REST services implement both, and for public API’s the usual option is to only have support for asymmetric signing (symmetric signing makes sense in different scenarios, more on that soon in another post). For that reason the focus from now on will be asymmetric signing with RSA, which means creating a pair of public/private keys. Your service’s documentation will provide help on how to do this, but it won’t much different than this:
openssl genrsa -aes256 -out my_private_key.pem 2048
openssl rsa -pubout -in my_private_key.pem -out my_public_key.pem
The public key will need to be set in service API’s configuration, so that the token is validated correctly when the authentication service is called, and the private key and password (please don’t create a “passwordless” key pair…) will be used for creating the token.
Creating the token
Having the signing keys in PEM format and all the parameters ready, the JWT component from Outsystems forge can be used to create the JWT. Currently there are three public actions to create tokens: CreateSignedAsymmetricToken, CreateSignedSymmetricToken and CreateUnsignedToken, although it may not make sense it’s possible to create an unsigned token, having only the encoded header and payload parts without the signature section.
The action needed for this example is CreateSignedAsymmetricToken and by now all the information needed to create one should be available:
All the three actions return a token encoded in base64, needed later in the authentication, but also the plain version of the header and payload in JSON, which is useful for debug and logging purposes:
Sending the token
Now with the signed and encoded token the REST call for the authentication can be built. At this point is very important to go back to the service’s documentation, as the method the token is added to the request varies a lot, the following example shows the most common scenario of sending it as an HTTP header, but sending it as regular parameter of a POST or even a GET call is also frequent.
This should be enough to perform a REST call using JSON Web Tokens, and the authentication call responded with the authorization token, but feel free to reach out and ask your question.