Authentication
Authentication
Geena uses email-OTP login backed by Ed25519-signed JWTs with server-side session revocation. No passwords, no third-party identity provider.
Info
If your users authenticate through a partner company’s identity provider (SSO-style), see Partner OAuth Login instead — it describes the one-click OAuth2 flow for partner-managed users. The OTP flow below is for users who log in directly to Geena with an email address.
The flow
- Client calls
POST /auth/send-otpwith an email address. A 6-digit code is emailed to the user. - Client calls
POST /auth/verify-otpwith the email + code. The server returns{ token, expiresAt, isNewUser }. - If
isNewUser: true, the client calls the GraphQLuser.registermutation to materialise the user row. Otherwise skip. - Client stores the token and sends
Authorization: Bearer <token>on every subsequent request. - Before expiry, client calls
POST /auth/renewto slide the session forward by another 72 hours and receive a fresh JWT.
Info
Sessions are 72 hours (3 days) sliding. OTP codes expire after 15 minutes. Max 3 OTP sends per email per hour; max 5 verification attempts per code.
POST /auth/send-otp
Public. Sends a one-time code to the given email.
Response — always 200 { "success": true }, regardless of whether the
account exists. This prevents account enumeration.
Errors
400— invalid email format429— rate limit exceeded (more than 3 sends in the last hour)503— email service unavailable
POST /auth/verify-otp
Public. Exchanges the OTP code for a JWT and creates a session row.
Response
Errors
400— missing email or code401— invalid or expired code429— too many verification attempts
Tip
If isNewUser: true, your next call must be
mutation { user { register(input: {}) { userId } } } — without it the JWT
is valid but there’s no user row for the KMS to operate on.
POST /auth/renew
Authenticated. Extends the current session by 72 hours and issues a new JWT with the refreshed expiry.
Response
Secondary email verification
Some organization flows require the user to prove control of an email other than the one they logged in with (e.g. domain verification).
POST /auth/verify-email/send
Authenticated. Sends an OTP to the secondary email (re-uses the same OTP infrastructure; same rate limits apply).
POST /auth/verify-email/confirm
Authenticated. Verifies the OTP and attaches the newly verified email to the current session.
Response — { "verified": true }.
Session revocation
Sessions can be revoked server-side via the user.security mutations
(revokeSession, revokeAllSessions, revokeAllSessionsIncludingCurrent).
A revoked session’s JWT will fail auth verification on the next request.