What it does
Privacy spec §3 (spec), no flag:
- P-Entrar (
/sign-in): Continue with passkey (the white pill), Continue with Apple and Continue with Google when the server has their credentials, then Use email and password, which opens the email form (/sign-in-email). On iOS Google shows only beside Apple (App Store guideline 4.8); Apple shows only on iOS. A device without passkeys makes the email link the white pill. Sign-up keeps Apple, Google and email. - P-Seguranca (
/security, from P-Central and Account): passkeys by name, two-step verification, Apple and Google (the linked accounts,/linked-accounts), signed-in devices with the last new device or country, the new sign-in alert switch, this device's Face ID lock (iOS) and Hide amounts in the app switcher, and for the household's owners and admins the 2FA requirement for sharing.
New sign-in alerts
Better Auth's session.create hook records each User's device (deviceLabel: browser and system, e.g. "Safari · macOS", or "iOS"/"Android" for the app) and country (cf-ipcountry, on Workers only) in sign_in_device, one row per pair. A new pair after the first sends the alert email in the account's language (@autofolio/email/sign-in-alert): device, country, time, and where to sign that device out. The first sign-in never alerts, and accountPreference.signInAlerts (on by default) turns the email off. No IP address or city is stored or sent.
The 2FA requirement
organization.require_second_factor, off by default, is switched by owners and admins with security.setRequirement (audited as org.second_factor_changed, metadata secondFactor). While it is on, requireSecondFactorToShare (platform/rpc/require-second-factor.ts) answers SECOND_FACTOR_REQUIRED to a User with neither two-step verification nor a passkey on passport.create, showcase.create, inviteLink.create and vehicleMember.set when it grants a car (taking access back is never blocked). The app's error toast for that code opens Security; P-Seguranca shows a notice while the User lacks both. A solo User is never asked unless they turn it on.
App switcher cover
A device setting like the Face ID lock (app-lock.switcher.ts, SecureStore): while it is on, SwitcherCover covers the app whenever it is not active, so the iOS switcher's snapshot shows no amounts. Off by default; not offered on web.
Apple and Google setup
The buttons stay hidden until the server has credentials: appConfig.get returns socialProviders, the providers whose id and secret are both set (packages/auth/src/social-providers.ts). Per environment (local, preview, production), set these as Worker secrets or in apps/web/.env:
| Variable | Value |
|---|---|
GOOGLE_CLIENT_ID | OAuth client of type Web application (Google Cloud console → Credentials) |
GOOGLE_CLIENT_SECRET | That client's secret |
APPLE_CLIENT_ID | The Services ID (e.g. io.zietec.autofolio.signin) |
APPLE_CLIENT_SECRET | The client secret JWT signed with the Sign in with Apple key (.p8); it expires within six months |
APPLE_APP_BUNDLE_IDENTIFIER | The iOS bundle id (io.zietec.autofolio), so a native Apple ID token is accepted |
Redirect URIs to register, one per origin the server answers on (BETTER_AUTH_URL):
- Google, Authorized redirect URIs:
https://<origin>/api/auth/callback/google(andhttp://localhost:3005/api/auth/callback/googlefor local). - Apple, the Services ID's Return URLs:
https://<origin>/api/auth/callback/apple; its Domains list the origin's host. Apple refuseslocalhost: test it on a preview or a tunnel.
The app needs nothing per provider: Better Auth's Expo plugin opens the provider in an auth session and returns to the app scheme (NATIVE_APP_SCHEME, trusted through nativeTrustedOrigins). Apple posts back from https://appleid.apple.com, which social-providers.ts adds to the trusted origins. An Apple or Google sign-in with an email that already has an account links to it when the provider vouches for the email (account.accountLinking, no trusted providers); a User links or unlinks one later from Security → Apple and Google, and can never unlink the last way to sign in.
Procedures
| Procedure | Who | What |
|---|---|---|
security.overview | Member | Signed-in devices, the last new device (country named in locale), the requirement, whether the User holds a passkey, whether they manage the household |
security.setRequirement | Owner or admin, audited | Turns the household's 2FA requirement on or off |
Key files
packages/api/src/features/security/andpackages/api/src/platform/rpc/require-second-factor.tspackages/auth/src/sign-in-device.ts,packages/email/src/sign-in-alert.ts,packages/db/src/schema/security.tsapps/mobile/src/features/auth/auth.entry.screen.tsx,apps/mobile/src/features/settings/settings.security.screen.tsx,apps/mobile/src/features/settings/settings.linked-accounts.screen.tsx,apps/mobile/src/features/app-lock/app-lock.switcher-cover.tsx