Create custom JWT Token & Signing Keys for use as your own Realm Custom Authentication Provider.

Josman Pérez Expóstio
Realm Blog
Published in
5 min readJun 9, 2021

Motivation

This guide will show how to create a signing key and a JWT token to test one of the Authentication providers Realm offers.

There are two main scenarios for requiring Custom JWT Authentication.

  1. Using a third-party service authentication like Firebase, Cosync, or Auth0.
  2. Using your own custom authentication to sign and validate JWT tokens.

This guide will focus on the creation of custom signing keys and JWT tokens to authenticate your users on your Realm App.

Prerequisites

You will need to download the example project provided to create a signing key and JWT tokens that you are going to use later on.

Download or clone this repository: https://github.com/josmanperez/JWTNodejs into a folder on your system.

Alternatively, if you have a signing key and JWT ready from the external provider, you can skip the above prerequisite and skip the section of “Configure and run the project example” to start from “Enable & configure Custom JWT Authentication”.

Step by step guide

Configure and run the project example

After downloading or cloning the project, please follow the steps documented in its README to create and retrieve signing keys and JWT tokens.

Open a terminal in the project’s root folder and install the dependencies with

npm install

Edit the aud field’s value in the claims object (within the index.js file) to match your own Realm App ID:

var claims = {
"iss": "http://myapp.com/", // The URL of your service
"sub": "users/user1234", // The UID of the user in your system
"scope": "self, admins",
"aud": "app-id" // Your APP ID
};

After that, run the project:

node index.js

This will output the signing key and a JWT token signed by that key:

signing key: UWaNHq1sR+3HEYyrcqO1MLa4zgtR9mYHW/wRYNsBzKRlqBMUD8U3sLUS0+j2RsN2tfNV4rQhhxfcmNmDldk94EOtDiAxg8By6YUod0fXIgWGykeb7VYg5s/NzS1UTTe8Fj7ddB522HwR3iCz97sF3H2oUW0MFYtJr9eF61MG+ZHbaw4FWeqGwqc9W0is/Q4ceLzBR3ndS+gsT/5sdMVpAt+oVa0Z08WG0BCRJrFyJhcxOkC2UGGGQVxcGUHS/ICP5zgWcOp3/iDswC6MBkl3W1T4BFmGyrBhjArGWaCwo2ae0/Z0rvSkeERgF4+AMFNRIjAYEcERFUhG1kgwL1/vAw==JWT token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbXlhcHAuY29tLyIsInN1YiI6InVzZXJzL3VzZXIxMjM0Iiwic2NvcGUiOiJzZWxmLCBhZG1pbnMiLCJhdWQiOiJhcHAtaWQiLCJqdGkiOiI5NzU4YjhmNC0yMGEwLTQ5YjgtOGU0ZS03Njg3M2NhYTVlYmMiLCJpYXQiOjE2MTg2NzM1MjcsImV4cCI6MTYxODY3NzEyN30.TJ4UdpODFBrquoJwTpUIbuYQ30qXUi5PCOhIZzHVfykJwt {
header: JwtHeader { typ: 'JWT', alg: 'HS256' },
body: JwtBody {
iss: 'http://myapp.com/',
sub: 'users/user1234',
scope: 'self, admins',
aud: 'app-id',
jti: '9758b8f4–20a0–49b8–8e4e-76873caa5ebc',
iat: 1618673527,
exp: 1618677127
},
toString: [Function (anonymous)]
}

You need to save these for the next step. PLEASE be aware that we need to use the same signing key created in the step below to create a new JWT token with the same signing key, instead of creating a new signing key each time.

var signingKey = "UWaNHq1sR+3HEYyrcqO1MLa4zgtR9mYHW/wRYNsBzKRlqBMUD8U3sLUS0+j2RsN2tfNV4rQhhxfcmNmDldk94EOtDiAxg8By6YUod0fXIgWGykeb7VYg5s/NzS1UTTe8Fj7ddB522HwR3iCz97sF3H2oUW0MFYtJr9eF61MG+ZHbaw4FWeqGwqc9W0is/Q4ceLzBR3ndS+gsT/5sdMVpAt+oVa0Z08WG0BCRJrFyJhcxOkC2UGGGQVxcGUHS/ICP5zgWcOp3/iDswC6MBkl3W1T4BFmGyrBhjArGWaCwo2ae0/Z0rvSkeERgF4+AMFNRIjAYEcERFUhG1kgwL1/vAw==";
var jwt = helper.createToken(claims, signingKey);
console.log(`JWT token: ${jwt} \n`);

Enable & configure Custom JWT Authentication

Go to DATA ACCESS in your Realm App and select Authentication

Authentication providers screenshot
  • Enable the “Custom JWT Authentication” provider.
  • Select “Manually specify signing key”, as this example will cover the custom creation of a signing key.
  • Select HS256 as the signing algorithm. We could use RS256 if desired but the default JWT token creation in the project example uses HS256 (it can be easily configured to use RS256)
  • Create a new Signing Key (secret name) and paste the signing key created in the previous step
Signing keys section
  • Save changes (Review and Deploy if Sync is not enabled)
Settings for the authentication provider

Test the authentication method

There are several ways to test the authentication method. We are going to use a GraphQL external client to test it.

We need to have documents and collections added to the Schema on our Realm App before being able to query and return documents.

Assuming we have the above, we could use Postman to query our GraphQL endpoint. Under BUILD -> GraphQL section in Realm, you will need to grab the GraphQL Endpoint and execute a POST to that endpoint with the authentication method configured previously and a query to return a document.

To use the Custom JWT token authentication we need to add the HEADER:

'jwtTokenString: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbXlhcHAuY29tLyIsInN1YiI6InVzZXJzL3VzZXIxMjM0Iiwic2NvcGUiOiJzZWxmLCBhZG1pbnMiLCJhdWQiOiJjYXNlcy1sb2dleSIsImp0aSI6ImMyNjU4NWE2LTBhNTktNGI3ZS05NTA0LTZmNTBlM2U0ZGIzYSIsImlhdCI6MTYxODY3NDI1NywiZXhwIjoxNjE4Njc3ODU3fQ.vfHSXacPPGWvKvEOx7hneLOTj6WQFnJMY8ta_Jo5_QU'

To the request

A cURL example of a request could be the following:

curl - location - request POST 'https://eu-west-1.aws.realm.mongodb.com/api/client/v2.0/app/cases-logey/graphql' \
- header 'jwtTokenString: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbXlhcHAuY29tLyIsInN1YiI6InVzZXJzL3VzZXIxMjM0Iiwic2NvcGUiOiJzZWxmLCBhZG1pbnMiLCJhdWQiOiJjYXNlcy1sb2dleSIsImp0aSI6ImMyNjU4NWE2LTBhNTktNGI3ZS05NTA0LTZmNTBlM2U0ZGIzYSIsImlhdCI6MTYxODY3NDI1NywiZXhwIjoxNjE4Njc3ODU3fQ.vfHSXacPPGWvKvEOx7hneLOTj6WQFnJMY8ta_Jo5_QU' \
- header 'Content-Type: application/json' \
- data-raw '{"query":"query {\n listingsAndReview {\n _id\n }\n}","variables":{}}'

If everything was configured correctly, this request should validate and return the desired document:

{
"data": {
"listingsAndReview": {
"_id": "10051164"
}
}
}

Possible errors thrown

The audience not configured correctly

This error happens when the aud set on the JWT token claim is not configured correctly. If we made a mistake writing the App ID this error might be thrown.

Error:
'"cases-logey"' not present in 'aud' claim

Audience not present

This error could happen when the aud field is not present on the JWT token, even though it was not set in the optional audience field when configuring the Authentication provider.

Error:
invalid custom auth token: 'aud' must be a string or array of strings containing the clientAppId

Invalid number of segments

This error will be thrown if the JWT is not well-formatted. A JWT token consist of three parts encoded separately using Base64url Encoding (RFC 4648) and concatenated using periods.

Error:
token contains an invalid number of segments

Signature is invalid

This error will be thrown if the JWT token is not signed by the same signing key provided in the authentication settings under the Realm signing key (secret)

Error:
signature is invalid

Wrapping everything up

In this tutorial, we learned how we can create our own custom signing keys to authenticate JWT tokens and let users access our app. The purpose of this tutorial is to learn how to use custom JWT authentication with Realm to integrate yet another authentication provider into our app.

We can benefit from using a third-party authentication provider like https://cosync.net/, https://auth0.com/, or http://firebase.google.com, but today we learned how to integrate with our own library.

--

--

Josman Pérez Expóstio
Realm Blog

If I had to sum up my professional interests in one sentence, I could only say that I am passionate about technology.