Skip to main content

Authentication

Most Haltless API endpoints authenticate with a bearer JWT access token. Telemetry ingestion authenticates with an API key instead. See Sensor Data and the API Keys guide.

Send the access token on every authenticated request:

Authorization: Bearer <jwt>

Access tokens last 30 minutes. A refresh token, valid for 7 days, is returned as a secure, httpOnly cookie by /api/v1/auth/login and is used by /api/v1/auth/refresh to mint a new access token. Each refresh replaces the cookie, and the old one stops working.

Endpoints​

MethodPathDescription
POST/api/v1/auth/loginExchange email and password for an access token
POST/api/v1/auth/refreshGet a fresh access token from the refresh cookie
GET/api/v1/auth/meReturn the authenticated user's profile
POST/api/v1/auth/logoutRevoke the current session
POST/api/v1/auth/mfa/verifyComplete an MFA challenge for a full token
POST/api/v1/auth/forgot-passwordEmail a password-reset link
POST/api/v1/auth/reset-passwordSet a new password from a reset token
GET/api/v1/auth/sso/checkCheck whether an email domain uses SSO
POST/api/v1/auth/sso/exchangeExchange an SSO code for tokens

Log in​

POST /api/v1/auth/login

Request body

{
"email": "user@example.com",
"password": "<password>",
"tenant_id": null
}

tenant_id is optional. Send it only when a previous response asked you to choose an organization (see below).

Response: 200 OK

{
"access_token": "<jwt>",
"token_type": "bearer",
"mfa_required": false,
"tenant_choice_required": false,
"tenants": [],
"password_expired": false
}
FieldDescription
mfa_requiredtrue when the account has multi-factor authentication enabled. access_token is then a pending token, valid for 5 minutes and only for completing the challenge
tenant_choice_requiredtrue when the email and password match accounts in more than one organization. access_token is then empty and tenants lists the organizations (tenant_id, name); repeat the request with the chosen tenant_id
password_expiredtrue when the password is over 90 days old. Until it is changed, requests other than changing it return 403

Errors

StatusMeaning
401Wrong email or password
403The email address has not been verified yet
423The company's account is suspended
429Too many failed attempts: 10 failures within 10 minutes lock the account for 15 minutes

Refresh an access token​

POST /api/v1/auth/refresh

Sends the httpOnly refresh cookie set at login; no request body is required.

Response: 200 OK

{
"access_token": "<jwt>",
"token_type": "bearer"
}

Complete an MFA challenge​

POST /api/v1/auth/mfa/verify

Request body

{
"mfa_token": "<pending-token>",
"code": "123456"
}

The code accepts a six-digit time-based one-time code or a single-use recovery code.

Response: 200 OK

{
"access_token": "<jwt>",
"token_type": "bearer"
}

Get the current user​

GET /api/v1/auth/me

Requires a bearer JWT. Returns the authenticated user's profile.

Response: 200 OK

{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"email": "user@example.com",
"full_name": "Jordan Rivera",
"role": "operator",
"mfa_enabled": true,
"timezone": "UTC",
"locale": "en",
"last_login_at": "2026-08-07T09:12:00Z"
}

Log out​

POST /api/v1/auth/logout

Requires a bearer JWT. Revokes the current access and refresh tokens and clears the refresh cookie. Returns 204 No Content.

Password reset​

POST /api/v1/auth/forgot-password emails a time-limited reset link to the address if it matches a user. It always returns 204 No Content, so it never reveals whether an email is registered.

{
"email": "user@example.com"
}

POST /api/v1/auth/reset-password consumes the emailed token and sets a new password:

{
"token": "<reset-token>",
"new_password": "<new-password>"
}

Returns 204 No Content on success.

Single sign-on​

If your organization uses SSO, check a login email's domain before showing a password field:

GET /api/v1/auth/sso/check?email=user@example.com

Response: 200 OK

{
"has_sso": true,
"provider_name": "Example IdP",
"redirect_url": "https://idp.example.com/authorize?..."
}

Redirect the user to redirect_url. After the identity provider authenticates the user, your login page receives a short-lived code that you exchange for tokens:

POST /api/v1/auth/sso/exchange

{
"code": "<sso-code>"
}

Response: 200 OK

{
"access_token": "<jwt>",
"token_type": "bearer"
}

See the Authentication getting-started guide for a full walkthrough.