Authentication

API authentication, session lifecycle, and security best practices

Authentication API

Cliqer authenticates with an httpOnly session cookie (session_token), minted by POST /api/auth/login. Browsers send it automatically on every request; server-to-server tooling keeps it in a cookie jar. Studio and Enterprise teams can additionally mint API keys for server-to-server access, sent as Authorization: Bearer cliqer_<key>, see API Key Authentication below.

Session Model

CredentialWhere it livesHow it is obtained
Session cookie (session_token)httpOnly, Secure cookie on your Cliqer hostSet by POST /api/auth/login, rotated automatically by the server

The cookie is HttpOnly, so it is not readable from JavaScript. Its lifetime follows the server session TTL and is renewed transparently whenever you call GET /api/auth/me. There is no separate refresh endpoint to call, keeping a long-lived client polite means calling GET /api/auth/me periodically.

Session Lifecycle

Using the Session

Browsers attach the cookie automatically. For server-to-server clients, persist the cookie the login response sets and send it on subsequent requests:

# Save the session cookie on login, then reuse it
curl -X POST "$BASE_URL/api/auth/login" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"email":"user@example.com","password":"your_password"}'

curl -X GET "$BASE_URL/api/auth/me" -b cookies.txt

API Key Authentication

Studio and Enterprise teams can mint long-lived API keys for server-to-server access, an alternative to holding a user's login credentials. Create and revoke them in the dashboard under Team → API keys (/dash/team/api-keys); minting requires the team owner (or a custom role granted the API-keys permission). Key management is available on the Studio and Enterprise plans only.

A key is shown once at creation, in the form cliqer_<prefix>_<secret>. Store it securely: it cannot be recovered, so revoke and re-create if it is lost. Send it as a Bearer token on any endpoint that accepts a session:

curl -X GET "$BASE_URL/api/licenses/status?license_key=YOUR_LICENSE_KEY" \
  -H "Authorization: Bearer cliqer_ab12cd34_your_secret_here"

The key authenticates as the user who created it, scoped to that user's team and plan. A revoked or unknown key returns 401, exactly like a missing session. Admin-only endpoints always reject API keys with 403. Keys are subject to the same rate limits as session requests.

Treat an API key like a password. Anyone holding it can act as your account on documented endpoints until you revoke it.

Log In

Exchange user credentials for a session. On success the response sets the session_token cookie.

Endpoint: POST /api/auth/login

ParameterTypeRequiredDescription
emailstringYesUser email (a WordPress username is also accepted)
passwordstringYesUser password
otpstringNoTOTP code, when the account uses an authenticator app
email_otpstringNoEmailed PIN, when the account uses email 2FA
request_email_otpbooleanNoAsk the server to send an email PIN (for both method)
curl -X POST "$BASE_URL/api/auth/login" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{"email":"user@example.com","password":"your_password"}'

Response (success): sets the session_token cookie and returns the session metadata.

{
  "data": {
    "expires": 604800000
  }
}

Response (2FA required): a 200 control-flow signal, not an error. Resubmit POST /api/auth/login with the same credentials plus otp (authenticator) or email_otp (emailed PIN).

{
  "requires_otp": true,
  "method": "totp"
}

method is one of totp, email, or both. For email/both the server emails a PIN (set request_email_otp: true to trigger it on the both method).

Invalid credentials return 401, as does a wrong or expired TOTP code. A wrong or expired emailed PIN returns 400 with a message asking for a new one.

Session Rotation

There is no separate refresh endpoint. The server rotates the session_token cookie for you: when a session is close enough to expiry, GET /api/auth/me responds with a fresh Set-Cookie alongside the profile. A client that keeps a cookie jar and calls GET /api/auth/me periodically stays signed in indefinitely with no extra work.


Current User

Return the authenticated user's profile, or { "data": null } when there is no valid session (anonymous-friendly, never a 401).

Endpoint: GET /api/auth/me

curl -X GET "$BASE_URL/api/auth/me" -b cookies.txt

Response:

{
  "data": {
    "id": "uuid",
    "email": "user@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "role": "uuid",
    "tfa_method": "none",
    "is_admin": false,
    "biometric_unlocked": false
  }
}

Log Out

Terminate the session for the current cookie and clear it from the browser.

Endpoint: POST /api/auth/logout

curl -X POST "$BASE_URL/api/auth/logout" -b cookies.txt -c cookies.txt

Response:

{
  "success": true
}

Security Best Practices

Recommended Security Measures
  1. Use HTTPS only - The session cookie is Secure; all requests must use TLS 1.2+.
  2. Never read the cookie from JavaScript - It is HttpOnly by design; keep it that way.
  3. Refresh proactively - Call GET /api/auth/me before the session expires on long-lived tabs; the server rotates the cookie for you.
  4. Log out to revoke - POST /api/auth/logout terminates the session server-side immediately.
  5. Store credentials, not sessions - Server-to-server integrations should hold the login credentials in a secret manager and re-establish a session, never persist the cookie in source.
See Security Overview for enterprise security features.