Skip to content

Passkeys don't work in Safari — WebAuthn ceremony starts after an awaited fetch #15212

Description

@iLord-DEV

Bug description

Passkeys do not work in Safari, neither creating nor signing in with one. Both flows work in Chrome against the same server, same account and same Statamic install.

Creating (/cp/passkeys → "Create passkey"): the button shows its spinner indefinitely. The Touch ID / Face ID prompt never appears.

Signing in (login screen → "Passkey"): same result — nothing happens, no prompt.

Safari's console logs this warning from SimpleWebAuthn:

startRegistration() was not called correctly. It will try to continue with the provided
options, but this call should be refactored to use the expected call structure instead.
See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge

Nothing is written to laravel.log — the failure is entirely client side.

What I ruled out

  • Relying party / origin: APP_URL matches the origin exactly (https://staging.example.com).
  • Storage: a passkey created in Chrome is confirmed to land in the iCloud Keychain, so the credential store is reachable.
  • Licence: same install, Pro trial, works in Chrome.
  • Server errors: no entries in laravel.log for the attempts.

Likely cause

Both flows fetch their options first (cp/passkeys/create for registration, cp/passkeys/options for authentication) and call startRegistration() / startAuthentication() afterwards, in the promise continuation.

Safari requires the WebAuthn ceremony to be started directly from the user gesture. Once an awaited request sits between the click and the call, Safari drops the gesture and the ceremony never starts — silently, which matches the endless spinner. Chrome does not enforce this.

The usual fix is to pass the options promise into the ceremony rather than awaiting it first, so the call happens synchronously within the gesture.

How to reproduce

  1. Open the CP in Safari (macOS 15, Safari 18).
  2. Go to Users → Passkeys → "Create passkey".
  3. The spinner starts, no system prompt appears, nothing completes.
  4. Repeat in Chrome — the prompt appears and the passkey is created.

Environment

  • Statamic 6.27.2 (Pro, trial)
  • Laravel 13.25, PHP 8.5
  • web-auth/webauthn-lib 5.3.5
  • Safari on macOS (fails) / Chrome on macOS (works)
  • Eloquent user driver, statamic.webauthn at defaults

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions