Skip to content

Authentication

SM API supports three authentication paths: Google/Microsoft SSO, magic link, and API key. All portals use the same session cookie on .sprintmode.ai — users authenticated on studios.sprintmode.ai are automatically authenticated on mode.sprintmode.ai.

Auth Methods

1. CF Access (User Session)

Browser users authenticate via Cloudflare Access. After SSO login, CF adds the header cf-access-authenticated-user-email to every request. SM API trusts this header.

2. CF Access (Service Token)

Server-to-server calls (portal workers calling SM API) use CF Access service tokens. Set headers:

CF-Access-Client-Id: <client_id>
CF-Access-Client-Secret: <client_secret>

These are set as environment variables SM_API_CLIENT_ID and SM_API_CLIENT_SECRET on each portal's CF Pages project.

3. API Key

Agents, MCP clients, and form proxies use an API key:

X-SM-Key: <key>
# or
Authorization: Bearer <key>

Routes

GET /auth/sso/google

Initiates Google OAuth2 flow.

Auth: Public
Query params:

ParamTypeDescription
redirectstringURL to redirect to after login. Default: https://clients.sprintmode.ai/client/
productstringProduct tag (e.g. studios, mode). Stored on session.

Behavior: Redirects to Google OAuth2 authorization URL with state containing the redirect URL and product.


GET /auth/sso/google/callback

Google OAuth2 callback. Creates or updates contact, sets JWT session cookie.

Auth: Public
Query params: code, state (set by Google)

Behavior:

  1. Exchanges code for Google user info
  2. Looks up contact by email in CRM
  3. Creates contact if not found (for admin users: auto-creates with investor profile)
  4. Issues JWT session cookie (sm_client) on .sprintmode.ai domain
  5. Redirects to the URL in state.redirect

Cookie set:

sm_client=<jwt>; Domain=.sprintmode.ai; Path=/; HttpOnly; Secure; SameSite=None; Max-Age=604800

JWT payload: { id, email, name, avatar, products[], iat, exp }


GET /auth/sso/microsoft

Initiates Microsoft OAuth2 flow.

Auth: Public
Query params: redirect, product (same as Google SSO)


GET /auth/sso/microsoft/callback

Microsoft OAuth2 callback. Same behavior as Google callback.

Auth: Public


GET /auth/sso/redirect

Cross-domain SSO redirect helper. Used when a product portal on a non-.sprintmode.ai domain (e.g. app.privacyai.com) needs to redirect to SM SSO and return with a valid session.

Auth: Public
Query params:

ParamTypeDescription
redirectstringRequired. Final destination after auth
productstringProduct tag

POST /auth/sso/exchange

Exchange a one-time exchange token (set by /auth/sso/google/callback in a cross-domain flow) for a session cookie on the requesting domain.

Auth: Public
Request body:

json
{ "token": "<exchange_token>" }

Response:

json
{ "ok": true }

Sets sm_client cookie for the requesting origin's domain.


POST /auth/magic-link

Generate and send a magic link to a contact's email.

Auth: API key or CF Access
Request body:

FieldTypeRequiredDescription
emailstringyesContact email to send link to
redirectstringnoURL to redirect to after verification. Default: /client/
productstringnoProduct tag

Response:

json
{ "ok": true }

Sends email via Resend to the contact. Link expires in 1 hour.

Error responses:

  • 404 — Contact not found
  • 400 — Email missing

Verify a magic link token, create session cookie, redirect to destination.

Auth: Public
Path params: token — the magic link token

Behavior:

  1. Looks up token in magic_sessions table
  2. Validates not expired
  3. Marks token as used
  4. Issues JWT session cookie
  5. Redirects to the stored redirect URL

GET /auth/me

Return the currently authenticated user's session data.

Auth: Session cookie or API key
Response:

json
{
  "ok": true,
  "data": {
    "id": "ct_a1b2c3d4",
    "email": "user@example.com",
    "name": "Jane Smith",
    "avatar": "https://...",
    "products": ["studios"],
    "iat": 1715000000,
    "exp": 1715604800
  }
}

POST /auth/logout

Clear the session cookie.

Auth: Any
Response:

json
{ "ok": true }

Sets sm_client cookie with Max-Age=0 to clear it.


GET /auth/logout

Same as POST /auth/logout — GET variant for redirect-based logout flows.


The JWT session cookie sm_client is:

  • Domain: .sprintmode.ai (shared across all SM subdomains)
  • HttpOnly — not readable by JavaScript
  • Secure — HTTPS only
  • SameSite: None — required for cross-site iframe embeds and CF Pages functions
  • Max-Age: 7 days (604800 seconds)

JWT Payload

js
{
  id: "ct_a1b2c3d4",     // CRM contact ID
  email: "...",
  name: "...",
  avatar: "...",          // Google/Microsoft profile photo URL
  products: ["studios"],  // products this contact has access to
  iat: 1715000000,        // issued at (Unix timestamp)
  exp: 1715604800         // expires at (Unix timestamp)
}

Verify the JWT in a CF Worker using the SESSION_SECRET environment variable:

js
import { verify } from 'jsonwebtoken' // or use SubtleCrypto for edge

function getSession(request, env) {
  const cookie = request.headers.get('Cookie') || ''
  const match = cookie.match(/sm_client=([^;]+)/)
  if (!match) return null
  try {
    return verify(match[1], env.SESSION_SECRET)
  } catch {
    return null
  }
}

Sprint Mode LLC — Internal Platform Documentation