Summary: Authentication in the 7Mind system uses SuperTokens as the JWT issuer, validated in elixir-backend via JWKS, with Cloudflared providing a separate layer of protection for admin and internal access. Sources: direct code inspection (config/runtime/prod.ex, mix.exs — Joken 2.6 + Joken JWKS 1.7; lib/backend/user_identity/) Last updated: 2026-05-15
Auth layers
The backend uses two independent token validation paths:
1. SuperTokens JWT (mobile and web clients)
SuperTokens acts as the auth server and issues JWTs. The backend validates tokens using JWKS (JSON Web Key Sets) rather than a shared secret, meaning the backend never holds a signing key — it fetches the public key from SuperTokens and verifies signatures against it.
Relevant env vars:
SUPERTOKENS_JWT_ISSUER— expectedissclaim in incoming tokensSUPERTOKENS_JWKS_URL— endpoint the backend fetches public keys from
Library: Joken 2.6 for JWT parsing + Joken JWKS 1.7 for key fetching.
SSO flows (Apple, Google, Facebook sign-in) are handled within the user_identity domain and ultimately produce a SuperTokens session.
2. Cloudflared JWT (internal and admin access)
Admin panel and internal service traffic is protected by Cloudflare Access tunnels. The backend validates the Cloudflare-issued JWT using a separate JWKS endpoint.
Relevant env vars:
CLOUDFLARED_JWT_AUDIENCE— expectedaudclaimCLOUDFLARED_JWKS_URL— Cloudflare’s public key endpoint
This is entirely separate from the SuperTokens path. Cloudflared handles identity at the network layer; SuperTokens handles identity for application users.
User identity domain
The user_identity domain in elixir-backend owns:
- Session creation and validation
- SSO integrations (Apple, Google, Facebook)
- The
Backend.Shared.AuthenticationTokenbehaviour, which allows pluggable auth strategies - Its own Ecto repos (
BACKEND_USER_IDENTITY_IDENTITY_DATABASE_URL,BACKEND_USER_IDENTITY_APIV1_DATABASE_URL)
Two databases exist for this domain — one appears to be a legacy V1 API store and one the current identity store.
What agents should know
- Do not implement custom token signing. All token issuance goes through SuperTokens.
- The JWKS URLs are fetched at runtime, not compiled in. Rotating SuperTokens keys does not require a backend redeploy.
- When adding a new protected endpoint, use the existing auth plugs from
user_identityrather than rolling your own.
From api-contracts
The wire-level contracts capture three distinct auth schemes in contracts/shared/common.tsp, applied via @useAuth decorators:
| TypeSpec model | HTTP shape | Used on |
|---|---|---|
Shared.Common.Requests.SuperTokensAuth | bearer header st-access-token | the deprecated /auth/* routes that proxied directly to SuperTokens (signin, signup, signinup, password reset) and the deprecated Identity /me routes |
Shared.Common.Requests.APIv1Auth | bearer header carrying the legacy v1 auth_token | a small set of legacy endpoints (/monetization/mondia/link_user, /chargebee/self_serve_portal/session) |
Shared.Common.Requests.BackendSessionAuth | cookie backend_session | all of the new /user/* routes, plus /monetization, /content, /practice, /prevention — everything authenticated after the supertokens-auth migration |
Every endpoint under Identity.SuperTokens.SuperTokensOperations and Identity.Identity.IdentityOperations is marked #deprecated "Use Backend.UserIdentity instead". The same is true for the DeprecatedEndpoints interface under SevenMind.User, which mirrors the new endpoints under the old /user_identity/* prefix. Clients should target the new /user/* routes with the cookie-based session.
From 7mind-mobile-apps-monorepo
The Flutter app does not link the SuperTokens SDK directly. supertokens-flutter is not in pubspec.yaml. Instead:
- Users authenticate via SSO (
google_sign_in 6.2.2,sign_in_with_apple 6.1.4,flutter_facebook_auth 7.1.2) or email - Resulting tokens are stored on-device using
flutter_secure_storage 9.2.4 - Requests to the backend attach the token through Dio interceptors in
lib/features/core/network/interceptors/
The exact path by which SSO credentials are exchanged for a SuperTokens session is not yet traced from code inspection. The likely model: the mobile app sends the SSO ID token to the backend, which validates it with the SSO provider and then asks SuperTokens to mint a session. TBD: confirm from lib/features/authentication/ and the backend user_identity SSO modules.
From nuxt-website
The web client uses supertokens-web-js (v0.6) wired into @nuxtjs/auth for the 7mind theme. The flow is the cookie-based BackendSessionAuth variant described above, not bearer-token:
- Login (
POST /user/signin) returns a session cookie that the browser stores host-scoped. Configured redirect target is/login. axios.withCredentials = trueis set globally inplugins/axios-config.jsso every backend call carries the cookie.auth.resetOnError: false— API errors do not clear the auth state, because cookie expiry and invalidation is the backend’s job.plugins/auth.jsaugments$auth.userInfoby JWT-decoding the local token when present and derivingisAppleGeneratedEmailfrom the email suffix.- The 7sleep theme has
auth: false— no auth surface on the 7sleep website. - Identity service domain is configured via
IDENTITY_SERVICE_DOMAIN(id.7mind.deprod,id.6mind.destaging). - For the cookie to flow correctly across
7mind.de/6mind.de/8mind.de/9mindhost families, see multi-domain-hostname-rewriting — the frontend rewrites backend hostnames at request time so the cookie domain matches.
Related
- modulith-domain-model —
user_identityis a domain with its own database isolation - dual-brand-routing — auth is shared across 7Mind and 7Sleep
- elixir-backend — where validation logic lives
- 7mind-mobile-apps-monorepo — the primary mobile client that holds and sends SuperTokens session tokens
- nuxt-website — web client; uses cookie-based SuperTokens sessions
- multi-domain-hostname-rewriting — why cookie auth works across staging/prod/local for the web