Sign-in flows create a session. The Tenant API offers four entry points:

  • signIn — email + password
  • signInIDP — third-party identity provider (see IdP)
  • signInPasswordless — magic link / OTP (see passwordless)
  • createSessionToken — admin impersonation, no credentials required

All of them rely on the same per-IP rate limiting, captcha, and revealUserExists masking described in anti-abuse. All of them are recorded in the audit log. (since 2.2) Sign-in anomaly detection, when enabled, scores only the password signIn path; the IdP and passwordless flows seed its baseline but are not themselves scored.

Password sign-in

mutation {
  signIn(email: "[email protected]", password: "", expiration: 60) {
    ok
    result { token }
    error { code retryAfter }
  }
}
ArgNotes
email, passwordRequired.
expirationMinutes the session token should live. Capped at login.maxTokenExpiration.
otpTokenTOTP code if 2FA is enabled for the person.
options.trustForwardedClientInfo(since 2.2) See proxy trust.

Errors:

CodeCause
UNKNOWN_EMAILNo person with that email. Only returned when login.revealUserExists: true.
INVALID_PASSWORDWrong password. Only returned when login.revealLoginMethod: true (since 2.2).
INVALID_CREDENTIALSWrong email or password. Returned when login.revealUserExists: false (masks the email branch) and/or login.revealLoginMethod: false (masks the password/no-password branch).
PERSON_DISABLEDThe person has been disabled.
EMAIL_NOT_VERIFIED(since 2.2) The account was created while signup.requireEmailVerification was on and has not yet verified its e-mail. Prompt the user to verify, or resend via requestEmailVerification. See e-mail verification.
NO_PASSWORD_SETThe person has no password (IDP-only / passwordless-only). Only returned when login.revealLoginMethod: true (since 2.2); otherwise collapsed into INVALID_CREDENTIALS.
IDP_REQUIRED(since 2.2) The person is linked to an identity provider with disableLocalAuthentication and must sign in through it. Refused before the password is compared. Only returned when both login.revealUserExists and login.revealLoginMethod are true; otherwise collapsed into INVALID_CREDENTIALS.
OTP_REQUIREDThe person has 2FA enabled and otpToken was missing — or (since 2.2) anomaly detection forced a step-up for an unusual sign-in. The step-up case can occur even for an account with no standing 2FA and is indistinguishable from the 2FA case at the API; recover it identically by retrying signIn with otpToken set to the emailed code.
INVALID_OTP_TOKEN2FA token rejected.
RATE_LIMIT_EXCEEDEDPer-IP login rate limit (since 2.2) or per-email exponential backoff hit. retryAfter carries the wait in seconds.

Signing out

signOut invalidates the current session token. To end every session for the caller (e.g. "log out everywhere"):

mutation { signOut(all: true) { ok } }

signOut requires a session token; it does not work with permanent API keys.

When the session was federated via an OIDC provider that supports RP-initiated logout, signOut also returns a logoutUrl (since 2.2). Redirect the browser there to terminate the session at the IdP as well (OIDC Single Logout); it is null for plain/password sessions and for IdPs without an end_session_endpoint, where only a local logout happens. The logoutUrl is only produced when the IdP session was captured at sign-in — i.e. when session re-validation (configuration.revalidation.enabled) is on for that provider; otherwise it is always null even if the IdP has an end_session_endpoint.

mutation { signOut { ok logoutUrl } }

Admin: create session token

A SUPER_ADMIN (or any role with the PERSON_CREATE_SESSION_KEY permission) can mint a session token for any person without credentials. Useful for impersonation and debugging:

mutation {
  createSessionToken(email: "[email protected]", expiration: 120) {
    ok
    result { token }
    error { code }
  }
}

Pass either email or personId. Records a create_session_token audit entry.

Login configuration

All login behavior is controlled by the login section of the tenant configuration:

FieldEffect
revealUserExistsSee anti-abuse — enumeration protection.
revealLoginMethod(since 2.2) When false, NO_PASSWORD_SET / INVALID_PASSWORD / IDP_REQUIRED are collapsed into INVALID_CREDENTIALS and signUp omits the recommendedAction hint on EMAIL_ALREADY_EXISTS. Orthogonal to revealUserExists.
baseBackoff, maxBackoff, attemptWindowPer-email exponential backoff. Also drives the mail-init throttle for password reset and passwordless init.
defaultTokenExpirationLifetime applied when the client omits expiration.
maxTokenExpirationCap on client-requested expiration.
anomalyDetection(since 2.2) Opt-in sign-in anomaly detection for the password path — score thresholds that email the user or force a step-up second factor on an unusual login.

What the session can do

The session token authorizes subsequent Tenant API calls and Content API calls. The session's effective IP and User-Agent — visible in Identity.sessions and in audit-log entries — depend on whether the api_key has trust-forwarded-info.