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/tokenon 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.