Authentication

How parents sign in, how child devices pair, and which credential each part of the API expects.

4 min read

SafeCircle has two kinds of callers, and each has its own credential.

CallerCredentialObtained bySent as
Parent in a browserSession cookieSigning in on the dashboardCookie, automatically with credentials: "include"
Parent in a native appSession tokenSigning in through the APIAuthorization: Bearer <token>
Child deviceDevice tokenPairing with a 6-digit codex-device-token: <token>

Parent authentication is handled by Better Auth at /api/auth/*. The data API then reads the same session.

Parent accounts

Sign-up

Sign-up is open to everyone. New accounts need a verified email, and the SafeCircle team can pause registration at any time.

  • Email verification. Email and password sign-up requires a verified address. The verification link expires after 24 hours, and the user is signed in automatically once they verify.
  • Registration switch. While registration is paused, sign-up (email or social) fails with 400 and the code SIGNUPS_DISABLED, the same answer for registered and unregistered emails. Admins flip the switch in the dashboard.
  • Mobile apps. The Android apps skip the captcha only with a valid Play Integrity attestation. Web sign-up uses Cloudflare Turnstile.

Sign-in methods

MethodNotes
Email and passwordPasswords are checked against known breaches in production. Reset links expire after 1 hour
Social sign-inGoogle, Apple, Discord and X (Twitter), each enabled only when configured
PasskeysWebAuthn, with the relying party name SafeCircle
Authenticator app (2-step verification)TOTP with backup codes. Issuer name SafeCircle

A last-used method is remembered per user, and a user can be signed in on several devices at once.

Bot protection

When Cloudflare Turnstile is configured, the protected requests (such as sign-in and sign-up) must include the challenge result in an x-captcha-response header. The official Android apps satisfy this check through a separate mechanism that is not available to third parties.

Sessions

On the web, the session is a cookie. Its name starts with safecircle, it is shared across *.safecircle.tech, and it is set Secure with SameSite=None so that fetch with credentials works from other SafeCircle subdomains. Your calls must include credentials, and your origin must be on the CORS list.

Native apps use the bearer plugin instead. The sign-in response contains a token, which you send as Authorization: Bearer <token>.

Useful Better Auth routes:

RoutePurpose
POST /api/auth/sign-in/emailSign in. Returns { token, user }
POST /api/auth/sign-up/emailCreate an account. Needs email, password and name
GET /api/auth/get-sessionCurrent session and user, or null
POST /api/auth/sign-outEnd the session
GET /api/auth/list-sessions, POST /api/auth/revoke-sessionSee and sign out your sessions
POST /api/auth/request-password-reset, POST /api/auth/reset-passwordPassword reset
POST /api/auth/two-factor/enable, .../verify-totp, .../disable2-step verification
GET /api/auth/passkey/list-user-passkeys, DELETE /api/auth/passkey/delete-passkeyPasskey management

The full surface, including social sign-in redirects and passkey registration, is documented by Better Auth.

get-session is called on every page load, so it uses the general rate-limit bucket. Other /api/auth/* routes are limited to 30 requests per minute per IP.

Child devices

A child's phone never has a parent account. It pairs once and keeps a device token.

The parent creates a code

A signed-in parent calls devices.createPairingToken for a child. The response is a 6-digit code valid for 5 minutes. Creating a new code invalidates any earlier unused code for that child.

The child app redeems it

The child app calls devices.pair with the code and a device name. This procedure is public. The code is claimed atomically, so it works once.

The device keeps a token

The response contains a random 256-bit deviceToken, a deviceId and the childId. The app stores them and sends the token in x-device-token on every later call.

Revoking

A parent calls devices.revoke. The device record is deleted, so the token stops working immediately.

A device token can create alerts (alerts.create), request a safe-search family link (search.familyLink) and submit feedback (POST /api/feedback). It cannot read any data. It does not expire on its own; revoking it is the only way to end it.

Other credentials

CredentialUsed byNotes
Telegram link codeDashboard and Telegram bot8 characters, valid for 10 minutes, deleted when used. See Telegram bot
Family tokenChild app and SafeCircle SearchSigned with HMAC, bound to a device, valid for 365 days. Once the device is unpaired, the parent's site rules stop applying. See SafeCircle Search
Bot keyTelegram bot to backendServer to server only
Admin roleSafeCircle staffGives access to admin procedures such as the registration switch, which are not documented here