Skip to content

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.

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.

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 WorkspaceClient and calling current_user.me(). An inactive account is rejected with 403. 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-Auth over Authorization, because its SPCS (Snowpark Container Services) ingress rewrites the Authorization header with a Snowflake-issued OAuth token before forwarding. Pipeline clients send the app token in X-Service-Auth; direct internal callers can still use Authorization.

Use Authorization: Bearer <token> for all three token types. A user token here is a Databricks PAT, introspected against your workspace host.

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.

  1. 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"
    }
  2. Call any protected endpoint with the returned token:

    Terminal window
    curl "$NEXA_API_URL/api/v1/catalogs" \
    -H "Authorization: Bearer $ACCESS_TOKEN"
  3. Refresh before expiry. The JWT is short-lived; re-run step 1 when expires_in elapses. There is no refresh-token flow — request a new token.

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.