Authentication
Every Nexa API request carries a bearer token in the Authorization header. The services
accept three kinds of token, checked in order, so the same header works whether the caller is
another Nexa service, a registered API client, or a human using their data-platform credentials.
This page describes the real scheme enforced by the authentication middleware and shows an
authenticated request you can copy.
The bearer scheme
Section titled “The bearer scheme”Send the token as a standard Authorization: Bearer <token> header. The middleware splits the
header, requires the scheme to be bearer (case-insensitive), and rejects anything else with
401. There is no session, cookie, or API-key-in-query support.
Authorization: Bearer <token>A handful of paths are public (no token required) so that health probes and token exchange
can work: /health, /info, and the token endpoint /api/v1/auth/token. The interactive docs
(/docs, /redoc, /openapi.json) are open in non-production so you can fetch a token and then
click Authorize; they are locked down in production.
The three token types
Section titled “The three token types”When a request arrives, each service tries these in sequence and uses the first that validates:
| # | Token type | How it is minted | Identity it maps to |
|---|---|---|---|
| 1 | Service token service-to-service | Static shared secret (NEXA_SERVICE_AUTH_TOKEN), compared with constant-time equality; a previous value is also accepted during rotation |
internal-service, role admin |
| 2 | Nexa client JWT API clients | Signed by the service (HS256) and returned from POST /api/v1/auth/token in exchange for client credentials |
The client sub from the JWT |
| 3 | Data-platform user token humans | Your Databricks personal access token (PAT); validated by calling the workspace’s current-user endpoint | Your workspace username |
Notes that matter in practice:
- User tokens are introspected live. The Databricks and Agents services validate a user token
by constructing a
WorkspaceClientand callingcurrent_user.me(). An inactive account is rejected with403. Successful validations are cached in-memory for 5 minutes (keyed by an HMAC of the token, never the raw token), so repeated calls don’t hammer the workspace. - Snowflake reads a different header first. The Snowflake service prefers
X-Service-AuthoverAuthorization, because its SPCS (Snowpark Container Services) ingress rewrites theAuthorizationheader with a Snowflake-issued OAuth token before forwarding. Pipeline clients send the app token inX-Service-Auth; direct internal callers can still useAuthorization.
Use Authorization: Bearer <token> for all three token types. A user token here is a
Databricks PAT, introspected against your workspace host.
Send the Nexa app token in X-Service-Auth: Bearer <token> when calling through the public
SPCS endpoint; Authorization may be overwritten by ingress. Internal (non-ingress) callers
may use Authorization.
Getting a client token
Section titled “Getting a client token”Registered API clients exchange a client ID and secret for a short-lived Nexa JWT. The credentials
are provisioned in your deployment configuration (NEXA_CLIENT_ID / NEXA_CLIENT_SECRET); the
issued token’s lifetime is set by the service.
-
Request a token by posting your credentials to the token endpoint. This path is public.
Terminal window curl -X POST "$NEXA_API_URL/api/v1/auth/token" \-H "Content-Type: application/json" \-d '{"client_id": "'"$NEXA_CLIENT_ID"'", "client_secret": "'"$NEXA_CLIENT_SECRET"'"}'The response contains the token and its lifetime:
{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","token_type": "Bearer","expires_in": 3600,"workspace": "nexa-api"} -
Call any protected endpoint with the returned token:
Terminal window curl "$NEXA_API_URL/api/v1/catalogs" \-H "Authorization: Bearer $ACCESS_TOKEN" -
Refresh before expiry. The JWT is short-lived; re-run step 1 when
expires_inelapses. There is no refresh-token flow — request a new token.
Response codes for auth failures
Section titled “Response codes for auth failures”| Status | Meaning |
|---|---|
401 Unauthorized |
Missing header, wrong scheme, or an invalid/expired token |
403 Forbidden |
Valid token but the user account is inactive |
503 Service Unavailable |
The auth system itself is misconfigured or the upstream workspace is unreachable |
For the environment concept these tokens operate within, see Core Concepts. To skip token handling entirely, use the Nexa CLI, which injects the bearer header for you.