Partner OAuth Login

Partner OAuth Login

In addition to email-OTP, Geena supports logging in via a partner OAuth2 identity provider. A partner company’s users click one link on the partner’s site, authenticate at the partner’s IdP, and land in Geena with an active session. Users don’t type a password on Geena, don’t pick a plan, and don’t see any registration form — everything is decided by the partner configuration we set up for you in advance.

Warning

Partner onboarding is manual. Adding, updating, or rotating a partner configuration — OAuth endpoints, client ID, client secret, plan assignment, email-field mapping — is performed by the Geena team via a code-reviewed deploy. Partners cannot self-serve. If you want to enable OAuth login for your users, email us at support@geena.eu with the details listed below under Onboarding.

The user flow

From the end-user’s perspective, there are only two moving parts:

  1. On the partner’s site, the user clicks a button or link pointing at https://api.test.geena.eu/auth/oauth/initiate/<partner-id>.
  2. The browser is redirected to the partner’s IdP, the user logs in there, and the browser returns to Geena — which sets a session cookie and redirects the user to the dashboard landing page (https://app.test.geena.eu/oauth/complete in staging).

From that point, the session cookie (identa_session — legacy name from an earlier iteration of the product) carries the user’s identity on every GraphQL request to https://api.test.geena.eu/graphql, the same as a JWT would for OTP-authenticated users.

Tip

First-time users are registered automatically. The Geena account is created with the plan you (the partner) have been assigned during onboarding, and the account is permanently tagged with your partner ID — we know these users came from you. Returning users simply log in; their existing account is reused.

The one URL you need to give your users

https://api.test.geena.eu/auth/oauth/initiate/<your-partner-id>

<your-partner-id> is the lowercase-hyphen id we pick during onboarding (e.g. acme, partner-beta). That URL is the entire client integration: put it behind any “Sign in to Geena” button on your site, in an email, in a QR code, wherever makes sense. No JavaScript SDK, no secrets in your frontend, no parameters to pass — the button is literally an <a href>.

<a href="https://api.test.geena.eu/auth/oauth/initiate/acme">
  Sign in to Geena
</a>

What Geena needs from your IdP

To onboard your partner integration, the Geena team needs your IdP to meet these requirements:

Requirement Notes
OAuth 2.0 authorization-code flow Standard; supported by all major IdPs (Auth0, Okta, Keycloak, Azure AD, Google, Microsoft, etc.).
PKCE (S256) Mandatory on every request. Handled server-side by Geena — nothing for your IdP to do beyond accepting PKCE parameters.
HTTPS on all three endpoints authorize, token, and userinfo URLs must be https://.
Userinfo returns a stable user ID A field like sub, id, or user_id that doesn’t change across logins for the same user. Tell us which field to read.
Userinfo returns a verified email A field like email_verified (boolean) that’s true when the user’s email has been verified on your side. If your IdP doesn’t expose this, tell us during onboarding and we’ll discuss options (none of them auto-enabled — this is a security control).
Standard client authentication client_secret_post (default) or client_secret_basic. Tell us which one your IdP expects.

Geena holds the OAuth client ID and client secret server-side. You provide them once, and they never appear in any client-facing traffic or browser.

What you need to register on your side

During onboarding we give you the callback URL to register as an authorized redirect URI in your IdP’s OAuth client configuration:

https://api.test.geena.eu/auth/oauth/callback/<your-partner-id>

This URL is unique per partner (the path contains your id, not a query param), and it’s the only Geena-side URL your IdP ever redirects to.

Onboarding

Email support@geena.eu with:

  1. A short partner id you’d like (lowercase letters, digits, hyphens — e.g. acme).
  2. OAuth endpoint URLs for your IdP:
    • Authorization URL (where users get redirected to log in)
    • Token URL (where Geena exchanges the code for an access token)
    • Userinfo URL (where Geena fetches user identity with the access token)
  3. OAuth scopes to request (typically openid email profile, but tell us what your IdP needs).
  4. Client ID for a new OAuth client you register for Geena, with the callback URL above as an authorized redirect URI.
  5. Client secret (sent securely — we’ll set up a delivery channel).
  6. Field mapping in your userinfo response:
    • Which field holds the stable user ID? (e.g. sub)
    • Which field holds the email? (e.g. email)
    • Which field holds the verified-email boolean? (e.g. email_verified)
  7. Client auth methodpost or basic (most IdPs support both; default is post).
  8. Plan — which Geena plan should your users be assigned? We’ll confirm available options during onboarding.

Once we deploy your configuration, the URL …/auth/oauth/initiate/<your-id> starts working immediately.

After login — using the session

Geena delivers the session as a cookie (identa_session), not as a JWT in a response body. That means:

  • The cookie is HttpOnly; Secure; SameSite=Lax — not readable from JavaScript. Your frontend never handles a token directly.
  • To call the GraphQL API from a browser logged in via OAuth, send requests with credentials:
fetch("https://api.test.geena.eu/graphql", {
  method: "POST",
  credentials: "include",                // send the session cookie
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    query: `query { user { status { registered } } }`,
  }),
});
  • Because cookies cross domains only when CORS explicitly allows credentials, the Geena API’s CORS origin list must include your dashboard origin. The Geena team handles this during onboarding.
Info

OAuth-authenticated users share the same session table and the same /auth/renew flow as OTP users. Session lifetime is 72 hours sliding. Existing server-side session revocation (revokeSession, revokeAllSessions) applies to OAuth sessions identically.

What happens on errors

All failure outcomes produce the same response headers (Cache-Control: no-store, Referrer-Policy: no-referrer) so the authorization code never leaks via browser caches or third-party referrers.

Outcome What the user sees What to tell them
Partner id doesn’t exist 404 Not Found from Geena Check the URL’s partner id matches what we configured.
State / cookie mismatch 400 Bad Request Usually means a stale tab or a cross-site cookie problem. Tell the user to open Geena in a fresh tab.
Token exchange failed 502 Bad Gateway Geena couldn’t complete the exchange with your IdP. Check your IdP logs; ping us if unclear.
Email not verified 400 Bad Request Your IdP returned email_verified: false (or omitted the field). The user must verify their email on your side first.
Email conflict 409 Conflict A user already exists in Geena with the same email address but registered via OTP, not via your IdP. This is a security boundary — we don’t silently merge accounts. Contact us to resolve case-by-case.

Security model — for reassurance

  • Geena validates the OAuth response with PKCE S256, a one-shot server-side state value, and a cookie-bound CSRF check.
  • The user identity Geena stores (sub + email) comes directly from your IdP’s userinfo endpoint over TLS — Geena does not accept or read any identity data from the user’s browser.
  • The access token Geena obtains is used once, to fetch userinfo, and is then discarded. Geena does not store or re-use it.
  • Email is immutable on our side after first registration. If your user changes their email at your IdP, their Geena account retains the original email. This is intentional — a compromised IdP cannot rotate the stored email out from under us. Email changes require a support flow.

If any of this needs to differ for your deployment (e.g. your IdP doesn’t emit email_verified and you want to discuss the trust implications of bypassing that check), bring it up during onboarding.

What Geena cannot do

  • Self-service partner configuration. There is no admin panel for you to configure endpoints. All configuration goes through us.
  • Custom post-login redirect per partner. The landing URL after login is the same for all partners (the Geena dashboard). If your users need to return to a specific page on your site, do that redirect from the dashboard.
  • Multi-endpoint userinfo (e.g. GitHub’s /user + /user/emails). The current implementation assumes one userinfo URL. Partners using a provider that splits identity across endpoints need a custom adapter — talk to us.
  • Social-login style “sign in with my existing Geena account via Google” for existing OTP users. A partner-registered account and an OTP-registered account with the same email are deliberately different; we do not auto-merge.

Questions

Email support@geena.eu. Include your partner id in the subject line if you have one.