What developers ship today
- API keys in
Info.plist, source files, or build settings. - Same value in every install. Rotate the key, ship a new build.
- Anyone with the IPA can read them.
Runtime delivery for iOS secrets
Your iOS app fetches secrets from appAttest at runtime. They land in Keychain. They never ship in your binary.
One line. AppAttest.start(). Your keys land in Keychain when Apple says it's really your app.
The default
Drop them in Info.plist, hard-code them in a Swift file, embed them via build settings — the result is the same. Anyone with the IPA and ten minutes can read them out.
<key>OpenAIAPIKey</key>
<string>sk-proj-abc123xyz...</string>
<key>StripePublishableKey</key>
<string>pk_live_51HqX...</string> Shipped to every install. Same value in every copy.
<!-- no secrets here -->
<!-- they arrive at runtime, attested --> Binary ships clean. Keys land in Keychain after Apple verifies the install.
Positioning
How it works
AppAttest.start() One synchronous call in your @main. Apple proves the binary is yours; the SDK syncs your secrets and persists them in Keychain.
AppAttest.secrets["OPENAI_API_KEY"] Synchronous subscript. After the first launch, secrets load from Keychain before the first frame — no async / await on the hot path.
switch AppAttest.state { /* … */ } Observable state — ready, sandboxBlocked, paymentRequired, failed. SwiftUI re-renders. No throwing on the read path.
@mainimport SwiftUI
import AppAttest
@main
struct MyApp: App {
init() { AppAttest.start() }
var body: some Scene {
WindowGroup { ContentView() }
}
}
struct ContentView: View {
var body: some View {
if let key = AppAttest.secrets["OPENAI_API_KEY"] {
Text("Ready")
} else {
ProgressView("Loading…")
}
}
} What developers ship today
Info.plist, source files, or build settings.What appAttest changes
Sandbox runs indefinitely. Production starts when you subscribe a project.