Internal Docs
Sign In with Apple Setup
The feature flags panel is protected by Sign In with Apple. Only you (the admin) can authenticate. This page explains how the auth flow works and how to configure it.
Official Apple Developer Documentation:
How it works
Client requests Sign In with Apple
On iOS, ASAuthorizationAppleIDProvider presents the native sheet. On web, Apple's JS SDK opens a popup. Either way, Apple returns a short-lived identity token (JWT, valid 5 min).
Client sends token to POST /auth/apple
The Apple identity token is sent as Authorization: Bearer <token>.
Server verifies the Apple JWT
Apple's public keys are fetched from https://appleid.apple.com/auth/keys and cached for one hour. The server verifies the signature, checks the token hasn't expired, and confirms the audience is your iOS bundle ID or web Service ID.
Server checks admin identity
The token's sub claim (your permanent Apple user ID) is compared to the ADMIN_APPLE_USER_ID environment variable. If they don't match, the request is rejected with 401.
Server issues a 7-day session JWT
Signed with HMAC-SHA256 using SESSION_SECRET. The client stores this in the Keychain (iOS) or sessionStorage (web) and attaches it as a Bearer token to all subsequent /api/flags requests.
Environment variables
See server/.env.example for a copy-paste template.
SESSION_SECRET
Required in production
HMAC-SHA256 key used to sign and verify session JWTs. Generate with:
openssl rand -hex 32
Defaults to an insecure dev string if unset. Always set this in production.
ADMIN_APPLE_USER_ID
Required
Your permanent Apple user ID. To discover it:
- Start the server without this variable set.
- Attempt to sign in from the iOS app or web panel.
- The server logs:
ADMIN_APPLE_USER_ID is not set. Attempting user sub: 000000.abc123… - Copy that value and set the env var, then restart.
APPLE_IOS_BUNDLE_ID
Optional
iOS app bundle ID used for audience validation. Defaults to julio.fruta.
APPLE_SERVICE_ID
Optional — web only
Apple Service ID for Sign In with Apple on the browser. Leave blank to disable web sign-in. See the web setup section below for how to create one.
API reference
/auth/apple
Exchange an Apple identity token for a server session token.
Request
Authorization: Bearer <apple-identity-token>
Response 200
{ "sessionToken": "<server-jwt>" }
Errors
401 — missing token, invalid signature, expired, wrong audience, or not the admin user.
503 — ADMIN_APPLE_USER_ID not configured (logs the sub to help you set it).
/api/flags
Return all feature flags. Requires a valid session token.
Request
Authorization: Bearer <session-token>
Response 200
[{ "key": "immersive_mode", "isEnabled": true, "description": "…" }]
/api/flags
Create or update a feature flag. Requires a valid session token.
Request
Authorization: Bearer <session-token>
Content-Type: application/json
{ "key": "my_flag", "isEnabled": true }
Web Sign In — Apple Service ID setup
-
1
Create a Service ID
In Apple Developer → Identifiers, click + and select Services IDs. Use an identifier like
dev.julio.featureflags.web. -
2
Enable Sign In with Apple
Enable the capability, click Configure, select your App ID (
julio.fruta) as the primary, add your domain, and set the redirect URI tohttps://<your-domain>/feature-flags.html. -
3
Update config in two places
Set the env var on the server:
APPLE_SERVICE_ID=dev.julio.featureflags.web
And update the constant in
frontend/feature-flags/feature-flags.html:const APPLE_SERVICE_ID = 'dev.julio.featureflags.web';
iOS — enabling Sign In with Apple
Open Julio.xcodeproj in Xcode, select the Julio target → Signing & Capabilities, and add the Sign In with Apple capability if it isn't there yet.
The Feature Flags tab in the app shows a "Sign in with Apple" button when unauthenticated. On success, the session token is stored in the Keychain and persists across launches.
To sign out, tap Sign Out in the toolbar — this deletes the Keychain entry.
Token storage summary
iOS
Session JWT stored in kSecClassGenericPassword Keychain item with service dev.julio.feature-flags.session. Survives app restarts. Deleted on sign-out.
Web
Session JWT stored in sessionStorage under key ff_session_token. Cleared when the browser tab is closed. Sign Out button removes it immediately.