diff --git a/.unipi/docs/fix/2026-06-04-imtoken-auto-login-without-query-fix.md b/.unipi/docs/fix/2026-06-04-imtoken-auto-login-without-query-fix.md new file mode 100644 index 0000000..ba5c904 --- /dev/null +++ b/.unipi/docs/fix/2026-06-04-imtoken-auto-login-without-query-fix.md @@ -0,0 +1,34 @@ +--- +title: "imToken in-app browser opens but does not log in — Quick Fix" +type: quick-fix +date: 2026-06-04 +--- + +# imToken in-app browser opens but does not log in — Quick Fix + +## Bug + +imToken can be opened from Chrome into its in-app browser, but the site does not complete wallet login. + +## Root Cause + +`AutoInjectedLogin` only started when the URL contained `?autoLogin=imToken`. imToken's deeplink/in-app-browser navigation can open the page while dropping or not preserving that query string, so the auto-login effect never ran even though the page was inside imToken and an injected provider was available. + +## Fix + +Added an imToken browser fallback: if no explicit `autoLogin` query parameter exists, but the current user agent is imToken, `AutoInjectedLogin` treats it as an imToken direct-login session and runs the same injected login path. + +### Files Modified + +- `src/wallet/AutoInjectedLogin.tsx` — starts imToken direct login based on imToken in-app-browser detection when the deeplink query is missing. +- `src/wallet/injected.ts` — exports `isImTokenBrowser()` so the auto-login flow can reuse the imToken browser detection. + +## Verification + +- `npx tsc --noEmit` +- `npm run format:check` +- `npm test` + +## Notes + +This preserves the explicit `?autoLogin=` flow for TokenPocket and other wallets, while making imToken robust when the deeplink opens the page without the query parameter. diff --git a/src/wallet/AutoInjectedLogin.tsx b/src/wallet/AutoInjectedLogin.tsx index 2ae0e2e..6805af7 100644 --- a/src/wallet/AutoInjectedLogin.tsx +++ b/src/wallet/AutoInjectedLogin.tsx @@ -2,6 +2,7 @@ import { useEffect } from "react"; import { connectInjectedWallet, getInjectedWallet, + isImTokenBrowser, signInWithInjectedWallet, type WalletKind, } from "./injected"; @@ -47,9 +48,9 @@ function waitForInjected(kind: WalletKind): Promise { /** * When the page is opened via a `?autoLogin=` deeplink (typically from * inside TokenPocket / imToken in-app browsers), wait for the wallet to inject - * `window.ethereum`, then require a wallet signature and complete a verified - * backend wallet session. Bypasses WalletConnect entirely so it works on - * networks where the WC relay is blocked. + * `window.ethereum`, then complete wallet login without WalletConnect. imToken + * may drop the query string while opening its in-app browser, so imToken browser + * detection also starts the same direct-login path. */ export function AutoInjectedLogin() { const { completeLogin, status } = useWallet(); @@ -57,11 +58,12 @@ export function AutoInjectedLogin() { useEffect(() => { if (typeof window === "undefined") return; const params = new URLSearchParams(window.location.search); - const kind = parseKind(params.get(AUTO_LOGIN_PARAM)); + const explicitKind = parseKind(params.get(AUTO_LOGIN_PARAM)); + const kind = explicitKind ?? (isImTokenBrowser() ? "imToken" : null); if (!kind) return; if (status === "loading") return; - stripAutoLoginParam(); + if (explicitKind) stripAutoLoginParam(); if (status === "loggedIn") return; let cancelled = false; diff --git a/src/wallet/injected.ts b/src/wallet/injected.ts index 992478a..fcfc66d 100644 --- a/src/wallet/injected.ts +++ b/src/wallet/injected.ts @@ -138,7 +138,7 @@ export function getInjectedEthereum(): EthereumProvider | null { return maybeWindow.ethereum ?? null; } -function isImTokenBrowser(): boolean { +export function isImTokenBrowser(): boolean { if (typeof navigator === "undefined") return false; return /imtoken/i.test(navigator.userAgent || ""); }