JWT is a service application that provides a set of actions to handle JSON Web Tokens, both for creating tokens and parsing existing ones, exposed via server and service actions on the JWT module, so it can be consumed in an Outsystems application. The actions provided are meant to handle different cryptographic algorithms and key formats, but they can be divided into three groups and most likely only one action per usage scenario might be needed:
To learn more about JWT usage and its structure, consult the JWT introduction.
It is recommended to consult the component demo to obtain implementation examples.
Symmetric (same key is used to sign and validate the token)
Asymmetric (private key is used to sign and public key to validate the token)
PEM format is a text file with the delimited key encoded in base64
-----BEGIN RSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDKEY_ENCODED_IN_BASE64-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
KEY_ENCODED_IN_BASE64
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----KEY_ENCODED_IN_BASE64 ----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
----END PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----KEY_ENCODED_IN_BASE64 -----END ENCRYPTED PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN PUBLIC KEY----KEY_ENCODED_IN_BASE64 -----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY----
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----KEY_ENCODED_IN_BASE64 -----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
These are text file with the key encoded in a JSON structure, equivalent to PEM but less prone to formatting errors
Represents a single key, can contain the private or public key
{"use": "sig", "kty": "RSA","kid": "key_id", "alg": "RS256","n": "KEY_ENCODED_IN_BASE64", "e": "AQAB"}
{
"kty": "RSA",
"alg": "RS256",
"e": "AQAB"
A set of multiple JSON Web Keys
{ "keys": [ { "use": "sig", "kty": "RSA", "kid": "key_id_1", "alg": "RS256", "n": "KEY_ENCODED_IN_BASE64", "e": "AQAB" }, { "use": "sig", "kty": "RSA", "kid": "key_id_2", "alg": "RS512", "n": "KEY_ENCODED_IN_BASE64", "e": "AQAB" } ]}
"alg": "RS512",
]
Generate a JSON Web Token (JWT)
──────────────────────────────────────────────────────────────────
A JWT can be generated, in two different ways. The difference is in the token Signature definition, related to the JWT security. On one hand, a JWT can be generated using either a secret plain key (for secret key) or a private key (generating a PEM file). On the other hand, a JWT can be generated using a JSON Web Key (JWK), as a private key. This key is a JSON object.
a) Generate it using a secret plain / PEM key
To generate a JWT using a private key (for asymmetric algorithms), a PEM file must be generated to obtain a private and public key. Consult the Google documentation to generate these keys.
Step 1 - JSON Web Token (JWT) configuration
Header configuration
For Symmetric algorithms
(secret plain text key)
For Asymmetric algorithms
(private key from PEM file)
Use the SymmetricAlgorithm static entity to choose a symmetric algorithm.
Use the AsymmetricAlgorithm static entity to choose an Asymmetric algorithm.
Payload configuration
Fill the Payload data. All data is optional, however it is recommended to fill some Payload information. Custom claims can also be added. This image shows all Payload information that can be added in the generated token.
The given data is only as an example. You must adapt the data with your requirements.
Signature configuration
Use a secret plain text key. It is recommended to use a long and complex secret key, because this same key is used to decrypt the generated JWT when reading it.
Use a private key from a generated PEM file. The corresponding public key must also be generated in another PEM file. Consult the Google documentation to generate these keys.
Step 2 - Configure the corresponding action
For Symmetric algorithms (using secret plain text key)
Use CreateSignedSymmetricTokenService action and fill it with values specified in the previous step for the Header, Payload and Signature.
For Asymmetric algorithms (using a private key from a PEM file)
Use CreateSignedAsymmetricTokenWithPemKeyService action and fill it with the values specified in the previous step, for the Header, Payload and Signature parts.
Step 3 - Validate the generated token
Verify the success parameter returned by the corresponding action. An encoded token is also returned, and can be separated to obtain the header, payload and the signature individually using a String_Split action.
b) Generate it using a JSON Web Key (JWK)
A JSON Web Key (JWK) must be generated to obtain a private and public keypair. Consult https://mkjwk.org/ to generate all necessary keys, for testing purposes the online generator can be used but for Production is highly recommended to generate them locally or use the one from your authentication provider.
When generating a token using a JWK as signature, the Header cannot be configured. The related JWT must use an asymmetric algorithm, and both algorithm and key id parameters are defined when generating the JSON Web Key (JWK).
The signature must be a generated JSON Web Key (JWK). Consult https://mkjwk.org/ to generate all necessary keys.
The public and private keypair must be used to encode the JWT. The related public key (another key generated at the same time) will be used to validate the generated token.
Public and private keypair sample.
Read a JSON Web Token (JWT)
Two types of JWT can be decoded, using the related validation method. On one hand, a JWT generated using a Plain / PEM key, can only be decoded using either the same secret plain key, or the public key related to a private PEM key. On the other hand, a JWT generated using a JSON Web Key can only be decoded using the related public key (or the generated keypair).
a) Read a JWT generated using a plain secret / PEM key
To verify the signature of an asymmetric generated token (token generated using a private key in a PEM file), the public key related to the private one (when generating the PEM file) is necessary.
Step 1 - Configure all necessary parameters
Note:
To verify the LifeTime, the expected Issuer and the expected Audience, the signature verification must be enabled (set as TRUE).
All input parameters to decode a generated JWT.
Step 3 - Trigger the read action to decode the JWT
The read action created in the first step, can be triggered using a button or a link with the Destination property set to the read token action.
The ReadTokenService action returns the following parameters:
b) Read a JWT generated using a JSON Web Key (JWK)
To verify the signature of the generated token, the public key (or keypair) related to the private one (when generating the JWK) is necessary.
- Custom claims now allows for complex (nested JSON objects), along with simple objects:
Just set the boolean and you can put an entire JSON object as a text inside of the Claim Body
Although the action for reading tokens is the same for all signing scenarios (no separation between algorithms) and its invocation is easier that the Create Token actions, using JWT for authentication will require some preparation prior to the first call. If when creating a token for authentication in a REST service the rules to fill its payload are defined by the third-party service, now when we're implementing authentication on our service we must define the all the additional rules consumers should follow.
JSON Web Tokens is just one of the authentication options for REST APIs, it works really well for scenarios where different servers need to connect, as it can provide authentication between two or even more entities. It can also be used on client-to-server implementations where there's no human involved, but whenever there's human involved in that flow an authentication based in OAuth makes much more sense.
Assuming generated tokens will always be signed (which should be) there's the decision whether to use asymmetric or symmetric algorithm. The rule of thumb is simple:
Symmetric algorithms are better suited when there's a high trust between entities and the need to identify who's making the call isn't as important, so that a common secret can be shared between all parties. If that's the case a symmetric algorithm is easier to implement, and that shared secret can work in both ways of the communication. Examples:
Asymmetric algorithms should always be used when the API is meant to be called publicly or from outside the domain of the organization, as it provides stronger identification of parties.
It's very important to never forget that these tokens are signed but not encrypted. It's encouraged that some additional claims are added to the tokens, like additional identifiers, but no sensitive information should ever be saved inside it.
It's tempting to use JSON Web Tokens as an application's session token, its custom claims can hold lots of data in a single structure that can be added throughout the session. But a JSON Web Token has a higher footprint than other simpler session containers (like plain old session variables) and with a cryptographic signature involved in each call that will take a toll in the performance. JSON Web Tokens are well suited for authentication and identification.
Introduction to JSON Web Tokens
Authentication in REST services using JSON Web Tokens with Outsystems