Skip to content

fix: post-signup claim redirect + passkey retry for Samsung#1837

Open
Hugo0 wants to merge 2 commits into
devfrom
fix/post-signup-claim-redirect
Open

fix: post-signup claim redirect + passkey retry for Samsung#1837
Hugo0 wants to merge 2 commits into
devfrom
fix/post-signup-claim-redirect

Conversation

@Hugo0

@Hugo0 Hugo0 commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Bug 1 — Claim redirect: Remove KYC verification check from PostSignupActionManager — new users arriving via claim links were blocked from seeing the claim modal because they aren't KYC verified yet. KYC is only needed for bank/offramp claims, and the claim page itself handles that gating.
  • Bug 2 — Passkey login: Auto-retry passkey login once on NotAllowedError for devices with multiple passkey providers (Google Credential Manager + Samsung Pass). The first provider may intercept and report "no passkeys" while the actual passkey lives in the other provider.
  • Add TODO for future WebAuthn conditional mediation as the longer-term fix for the Samsung issue.

Bug 1 details

  • User report: new user arrives via claim QR/link → signs up → completes passkey setup → lands on home with $0
  • Root cause: PostSignupActionManager gated the claim modal on isUserKycVerified(), which is always false for new signups
  • Fix: Remove the KYC gate — the redirect URL in localStorage is now picked up immediately on /home

Bug 2 details

  • User report: Samsung S22 Ultra user taps "Log In" → Google Credential Manager shows "No passkeys available" → has to dismiss and retry multiple times before Samsung Pass responds
  • Sentry: ~3,900 events across 400 users for LOGIN_CANCELED (PEANUT-UI-6T2/A9W/6T7), many likely from this dual-provider conflict
  • Fix: Extract login attempt to _attemptLogin(), auto-retry once on NotAllowedError before throwing to the UI
  • Future: TODO added for conditional mediation (WebAuthn autofill) which surfaces passkeys from ALL providers

Test plan

  • New user signup via claim link → should see claim modal on home page immediately after setup
  • New user signup via request link → should see "Send it!" modal on home page
  • Normal signup without claim link → no modal shown (no regression)
  • Claim to bank still requires KYC at the claim page level (not at the modal level)
  • Login on Android device → should work normally, auto-retry is transparent
  • Login canceled by user → still shows appropriate error after retry attempt
  • Login on Samsung with dual passkey providers → should succeed on auto-retry

New users arriving via claim links were blocked from seeing the claim
modal because PostSignupActionManager required KYC verification. KYC is
only needed for bank/offramp claims, and the claim page itself handles
that gating — the modal-level check was redundant and breaking the flow.

Also adds TODO for future WebAuthn conditional mediation to address
Samsung dual-provider passkey conflicts.
@vercel

vercel Bot commented Mar 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Mar 27, 2026 7:07pm

Request Review

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fba44ab9-3fc4-43ae-bf17-0d452a9a9141

📥 Commits

Reviewing files that changed from the base of the PR and between 5b6310a and 5f48562.

📒 Files selected for processing (1)
  • src/hooks/useZeroDev.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/hooks/useZeroDev.ts

Walkthrough

PostSignupActionManager no longer depends on auth/KYC state; modal check now triggers solely on presence of a redirect URL and useEffect depends only on router. useZeroDev refactors WebAuthn login: core key-acquisition moved to _attemptLogin, handleLogin now retries once on NotAllowedError, and persists WebAuthn key to cookie.

Changes

Cohort / File(s) Summary
PostSignupActionManager refactor
src/components/Global/PostSignupActionManager/index.tsx
Removed useAuth and isUserKycVerified usage. Replaced checkClaimModalAfterKYC with checkForPostSignupAction, changing modal-open condition from “KYC verified AND redirect URL exists” to “redirect URL exists” only. Updated useEffect dependency to router (removed user).
WebAuthn login refactor
src/hooks/useZeroDev.ts
Extracted WebAuthn key acquisition into new async helper _attemptLogin that builds headers, calls toWebAuthnKey in WebAuthnMode.Login, sets the key and writes WEB_AUTHN_COOKIE_KEY. handleLogin now calls _attemptLogin and performs one automatic retry on NotAllowedError; on repeated NotAllowedError it clears isLoggingIn and throws PasskeyError('LOGIN_CANCELED'). Removed previous inline key-generation block.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the two main changes: fixing the post-signup claim redirect issue by removing the KYC gate, and adding passkey retry logic for Samsung devices.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing both bugs, their root causes, fixes implemented, and providing a clear test plan.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/post-signup-claim-redirect

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/Global/PostSignupActionManager/index.tsx (1)

43-45: Consider moving the function inside useEffect or memoizing it.

checkForPostSignupAction is called inside the effect but isn't in the dependency array. While this works because router is stable, it could trigger ESLint's exhaustive-deps warning. Moving the logic inside the effect makes the intent clearer:

♻️ Optional: inline the check inside useEffect
     useEffect(() => {
-        checkForPostSignupAction()
+        const redirectUrl = getRedirectUrl()
+        if (redirectUrl) {
+            const matchedAction = POST_SIGNUP_ACTIONS.find((action) => action.pathPattern.test(redirectUrl))
+            if (matchedAction) {
+                setActionConfig({
+                    ...matchedAction.config,
+                    action: () => {
+                        router.push(redirectUrl)
+                        clearRedirectUrl()
+                        setShowModal(false)
+                    },
+                })
+                setShowModal(true)
+            }
+        }
     }, [router])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Global/PostSignupActionManager/index.tsx` around lines 43 -
45, The effect calls checkForPostSignupAction but doesn't include it in
dependencies; to avoid exhaustive-deps warnings and clarify intent, either
inline the logic of checkForPostSignupAction directly inside the useEffect that
currently depends on router, or wrap checkForPostSignupAction with useCallback
(referencing router as needed) and add that memoized function to the effect
dependency array; update the useEffect to call the inlined logic or the memoized
checkForPostSignupAction so ESLint no longer flags a missing dependency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/Global/PostSignupActionManager/index.tsx`:
- Around line 43-45: The effect calls checkForPostSignupAction but doesn't
include it in dependencies; to avoid exhaustive-deps warnings and clarify
intent, either inline the logic of checkForPostSignupAction directly inside the
useEffect that currently depends on router, or wrap checkForPostSignupAction
with useCallback (referencing router as needed) and add that memoized function
to the effect dependency array; update the useEffect to call the inlined logic
or the memoized checkForPostSignupAction so ESLint no longer flags a missing
dependency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6de56793-107e-4951-b4da-cccbf154dd05

📥 Commits

Reviewing files that changed from the base of the PR and between 07342a2 and 5b6310a.

📒 Files selected for processing (2)
  • src/components/Global/PostSignupActionManager/index.tsx
  • src/hooks/useZeroDev.ts

…evices

On Samsung devices with both Google Credential Manager and Samsung Pass,
the first provider may intercept the WebAuthn request and report "no
passkeys" while the actual passkey lives in the other provider. This adds
a single automatic retry so the second provider gets a chance to respond,
which typically succeeds.

Addresses ~3,900 Sentry events (PEANUT-UI-6T2/A9W/6T7) where many are
likely caused by this dual-provider conflict rather than actual missing
passkeys.
@Hugo0 Hugo0 changed the title fix: remove KYC gate from post-signup claim redirect fix: post-signup claim redirect + passkey retry for Samsung Mar 27, 2026
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