Reference implementation on GitHub
SyncTek-LLC/simdrive/examples/auth_bypass — the working iOS + compose pair this recipe describes.
Most real apps need real auth. Recordings need determinism: the same flow on the same build must produce the same screens every time, in CI, with no human in the loop.
OAuth, magic links, SMS one-time codes, biometric prompts, and rate-limited IDPs all break that contract:
The fix is an app-side launch arg that swaps in a deterministic fixture user, plus a backend env flag that accepts a non-secret bypass token only in non-production environments.
Launch the app under SimDrive with a bypass flag. Pass
SimDriveAuthInject as a launch arg from your session_start call (or
from xcrun simctl launch --console). The app reads ProcessInfo.arguments
on boot and, only when the flag is present and the build is non-Release,
short-circuits the login flow with a fixture user.
Backend accepts a fixed AUTH_BYPASS_TOKEN. Stand up your backend in a
recording env (compose profile, k8s overlay, whatever you use) that
reads AUTH_BYPASS_TOKEN from the environment. Requests carrying that
token in Authorization: Bypass <token> resolve to the fixture user.
Seed a deterministic fixture user. Pick a stable id
(00000000-0000-0000-0000-000000000001 works), seed it on backend boot,
keep all replay-relevant state attached to it.
Record + replay normally. SimDrive captures the flow as if the user were really logged in. Replay drives the same launch args, hits the same backend env, and gets pixel-stable screens every time — no IDP, no email, no SMS, no expiry.
Guard the bypass three ways. Compile-time build-flag check, runtime env check, and server-side env check. Any one of them slipping is fine. All three slipping at once is the only way you ship the bug.
A minimal Swift entry point that honours the flag only on non-Release builds.
Drop this into your App.init() or your AppDelegate.application(_:didFinishLaunchingWithOptions:).
import Foundation
enum AuthBypass { /// Returns the fixture user iff: /// 1. the build is NOT Release (compile-time guard), AND /// 2. the SimDriveAuthInject launch arg is present (runtime guard), AND /// 3. AUTH_BYPASS_TOKEN is set in the process env (runtime guard). static func fixtureUserIfEnabled() -> FixtureUser? { #if DEBUG || RECORDING let args = ProcessInfo.processInfo.arguments let env = ProcessInfo.processInfo.environment guard args.contains("SimDriveAuthInject"), let token = env["AUTH_BYPASS_TOKEN"], !token.isEmpty else { return nil } return FixtureUser( id: "00000000-0000-0000-0000-000000000001", email: "fixture@simdrive.local", bypassToken: token ) #else return nil // App Store builds: bypass is physically not in the binary #endif }}
struct FixtureUser { let id: String let email: String let bypassToken: String}Use it at startup:
@mainstruct MyApp: App { init() { if let user = AuthBypass.fixtureUserIfEnabled() { Session.shared.adopt(user) // skip the real login screens } } var body: some Scene { /* ... */ }}From your MCP client, pass the launch arg when starting the SimDrive session:
session_start( bundle_id="com.acme.familybag", device="iPhone 17", os_version="26.3", launch_args=["SimDriveAuthInject"], env={"AUTH_BYPASS_TOKEN": "rec_dev_only_not_a_real_secret"},)Or from the CLI, if you boot the app yourself before session_start:
xcrun simctl launch --console <udid> com.acme.familybag \ SimDriveAuthInject \ AUTH_BYPASS_TOKEN=rec_dev_only_not_a_real_secretStand up your backend in a recording env that knows it must accept the
bypass header. The compose snippet below uses Docker; adapt to your stack.
services: api: image: acme/api:latest environment: APP_ENV: recording # NOT "production" AUTH_BYPASS_TOKEN: rec_dev_only_not_a_real_secret AUTH_BYPASS_USER_ID: "00000000-0000-0000-0000-000000000001" ports: - "8080:8080" seed: image: acme/api:latest command: ["./bin/seed-fixture-user"] environment: DATABASE_URL: postgres://... FIXTURE_USER_ID: "00000000-0000-0000-0000-000000000001" FIXTURE_USER_EMAIL: fixture@simdrive.local depends_on: [db]The fixture user shape your seeder writes:
{ "id": "00000000-0000-0000-0000-000000000001", "email": "fixture@simdrive.local", "display_name": "Fixture User", "created_at": "2026-01-01T00:00:00Z", "tier": "pro", "onboarding_completed": true}Server-side, the auth middleware checks the bypass token only when
APP_ENV is one of dev | recording | ci:
ALLOWED_ENVS = {"dev", "recording", "ci"}
def authenticate(request): env = os.environ["APP_ENV"] auth = request.headers.get("Authorization", "") if auth.startswith("Bypass ") and env in ALLOWED_ENVS: token = auth.removeprefix("Bypass ").strip() if token == os.environ["AUTH_BYPASS_TOKEN"]: return load_user(os.environ["AUTH_BYPASS_USER_ID"]) # fall through to real auth return real_oauth_flow(request)The middleware rejects the bypass token outright in production — even if someone leaks the token to the wrong env, the server still says no.
#if DEBUG || RECORDING so the symbols are physically
absent from the production binary.ProcessInfo.environment at runtime — never hardcode..env.recording (gitignored).AUTH_BYPASS_TOKEN
is fine — it’s explicit). If you call it API_KEY someone will paste it.APP_ENV ∉ {dev, recording, ci}. This is the defence-in-depth backstop.SimDriveAuthInject appears in any string scanned from a Release .ipa.
(strings MyApp.app/MyApp | grep -q SimDriveAuthInject && exit 1.)AUTH_BYPASS_TOKEN if it ever appears in a chat, screenshot,
bug report, or pasted log. The token itself is non-secret in principle, but
rotating costs nothing and removes ambiguity.Reference implementation on GitHub
SyncTek-LLC/simdrive/examples/auth_bypass — the working iOS + compose pair this recipe describes.
Record + Replay concepts
Concepts → Record + Replay — why determinism matters and what the recording bundle looks like.
CI replay
Quickstart → CI replay — wire the recording into a GitHub Actions job that uses the recording backend profile.