Authentication

The Hubrix API uses short-lived JWT access tokens (15 minutes) carried as Authorization: Bearer <token>. Tokens are obtained via one of three flows: email/password, Google SSO, or Microsoft SSO.

Email / password

Call POST /auth/login with your credentials. On success you receive:

{
  "access_token":  "eyJhbGc...",   // JWT, valid 15 minutes
  "refresh_token": "abc123...",    // 32-byte random, valid 30 days
  "user": { "id": "uuid", "email": "you@example.com", "role": "owner" }
}

If MFA is enabled, include totp_code in the same request body. An omitted TOTP code returns 401 mfa_required.

# cURL
curl -X POST https://api.hubrix.ai/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "YOUR_PASSWORD", "totp_code": "123456"}'

Token refresh

Before the access token expires, call POST /auth/refresh. Each call rotates the refresh token — the previous one is immediately invalidated. A race between two concurrent refreshes will cause one to fail with 401 token_invalid; the client should retry with the newer token.

curl -X POST https://api.hubrix.ai/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "abc123..."}'

Google SSO

  1. Redirect the user to GET /auth/google/start. This stores a CSRF nonce in Redis (300s TTL) and returns a redirect to the Google consent screen with scopes openid email.
  2. Google redirects to GET /auth/google/callback?code=…&state=…. The API validates the state, exchanges the code, and either logs in an existing user or creates a new one (if a valid invite exists).
  3. The callback sets hubrix_token as an httpOnly cookie and redirects to /app. For programmatic use, call GET /auth/google/start?redirect_uri=YOUR_URI (when implemented).

Microsoft SSO

Same flow via /auth/microsoft/start and /auth/microsoft/callback. Uses MSAL with User.Read openid scopes and microsoft_tenant_id=common for multi-tenant accounts.

MFA (TOTP)

Users enable TOTP from POST /me/mfa/setup (returns QR code URI) then confirm with POST /me/mfa/verify. The secret is Fernet-encrypted at rest. Once enabled, every login requires a TOTP code. Recovery codes (8 generated at setup, stored as hashed values) can substitute for a TOTP code.

Step-up authentication

Sensitive operations (disabling MFA, changing email, requesting account deletion) require re-authentication within the last 5 minutes. These endpoints return 403 with type: step_up_required if the session is older. Call POST /auth/step-up with your password (and TOTP if enabled) to refresh the step-up claim.

API keys

Create API keys from Settings → API Keys. Keys have the format hbx_…. The plaintext key is shown exactly once at creation — only the SHA-256 hash is stored. Keys authenticate as the company without user context; role is effectively admin.

curl https://api.hubrix.ai/v1/me/profile \
  -H "Authorization: Bearer hbx_your_api_key_here"

Personal API tokens (user-scoped, with fine-grained permissions) are planned for a future release. Current API keys authenticate at company level.

JWT structure

Access tokens are HS256 JWTs. Decode the payload to inspect claims — do not rely on them for authorization (the server validates the signature on every request):

{
  "sub": "user-uuid",      // user_id
  "cid": "company-uuid",   // company_id
  "role": "owner",         // owner | admin | member
  "exp": 1746376800        // Unix epoch — 15 min from issue time
}

The SECRET_KEY used to sign tokens is never exposed. Do not attempt to verify tokens client-side — treat them as opaque.

Logout

Call POST /auth/logout to revoke the current refresh token server-side and clear the httpOnly session cookie. All other active sessions remain valid until their access tokens expire. To revoke all sessions, call POST /me/sessions/revoke-all.