JWT Authentication - rezolved/rezolve_sdk_sampleapp_android GitHub Wiki

Rezolve is utilizing a server-to-server JWT authentication system, conformant with the https://tools.ietf.org/html/rfc7519 standard. If you are not familar with JSON Web Tokens, the site https://jwt.io/ provides an excellent primer on the use of JWTs, as well as links to various JWT libraries you can utilize.

Rezolve expects the primary authentication of users will happen outside the SDK. Thus, exactly how you implement authentication in your app will depend on your existing auth system. In the server-to-server realm, however, there is only one instance in which your authentication server must interact with the Rezolve server.

After that, whether or not the SDK can talk to Rezolve depends on supplying a valid JWT to the SDK from your auth system.

When the Partner creates a new user on their auth server, or wishes to associate an existing user with Rezolve for the first time, the partner must generate the Registration JWT, and then POST it to the /api/v2/authentication/register endpoint. The Rezolve server will validate the JWT, create a new user, create the user's public/private key pair, and return to you the Rezolve EntityId.

When a user logs in to your auth system, generate a new Login JWT and supply to CreateSession in the SDK. As long as the JWT is valid, the SDK can talk to Rezolve. A method is suggested below for smoothly handling JWT timeouts without interrupting the SDK session.

Terminology

Term Definition
partner_id A numerical id you are assigned by Rezolve. Usually a 2-4 digit integer.
partner_api_key The API key you are assigned by Rezolve. 36 characters including dashes.
partner_auth_key The Auth key you are assigned by Rezolve. This plays the role of the JWT Secret. The partner_auth_key is typically a ~90 character hash.
JWT token A JSON Web Token, consisting of a header, payload, and signature. The header and signature are signed with the parther_auth_key, above. It is used as a bearer token when communicating with the Rezolve server.
accessToken In the IOS and Android code samples, the accessToken is the JWT Token you generated.
deviceId An id that is randomly generated upon app install and stored. This id is placed in both the JWT payload and x-header sent by the SDK. The Rezolve server checks that these values match to deter request origin spoofing. All calls except Registration calls require this.

JWT Flow

JWT Flow Chart

Create the Registration JWT

:information_source: Note: For testing via cURL or Postman without a server-side JWT library, you can use https://jwt.io/#debugger to generate valid JWT tokens.

Use https://www.epochconverter.com/ to generate the token expiration in Epoch time.

Click here for screenshots showing registration using jwt.io and Postman.

Requirements

You must possess:

field description example
partner_id The numerical id you are assigned by Rezolve 317
partner_api_key The API key you are assigned by Rezolve a1b2c3d4-e5f6-g7h8-i9j0-a1b2c3d4e5f6
partner_auth_key The Auth key you are assigned by Rezolve qwer+4ty ... JYG6XavJg== (approx 90 characters)

JWT Header

key value notes
alg HS512 algorithm, HMAC SHA-512
typ JWT type
{
    "alg": "HS512",
    "typ": "JWT"
}

JWT Payload

key value notes
rezolve_entity_id :NONE: use :NONE: when registering
partner_entity_id your_user_id The unique identifier for your user record. This may be a numerical id, or an identifying string such as email address.
exp 1520869470 Expiration, as a unix timestamp integer. Set the expiration value to a small number, now() + 30 minutes or less.
{
    "rezolve_entity_id": ":NONE:",
    "partner_entity_id": "partner_entity_id",
    "exp": 1520869470
}

Signature

HMACSHA512(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    ${$partner_auth_key}
)

Sign the header and payload with the partner_auth_key. It is not necessary to decode the key before using it. Pass the whole value as a string to your library's getBytes method.

You may need to specify the charset as UTF8.

  • Example 1, Microsoft: SecretKey(Encoding.UTF8.GetBytes(key));
  • Example 2, Java: Secret.getBytes("UTF-8");

The resulting JWT will look something like this (except without linebreaks); the first third is the header, the second third the payload, and the last third the signature:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.
eyJyZXpvbHZlX2VudGl0eV9pZCI6IjpOT05FOiIsInBhcnRuZXJfZW50aXR5X2lkIjoiMTIzIiwiZXhwIjoxNTIwODY5NDcwfQ.
5y2e6QpUKcqTNLTv75nO6a6iFPVxrF8YeAH5NTg2ZO9dkub31GEs0N46Hu2IJf1bQ_vC2IOO9Z2N7drmvA_AKg

Register a new Rezolve User

After the JWT is created, POST it to the Rezolve registration endpoint. This will create a Rezolve User, generate a public/private keypair for the user, and return to you the corresponding Entity Id.

Example, using Sandbox endpoint:

POST: https://core.sbx.eu.rezolve.com/api/v2/authentication/register
-H content-type: application/json
-H x-rezolve-partner-apikey: your-api-key
-H authorization: Bearer signed-jwt
-d {
  "name": "John Doe",
  "last_name": "Doe",
  "first_name": "John",
  "email": "[email protected]"
}

Responses:

201 OK
{
  "partner_id": "4",
  "entity_id": "d89d-d34fd-fddf45g8xc7-x8c7fddg"
}

400 Bad Request
{
  "errors": [
    {
      "type": "Bad Request",
      "message": "Missing required parameters in request body. Required: [\"field1\", \"field2\"]",
      "code": "6"
    }
  ]
}

422 Unprocessable entity
{
  "errors": [
    {
      "type": "Bad Request",
      "message": "Incorrect or malformed parameters",
      "code": "5"
    }
  ]
}

The endpoint will reply with an entity id and the partner id. You should save the Rezolve Entity Id to your authentication database and associate it with the user's record.

Logging in a User

Once a Rezolve User has been registered and an entity_id obtained, you can log in the user using the instructions below.

For returning users, log them in via your normal method in your auth server, and then follow the instructions below.

Create a new Login JWT, and use it as the accessToken in the createSession method.

JWT Header

Note the addition of the "auth" line.

key value notes
auth v2 auth version to use, login uses v2
alg HS512 algorithm, HMAC SHA-512
typ JWT type
{
    "auth": "v2",
    "alg": "HS512",
    "typ": "JWT"
}

JWT Payload

Note the addition of the device_id.

key value notes
rezolve_entity_id your_rezolve_entity_id use the entity_id you obtained during registration
partner_entity_id your_partner_entity_id set it to the unique identifier for your user record
exp 1520869470 Expiration, as a unix timestamp integer. Set the expiration value to a small number, now() + 30 minutes or less.
device_id wlkCDA2Hy/CfMqVAShslBAR/0sAiuRIUm5jOg0a An id randomly generated upon app installation and stored. This id is placed in both the JWT payload and x-header sent by the SDK. See below for generation instructions.
{
    "rezolve_entity_id": "entity123",
    "partner_entity_id": "partner_entity_id",
    "exp": 1520869470, 
    "device_id": "wlkCDA2Hy/CfMqVAShslBAR/0sAiuRIUm5jOg0a"
}

Signature

HMACSHA512(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    ${$partner_auth_key}
)

Sign the header and payload with the partner_auth_key.

Generating the device_id

// generate the random id
String deviceId = UUID.randomUUID().toString();

// store the device_id
private static void writeDeviceIdFile(File deviceidfile) throws IOException {
    FileOutputStream out = new FileOutputStream(deviceidfile);
    String id = UUID.randomUUID().toString();
    out.write(id.getBytes());
    out.close();
}

// read the stored device_id
private static String readDeviceIdFile(File deviceidfile) throws IOException {
    RandomAccessFile f = new RandomAccessFile(deviceidfile, "r");
    byte[] bytes = new byte[(int) f.length()];
    f.readFully(bytes);
    f.close();
    return new String(bytes);
}

// supply the random id to the SDK
RezolveSDK.setDeviceIdHeader(deviceId);