Sessions for user-facing apps
If your app authenticates end users with their Cortex credentials, use this endpoint to exchange an API key plus user credentials for a short-lived user JWT.
When you need this
Most integrations don't need sessions. If your service talks to Cortex on its own behalf — a background job, a server-side data pipeline, an automation — use the API key directly as described in Authentication. Every request runs as the API key's identity, and that is the right model for machine-to-machine work.
Sessions exist for a narrower case: you are building a user-facing application where your end users sign in with their own Cortex credentials, and each request needs to be made as that user rather than as your service account. Examples include a customer-built portal, a custom chat UI, or an internal tool that authorizes against Cortex user identities.
Same-organization scope
An API key authenticates users in the same organization that the key belongs to. If your organization is acme and you call /v1/auth/sessions with a user whose account lives in a different organization, the request returns 401 — the same response shape as bad credentials, with no information leak about whether the account exists elsewhere.
Cross-organization authentication (one credential minting JWTs for users in any organization) is reserved for Cortex-operated sign-in portals and is not part of the public developer surface. Within your own organization there is nothing extra to configure — any API key works.
Request
Send the user's email and password as a JSON body, authenticated with your API key:
curl https://api.cortex.cognit-dx.com/v1/auth/sessions \
-X POST \
-H "Authorization: Bearer $CORTEX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "alice@acme.example",
"password": "..."
}'The calling credential must be an API key. A request that presents a JWT in the Authorization header is rejected — JWTs cannot mint new JWTs.
Response
On success, the response is a flat object with the minted token and its expiration:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2026-05-17T15:32:11.123Z"
}The token is a JWT with an 8-hour lifetime. Treat the token as an opaque string — do not parse it, do not decode the payload, do not rely on its internal structure. The exact format is an implementation detail.
Use expires_at to know when to refresh. Shortly before it expires, exchange the current token for a fresh one with POST /v1/auth/sessions/renew — send the API key in the Authorization header and the current token in the body. No password is required, so you can keep users signed in silently. A token left idle past the 7-day renew window must mint a fresh session with credentials again.
Use the JWT
Send the JWT in the Authorization header on any downstream call. The request runs as the user the JWT was minted for.
curl https://api.cortex.cognit-dx.com/v1/threads \
-H "Authorization: Bearer $CORTEX_TOKEN"After 8 hours the JWT expires and the next request returns 401. Refresh silently with POST /v1/auth/sessions/renew (no credentials needed); only once a token is idle past the 7-day renew window do you re-mint with POST /v1/auth/sessions and the user's credentials.
Errors
| Status | Code | When |
|---|---|---|
401 | api_key_required | The calling credential is a JWT, not an API key. Only API keys can mint sessions. |
401 | invalid_credentials | The email or password is wrong, or the user belongs to a different organization than the API key. The two cases return the same response. |
400 | invalid_request | The request body is missing required fields or has the wrong shape. |
Chain of trust
Every minted JWT references the API key that minted it. If that API key is later revoked, every JWT derived from it stops working immediately — there is no independent validity window. Revoking a leaked API key is therefore enough to terminate every active user session it produced, without needing to track or invalidate JWTs individually.