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
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);