Authentication

We strongly recommend the use of an OpenID Connect client. This will save you a lot of time and effort. Code examples using a Node js library are provided below.

There are 2 types of access tokens supported by LOKE. Depending on the use-case you may need to implement both.

Regardless of the token used, a LOKE organization admin will need to install your client/application for you to access to their organization via the API.

Each access token will allow access the API, but user tokens have a stricter permission scope:

  1. client token will have access to ALL of the organizations that have been installed for your client. An admin user will need to install new organizations for you to have access here.
  2. user token will have access to the INTERSECTION of organizations that the user can access and are installed for your client. The user will be able to install the organization if needed.
Client User Client Token User Token
Not Installed No Access 🚫 🚫
Not Installed Access 🚫 🚫
Installed No Access ✅ 🚫
Installed Access ✅ ✅

When To Use

This will depend on your use-case. But typically it will be a combination of the following:

  1. client token - for offline requests where the user is not present (behind the scenes requests). Use client_credentials grant type to get a client access token.
  2. user token for online requests where the user is present such as initial configuration and connection. Use authorization_code grant type to get a user access token.
Purpose Client Token User Token
Offline / Backend ✅
Connection / Initial Setup ✅
Configuration ✅ ✅

You will need an authorization_code grant initially to ensure the user has access to connect the org, so a LOKE user account must be used at this stage.

Once connected, if you are already ensuring the user belongs to a specific account on your side, you can safely fetch data from the connected LOKE organization using client_credentials. This also means that users do not need a LOKE user for configuration, only for initial connection (pairing a LOKE organization to an account on your side).

Common Use Cases

Configured By Account Manager or Admin (Managed)

You can likely just use your client token for this. LOKE support can install required organizations to your client so you can access them. Your admin tooling will need some way to allow admins to pick and connect an installed LOKE organisation for your accounts.

Configured by Customer (Self-Service)

You will likely need to use a combination of client and user tokens. Have the user authenticate (approve) to your UI.

Your user-facing UI can then list all the INSTALLED organizations the user has access to, and allow them to install additional locations.

Once the user has installed their organization, it will be accessible for offline access via a client token.

Any organizations returned by the API using the user token will be both installed and accessible by the user, thus safe to allow the user to configure.

OpenID Connect

The authentication system for LOKE adheres to the OpenID connnect standard. As such you can use any OpenID Connect client to speed up the development process.

OpenID Connect is a layer on top of OAuth 2.0, so any standard OAuth client will also work, albeit with some extra manual work.

Access tokens are JWTs with a limited time-to-live (expiry). When this token expires you will need to get a new token. An OpenID Connect client should be able to parse these tokens for you and typically has helpers to check if it is expired.

To use this authentication system you will need the following data:

  • The OpenID Connect Issuer URL: https://auth.loke.global
  • A client ID and secret: to be provided by LOKE on request

Examples

Client Access Token Using Client Credentials

This is not intended as production ready code. It is only intended to demonstrate usage.

import { Issuer, Client, TokenSet } from "openid-client";

const issuer = await Issuer.discover("https://auth.loke.global");

const client: Client = new issuer.Client({
  client_id: YOUR_CLIENT_ID,
  client_secret: YOUR_CLIENT_SECRET,
});

/*
Step 1: when your process starts use getToken() to authenticate once
Step 2: when the token expires re-do step 1

You can check if the token is expired before using it. The expiry is embedded in the JWT.
*/

/** Generate a URL to redirect to */
async function getToken() {
  // Client ID and secret are already initialized in client
  // This tokenSet contains an access token
  const tokenSet = await client.grant({ grant_type: "client_credentials" });
  return tokenSet;
}

User Access Tokens via Authorization Codes

If you are new to OAuth then a couple of references to help understand are - this Okta article or this Auth0 article

This is not intended as production ready code. It is only intended to demonstrate usage.

import { Issuer, Client, TokenSet, generators } from "openid-client";

const issuer = await Issuer.discover("https://auth.loke.global");

const client: Client = new issuer.Client({
  client_id: YOUR_CLIENT_ID,
  client_secret: YOUR_CLIENT_SECRET,
});

/*
Step 1: when a user tries to log in redirect them to a URL generated with generateAuthorizationUrl()
Step 2: after "approving" the user's browser will be redirected back to your chosen callback URL
Step 3: process the callback request using authorizationCallback()
Step 4: store the returned access token, eg in a cookie or session so that you can use it on future requests
Step 5: when the token expires you will need to redirect the user back to step 1

You can check if the token is expired before using it. The expiry is embedded in the JWT.
*/

/** Generate a URL to redirect to */
function generateAuthorizationUrl() {
  const state: string = randomBytes(20).toString("hex");
  const codeVerifier: string = generators.codeVerifier();
  const codeChallenge: string = generators.codeChallenge(codeVerifier);

  const url: string = client.authorizationUrl({
    redirect_uri: `${MY_BASE_URL}/my/callback`,
    scope: "openid",
    prompt: "consent",
    state,
    code_challenge: codeChallenge,
    code_challenge_method: "S256",
  });
  return { url, state, codeVerifier };
}

/** Process a callback request (after the user has hit approve in LOKE) */
function authorizationCallback(req) {
  const state = req.body.state;
  // Need some way to get this from when we created the URL originally.
  const codeVerifier = getPreviousCodeVerifier(req);
  const params: CallbackParamsType = client.callbackParams(req);
  // This needs to match
  const url = `${MY_BASE_URL}/my/callback`;

  // This tokenSet contains an access token and an ID token.
  // Keep this to use in the session.
  const tokenSet: TokenSet = await client.callback(url, params, {
    state,
    code_verifier: codeVerifier,
  });
}

LOKE Apps

Installing LOKE apps

Anyone can use an installation URL to install your app on their organisation.

https://auth.loke.global/install-client?client=APP_CLIENT_ID

Click install once you have selected the organisation and you will be redirected to the set URL paramater for that app. To change this URL see modify LOKE apps

Modify LOKE apps

After creating a LOKE app, you can make changes to it.

  1. Select organisation from the top navigation

  2. Select the LOKE App you want to modify

  3. You can adjust many settings related to your app including the URL to what the users will be redirected to once they have installed your LOKE App

In this article