Skip to content

Authentication

Cortex uses OAuth2. Every API call carries a bearer JWT, which each service validates as a resource server. The token also carries the permissions that decide what the call may do.

Get a token (service integrations)

A backend integration authenticates with the client_credentials grant, using a registered service client:

TOKEN=$(curl -su "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials \
  https://auth.cortexbanking.com/oauth2/token | jq -r .access_token)
  • The token endpoint is /oauth2/token on the identity host (auth.cortexbanking.com).
  • Tokens are short-lived. Fetch a fresh one when it expires rather than caching across runs.
  • The JSON Web Key Set is published at /oauth2/jwks; services validate signatures against it.

The interactive admin console uses a different, browser-based flow (authorization code with PKCE). You do not need that for a server-to-server integration.

What the token carries

Cortex puts a few custom claims on the token, alongside the standard sub / iss / aud / exp:

Claim Meaning
tenant Your institution. Binds every read and write to your data, security-critical.
permissions An array of domain:action strings, exactly what this identity may do.
roles Maker-checker tier(s) (T1, T2, T3) used by the approvals system.
branch The branch scope, or ALL for head-office identities.

Permissions map straight to authorities on the backend. A call to an operation whose required permission you do not hold returns 403. The API reference names the required permission on each operation (for example payment:dispatch, journal:post, account:maintain).

Provisioning a client

Service clients are provisioned by an administrator (Access & Security → API clients). A client is granted a set of permissions; keep that set as small as the integration needs. The token can never do more than its permissions allow, so least privilege here is your main lever.

In production

In a production deployment an external identity provider (Keycloak, Auth0, Entra, Ping) can replace the built-in authorization server. It must emit the same claims (tenant, permissions, roles, branch) because those are what the platform enforces on. Nothing else about your integration changes.

The OpenAPI file does not declare the security scheme

openapi.json ships with no securitySchemes block, so generated clients will not add the bearer header for you. Send Authorization: Bearer $TOKEN on every request yourself.