Skip to content

Accept multiple Android apk-key-hash origins for passkey verification - #34

Merged
GianniCarlo merged 1 commit into
mainfrom
fix/passkey-android-hash-list
Jul 16, 2026
Merged

Accept multiple Android apk-key-hash origins for passkey verification#34
GianniCarlo merged 1 commit into
mainfrom
fix/passkey-android-hash-list

Conversation

@GianniCarlo

Copy link
Copy Markdown
Contributor

Why

With Play App Signing, the Play-delivered app asserts WebAuthn ceremonies with Google's app-signing certificate, while a locally-built release APK is signed with the upload key. PasskeyService.expectedOrigins accepted only one ANDROID_RELEASE_HASH, so passkey sign-in from an upload-signed build always failed server-side ("Verification failed" in the app) — found while smoke-testing the Android R8 build (bookplayer-android#80).

What

  • ANDROID_RELEASE_HASH now accepts a comma-separated list of android:apk-key-hash: origins (whitespace tolerated, empty segments dropped). Existing single-value envs behave identically.
  • Tests pin the single-value, multi-value, and trailing-comma cases.
  • development.env.template documents the list form.

Deploy note

After merge, append the upload-key origin to the prod ANDROID_RELEASE_HASH (comma-separated, after the existing Play-signing value):

android:apk-key-hash:qsUP5CNmVpU3DBQF2p_96b3_fhG83bo0sow6C1304nk

(SHA-256 of the upload certificate — same fingerprint already listed in bookplayer.github.io's assetlinks.json, so the client-side gate already passes.)

No DB changes, no migrations.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YNhXd8EkXcrjBVYLHm5ZSp

With Play App Signing the store build asserts WebAuthn ceremonies with
Google's app-signing cert, while locally-signed release builds assert
with the upload cert. expectedOrigins only accepted one
ANDROID_RELEASE_HASH, so upload-signed builds always failed
verification ("Verification failed" in the Android app).

ANDROID_RELEASE_HASH now accepts a comma-separated list (whitespace
tolerated, empty segments dropped); existing single-value envs behave
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNhXd8EkXcrjBVYLHm5ZSp
@github-actions

Copy link
Copy Markdown

✅ Claude PR Review — PASS

This PR extends ANDROID_RELEASE_HASH to accept a comma-separated list of Android signing-key hashes so that both the Play App Signing cert and the upload-key cert are accepted as valid WebAuthn origins. PasskeyService.expectedOrigins now splits, trims, and filters the value. The change is correct and low-risk: the env var is required at boot (config/envs.ts:53) so the ! assertion is sound, empty segments are dropped, and the list is passed to verifyRegistrationResponse/verifyAuthenticationResponse as expectedOrigin alongside the still-enforced expectedChallenge, expectedRPID, and single-use challenge/email-binding checks. New unit tests cover single, multiple, and trailing-comma inputs. No authorization, auth-middleware, IAP, or passkey-validation regressions.

Findings: no findings

Model claude-opus-4-8 · run log · 0 new · 0 carried over · 0 resolved · advisory (a human should still review). Duplicate findings are de-duplicated and stale ones auto-resolved across pushes.

@GianniCarlo
GianniCarlo merged commit 1fe9135 into main Jul 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant