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

1

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).

2

Client sends token to POST /auth/apple

The Apple identity token is sent as Authorization: Bearer <token>.

3

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.

4

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.

5

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:

  1. Start the server without this variable set.
  2. Attempt to sign in from the iOS app or web panel.
  3. The server logs: ADMIN_APPLE_USER_ID is not set. Attempting user sub: 000000.abc123…
  4. 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

POST /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.
503ADMIN_APPLE_USER_ID not configured (logs the sub to help you set it).

GET /api/flags

Return all feature flags. Requires a valid session token.

Request

Authorization: Bearer <session-token>

Response 200

[{ "key": "immersive_mode", "isEnabled": true, "description": "…" }]
POST /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. 1

    Create a Service ID

    In Apple Developer → Identifiers, click + and select Services IDs. Use an identifier like dev.julio.featureflags.web.

  2. 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 to https://<your-domain>/feature-flags.html.

  3. 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.