Repository navigation
Fix passkey logins failing on iOS Safari due to binary user handles - #42
Open
alireza-aminzadeh wants to merge 1 commit into
Open
alireza-aminzadeh wants to merge 1 commit into
alireza-aminzadeh wants to merge 1 commit into
Conversation
iOS Safari runs the raw HMAC user handle through a lossy UTF-8 decode, so the handle returned with the assertion no longer matches the stored one and login fails with an unhandled InvalidUserHandleException. Derive the default handle as hex, which stays ASCII within the WebAuthn 64 byte limit, and rethrow handle mismatches as InvalidPasskeyException so already-corrupted credentials fail with a validation error prompting re-registration instead of a 500. Existing credentials keep working because verification compares the handle stored on the credential, never a recomputed one.
2 of 10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #41
getPasskeyUserHandle()returns raw binary HMAC bytes as the WebAuthnuser.id. The sample handle in the report decodes to bytes full ofEF BF BD(U+FFFD) — binary data that went through a lossy UTF-8 decode/encode, where bytes below 0x80 survive and everything else is replaced. iOS Safari does that to the user handle somewhere between registration and the assertion, so the returned handle can never match the stored one again andCheckUserHandlethrows an unhandledInvalidUserHandleException, which surfaces as a 500.Two changes:
getPasskeyUserHandle()now returns the hex form of the same HMAC (droppedbinary: true). 64 ASCII characters, still within WebAuthn's 64 byte limit foruser.id, and it survives any UTF-8 round trip.VerifyPasskeycatchesInvalidUserHandleExceptionand rethrows it as anInvalidPasskeyException. Credentials that already registered a binary handle from an affected device are unrecoverable server-side — the authenticator holds the corrupteduser.id— so those logins now fail with a 422 telling the user to re-register instead of a 500.The derivation change does not affect existing credentials: verification compares the assertion against the handle stored on the credential record, never a recomputed one (the same reason the existing secret-rotation test passes). New tests cover a legacy credential with a raw binary handle still verifying when the authenticator returns it intact, and a regression test that corrupts the handle the same way iOS does (UTF-8 decode with U+FFFD substitution) and asserts the login now fails with the validation error.
One side effect worth noting: a user who registers an additional passkey after this change gets a hex handle on the new credential while older credentials keep their binary one. Each credential is validated against its own stored handle, so both keep working.
composer test(Pint, PHPStan, Pest — 79 tests, 182 assertions) passes on PHP 8.5.