Sandboxed – iOS Security for Builders

Episode 7

Passkeys on iOS: Killing Passwords in a Real App

Passkeys replace phishable passwords with cryptographic key pairs. Learn how to implement WebAuthn on iOS.

Passkeys replace phishable passwords with cryptographic key pairs. Learn how to implement the WebAuthn standard on iOS—and avoid the CDN caching trap that can brick your auth flow.

🔓The Problem with Passwords

Passwords are fundamentally broken. Users reuse them across sites, they get phished, they end up in data breaches, and even strong passwords can be intercepted. The authentication secret travels over the network every time you log in—that's the core vulnerability.

Passkeys flip the model: Instead of proving you know a secret, you prove you possess a private key. That key never leaves your device. What travels over the network is cryptographic proof—unforgeable, unreplayable, and tied to the specific domain.

🔐Public Key Cryptography to the Rescue

Passkeys are built on WebAuthn, which uses asymmetric cryptography. When you register a passkey:

  1. Your device generates a unique key pair for that website
  2. The public key goes to the server
  3. The private key stays in the Secure Enclave

When you authenticate, the server sends a challenge. Your device signs it with the private key. The server verifies with the public key. No shared secret, no phishing opportunity, no credential to steal.

💃The Two-Step Dance: Registration and Assertion

Registration Flow

The first step is creating the passkey. Your server generates a challenge and sends it to the client along with user info and your relying party (RP) identifier—typically your domain name.

Use ASAuthorizationPlatformPublicKeyCredentialProvider to create a registration request with createCredentialRegistrationRequest(challenge:name:userID:), then present it via ASAuthorizationController.

Assertion Flow

Subsequent logins use assertion—proving you still have the private key. The server sends a new challenge, you sign it, and the server verifies against the stored public key.

Call createCredentialAssertionRequest(challenge:) on the same provider, then present via ASAuthorizationController.

Handling the Response

Both flows complete through the ASAuthorizationControllerDelegate. Switch on the credential type:

  • ASAuthorizationPlatformPublicKeyCredentialRegistration — extract rawAttestationObject and rawClientDataJSON
  • ASAuthorizationPlatformPublicKeyCredentialAssertion — extract signature and rawAuthenticatorData

Send these to your server for WebAuthn verification.

📚Official Implementation References

Apple Developer Documentation

WebAuthn / FIDO2 Specifications

🔧 Apple Sample Projects

⚠️The Associated Domains CDN Trap

⚠️ WARNING: This is the silent killer of passkey implementations

Passkeys require Associated Domains to verify your app is allowed to create credentials for your domain. iOS fetches your apple-app-site-association (AASA) file from Apple's CDN, not directly from your server.

The nightmare scenario: You deploy your AASA file, it gets cached by Apple's CDN, then you discover a typo. The fix you deploy won't take effect for 24 hours or more. Your passkey flow is bricked until the cache expires.

Setting Up Associated Domains

Add the Associated Domains entitlement to your app with the webcredentials: prefix for your domain. You might also have applinks: for Universal Links.

See Apple's Supporting Associated Domains documentation for the complete setup guide and AASA file format.

Safety Checklist

  • Validate your JSON thoroughly before deploying. Use jq or an online validator. One misplaced comma breaks everything.
  • Use Developer Mode during development. Add ?mode=developer to your entitlement to bypass the CDN cache.
  • Deploy AASA early in your development cycle, not right before launch. Give yourself time to catch mistakes.
  • Test with a fresh device or clear the Associated Domains cache to verify your changes took effect.

🎯Key Takeaways

  • 1.Passkeys use public key cryptography—the private key never leaves your device, eliminating phishing and credential theft.
  • 2.Two-step dance: Registration creates the key pair, Assertion proves possession. Both use challenge-response patterns.
  • 3.ASAuthorizationController is your gateway to passkeys on iOS. Master the delegate pattern and credential types.
  • 4.Respect the CDN—Apple caches your AASA file. Deploy early, validate thoroughly, and use Developer Mode during testing.

📱About Sandboxed

Sandboxed is a deep-dive podcast series on iOS security—built for developers who ship apps to millions of users and need to understand what's actually happening under the hood.

Each episode gives you a mental model you can apply this week—concrete enough to act on, without the 50-page spec.

If that sounds useful, I'd love to have you along.

Ready to dive deeper?

Stay tuned for more episodes exploring iOS security topics.

Stay in the Loop

Get iOS security insights, new episode alerts, and exclusive content delivered to your inbox.

No spam. Unsubscribe anytime.

Passkeys on iOS: Killing Passwords in a Real App | Sandboxed Podcast