Skip to main content

Authenticate your backend

Nabla Connect is intended for your backend systems. Authentication follows the OAuth 2.0 client credentials flow with JWT-based client assertions.

info

The <baseUrl> for all Connect APIs is https://<region>.api.nabla.com/v1/connect/server, where <region> is us or eu. See API versioning.

1. Creating an OAuth Client

An OAuth Client authenticates with Nabla Connect on behalf of your backend. You will need to create one in Nabla Connect Admin and provide either of the following:

  • JWKS URL: a JSON Web Key Set endpoint that hosts one or more public keys. This is the preferred method as it allows for seamless key rotation. Your JWKS URL hosts one or more public keys, enabling Nabla to validate tokens using the correct key. If your keys change, you can simply update the response of your JWKS endpoint without reconfiguring your OAuth Client.

    How to obtain a JWKS URL

    If you don't already have a JWKS, you can expose one by setting up a service that hosts your public keys in the JWKS format. Cloud services such as AWS Cognito, Google Identity Platform, and Auth0 can help you automatically generating and exposing your keys as a JWKS.

  • Public key (static): Alternatively, you can provide a static public key in X.509 format (base64-encoded). This is less flexible since key rotation requires updating the configuration in the Nabla Connect Admin. We only accept the RS256 algorithm. You can generate a pair of public/private RSA keys using the following commands:

    openssl genpkey -algorithm RSA -out private_key.pem
    openssl rsa -pubout -in private_key.pem -out public_key.pem

    You can then create an OAuth Client using the public_key.pem file, which content starts with -----BEGIN PUBLIC KEY-----.

After creation, copy the OAuth Client UUID and use it as iss and sub when constructing the JWT client assertion.

Regularly rotate the OAuth keys

Rotate keys regularly. With a JWKS URL, update the keys at your endpoint with no downtime. With a static public key, create a new OAuth Client, migrate assertion signing, then delete the old client after a migration period.

2. Constructing a JWT Client Assertion

The client assertion is a one-time JWT used to authenticate against POST /oauth/token. Sign it with the private key that corresponds to the OAuth Client.

JWT header

  • alg: must be RS256.
  • typ: must be JWT.
  • kid: required if the OAuth Client uses a JWKS URL. It must match a key ID in the JWKS.

JWT body

  • sub: the OAuth Client UUID.
  • iss: same as sub.
  • aud: the full token endpoint URL (<baseUrl>/oauth/token).
  • exp: must not be in the past, and no further than 5 minutes in the future.
  • iat: optional; if present, must be within 5 minutes of exp and not in the future.
  • jti: optional but recommended — prevents reuse of the same JWT.

For constructing and signing JWTs, you can use libraries from Auth0, notably java-jwt for Java. See also RFC 7523.

Sample TypeScript to fetch an access token
import jwt from "jsonwebtoken";
import { randomUUID } from "crypto";

type AccessTokenParams = {
baseUrl: string;
oauthClientId: string;
oauthPrivateKey: string;
};

export async function requestAccessToken({
baseUrl,
oauthClientId,
oauthPrivateKey,
}: AccessTokenParams) {
const now = Math.floor(Date.now() / 1000);
const tokenUrl = `${baseUrl}/oauth/token`;
const clientAssertion = jwt.sign(
{
iss: oauthClientId,
sub: oauthClientId,
aud: tokenUrl,
jti: randomUUID(),
iat: now,
exp: now + 60,
},
oauthPrivateKey,
{ algorithm: "RS256" }
);

const response = await fetch(tokenUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_assertion_type:
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion: clientAssertion,
}),
});

const tokenJson = (await response.json()) as { access_token: string };
return tokenJson.access_token;
}

3. Requesting a Server Access Token

Send the assertion to POST /oauth/token:

POST /oauth/token
{
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": "<your JWT here>"
}

Only those grant_type and client_assertion_type values are supported.

Response:

{ "access_token": "<JWT_ACCESS_TOKEN>", "expires_in": 3600 }

Use this Bearer token on subsequent Connect Server API requests. Expiration is typically 1 hour, but may change without notice.

4. Handling token expiry

When the access token expires or approaches expiry, generate a new JWT client assertion and call /oauth/token again.