Interlaken
Authentication

Users, sessions and second factors

Password sign-in, emailed codes, authenticator apps and remembered browsers.

This is the flow behind the console's sign-in screen. You need it if you are building something that signs a person in directly. If you are writing a service, use API clients instead: they were made for that, and none of the routes on this page will accept a machine credential.

Signing in

curl -sX POST https://api.eu-par-1.interlaken.ai/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","password":"…"}'

The reply is 200 either way, and the body tells you which of two things happened.

Signed in, when the browser is already trusted:

{
  "access_token": "eyJ…",
  "refresh_token": "…",
  "id_token": "eyJ…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "…"
}

A second factor is wanted, otherwise:

{
  "status": "mfa_required",
  "challenge": "ch_…",
  "method": "email",
  "email_hint": "a••@example.com",
  "resend_after_seconds": 30,
  "mail_sent": true
}

Branch on status. A client that assumes the first shape will hand a user an undefined token and no explanation.

method is totp when the account has an authenticator app enrolled, and email otherwise. On the email path, mail_sent: false means the code could not be delivered, from a send cap or a provider failure; show the resend button rather than an error.

Completing the challenge

curl -sX POST https://api.eu-par-1.interlaken.ai/api/v1/auth/mfa/verify \
  -H 'Content-Type: application/json' \
  -d '{"challenge":"ch_…","code":"482913","remember_device":true}'

code is whichever of three things the user has: the emailed code, the current code from their authenticator app, or a recovery code, which is recognisable by its rc-xxxxx-xxxxx shape.

Success returns the same token body as a clean sign-in. Failure is specific, and the distinction matters because each one asks for different words on screen:

StatuserrorWhat to say
401invalid_codeWrong code. The body's attempts_left says how many tries remain.
429retry_laterToo many attempts. retry_after_seconds says how long.
410challenge_expiredThis sign-in attempt timed out. Start again from the password.
503secret_encryption_not_configuredAuthenticator codes are unavailable in this deployment.

POST /api/v1/auth/mfa/resend mails a fresh code, and only applies to the email method. Respect resend_after_seconds.

Remembered browsers

Passing remember_device: true sets a cookie called interlaken_device, good for 30 days, after which that browser skips the second factor. The value is opaque and the platform stores only its hash.

The cookie's domain is the parent domain every availability zone shares, so a browser trusted in one zone is trusted in the others without signing in again. It is Secure, HttpOnly and SameSite=None, which means a browser client must send credentials on cross-origin requests for any of this to work.

GET /api/v1/auth/security lists the remembered browsers alongside the account's other security state, and marks which entry is the browser asking. Removing one is DELETE /api/v1/auth/devices/{id}; removing all of them is DELETE /api/v1/auth/devices.

Authenticator apps

POST /api/v1/auth/totp/setup     → { "secret": "…", "otpauth_url": "otpauth://…" }
POST /api/v1/auth/totp/confirm   → { "recovery_codes": ["rc-…", …] }

Render otpauth_url as a QR code, take one code back to prove the app works, and show the recovery codes once. They are not retrievable later. POST /api/v1/auth/totp/recovery-codes replaces them and DELETE /api/v1/auth/totp turns the app off; both ask for the password again.

Seeds are sealed at rest. In a deployment with no encryption key configured, enrolment fails closed rather than storing a seed in the clear.

Keeping and ending a session

POST /api/v1/auth/token            refresh, with the refresh token
POST /api/v1/auth/logout           revoke this access token, and the refresh token if sent
POST /api/v1/auth/sessions/revoke-all  end every session this user has anywhere

Revocation is checked on every request in every zone, so signing out everywhere is effective immediately rather than eventually.

Account upkeep

change-password, forgot-password and reset-password behave as their names suggest. send-verify-email and verify-email confirm an address. PUT /api/v1/auth/locale sets the language the platform writes mail in, and it follows the account across zones, so a choice made once holds everywhere.

On this page