# 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](/connect/guides/api-versioning.md).

## 1. Creating an OAuth Client[​](#1-creating-an-oauth-client "Direct link to 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](https://app.nabla.com/admin/nabla-connect) 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[​](#regularly-rotate-the-oauth-keys "Direct link to 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[​](#2-constructing-a-jwt-client-assertion "Direct link to 2. Constructing a JWT Client Assertion")

The client assertion is a one-time JWT used to authenticate against [`POST /oauth/token`](/connect/reference/oauth-generate-server-access-token.md). Sign it with the private key that corresponds to the OAuth Client.

### JWT header[​](#jwt-header "Direct link to 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[​](#jwt-body "Direct link to 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](https://github.com/auth0), notably [java-jwt](https://github.com/auth0/java-jwt) for Java. See also [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523).

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[​](#3-requesting-a-server-access-token "Direct link to 3. Requesting a Server Access Token")

Send the assertion to [`POST /oauth/token`](/connect/reference/oauth-generate-server-access-token.md):

```
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[​](#4-handling-token-expiry "Direct link to 4. Handling token expiry")

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