Connect() auto-reconnects to previously cached provider — iframe session persists after logout (Modal SDK v10)

## Environment

- `@web3auth/modal` v10.13.1 (UMD via unpkg)

- `web3AuthNetwork`: `sapphire_devnet`

- Browser: Chrome (latest)

- Platform: Web (vanilla JS, no React)

## Problem

After a user logs in with one provider (e.g., Google), logs out, and opens the login popup again, `connect()` either:

1. Auto-connects to the previously used provider without showing the modal, OR

2. Shows the modal but auto-connects before the user clicks anything, OR

3. Shows the modal, user clicks a **different** provider (e.g., Twitter), but the SDK connects with the **previous** provider (Google)

The user cannot switch between providers without manually clearing site data for `wallet.web3auth.io` in browser settings.

## Root cause identified

The iframe at `wallet.web3auth.io/v5/frame` maintains its own cross-origin session/OAuth token cache. This cache persists independently of the parent page’s `localStorage`, `sessionStorage`, and `IndexedDB`. After logout, the SDK reports `connected: false`, but the iframe still holds cached OAuth tokens. When `connect()` or `connectTo()` is called, the iframe auto-reconnects using those cached tokens, ignoring the requested provider.

## Why `logout({ cleanup: true })` doesn’t fix it

`logout({ cleanup: true })` requires `connected === true` to send a cleanup message to the iframe. But after a session expires (or `localStorage` is cleared), `init()` reports `connected: false`, so `logout()` cannot be called. This creates a deadlock:

- Can’t `logout()` because not connected

- Can’t `connect()` fresh because iframe auto-reconnects

- Can’t access iframe storage because it’s cross-origin

## Diagnostic evidence

After `init()`, `localStorage` state shows:

```json

{

“connectedConnectorName”: null,

“cachedConnector”: null,

“currentChainId”: “0xaa36a7”,

“idToken”: null

}

```

SDK state: `connected: false`, `status: “ready”`

Yet `connect()` still auto-connects to the previous provider.

## What we tried (none worked)

1. `logout({ cleanup: true })` — SDK never reaches `connected: true` so this never runs

2. Clearing all `localStorage` keys matching `Web3Auth|torus|openlogin|plink|w3a` before and after `init()`

3. Deleting IndexedDB databases (`torus_default`, `openlogin_store`, `web3auth_store`, `plink_store`, `w3a_default`)

4. `sessionTime: 1` — iframe still caches OAuth tokens independently

5. `storageType: ‘session’` — iframe cache is unaffected

6. Two-phase init: first instance for `logout({ cleanup: true })`, fresh instance for `connect()` — first instance also sees `connected: false`

7. Polling `web3auth.connected` for 3 seconds after `init()` to catch async iframe reconnection — stays `false`

8. `connectTo(‘auth’, { authConnection: ‘google’ })` to explicitly specify provider — iframe ignores the `authConnection` parameter and returns the cached provider’s session

## Console logs

```

[W3A] init done: status=ready, connected=false

```

When `connect()` is called after the above, the modal either doesn’t appear (auto-connects silently) or appears and auto-connects before user interaction. If the previous session was with Google and user selects Twitter:

```

[web3auth-popup] userInfo for auth: {typeOfLogin: “google”, verifier: “…”, aggregateVerifier: “…”, hasIdToken: true}

```

When `connectTo()` is attempted while the iframe has auto-reconnected:

```

Uncaught (in promise) WalletLoginError: Failed to connect with wallet. Already connected

at fromCode (modal.umd.min.js:2)

at connectionError (modal.umd.min.js:2)

at checkConnectionRequirements (modal.umd.min.js:2)

at connect (modal.umd.min.js:2)

at connectTo (modal.umd.min.js:2)

```

Failed analytics fetch (non-blocking, but present on every load):

```

modal.umd.min.js:2 Failed to fetch

modal.umd.min.js:2 Error: Failed to fetch

at s (modal.umd.min.js:2:3210228)

at d.error (modal.umd.min.js:2:3210868)

'Failed to initialize Analytics'

```

## Package details

| Package | Version | Source |

|---------|---------|--------|

| `@web3auth/modal` | 10.13.1 | `https://unpkg.com/@web3auth/modal@10.13.1/dist/modal.umd.min.js\` |

| `web3` | 1.10.0 | `https://cdn.jsdelivr.net/npm/web3@1.10.0/dist/web3.min.js\` |

No other Web3Auth packages are used. The integration is vanilla JavaScript (no React, no bundler) loading the UMD build via `` tags.

## Minimal reproduction code

```javascript

const web3auth = new Web3Auth({

clientId: ‘YOUR_CLIENT_ID’,

web3AuthNetwork: ‘sapphire_devnet’,

chainConfig: {

chainNamespace: ‘eip155’,

chainId: ‘0x1’,

rpcTarget: ‘https://rpc.ankr.com/eth’,

},

});

await web3auth.init();

// connected is false, but iframe has cached session

const provider = await web3auth.connect();

// Auto-connects to previously cached provider without showing modal

// OR shows modal but ignores user’s provider selection

const userInfo = await web3auth.getUserInfo();

// Returns previous provider’s identity, not the one the user selected

```

## Steps to reproduce

1. Call `init()` + `connect()` — log in with Google

2. Call `logout({ cleanup: true })`

3. Call `init()` + `connect()` again — expect modal to show and let user pick a different provider

4. **Actual:** Auto-connects to Google without showing modal, or shows modal but still connects as Google regardless of selection

## Expected behavior

After `logout({ cleanup: true })`, the iframe’s cached OAuth session should be fully cleared so that the next `connect()` shows a fresh modal and honors the user’s provider selection.

## Question

Is there a way to force-clear the `wallet.web3auth.io` iframe’s cached session from the parent page? Or a constructor/init parameter that prevents the iframe from auto-reconnecting with cached OAuth tokens?

Thanks — you nailed the root cause. I searched the Embedded Wallets (Web3Auth) docs and internal knowledge and couldn’t find any SDK/constructor/init option to purge the cross-origin iframe (wallet.web3auth.io) session once the parent reports connected: false. That behavior matches your findings: the iframe maintains its own OAuth/session cache out of reach of the parent page for browser/OAuth security reasons.

Short actionable options/workarounds:

  • User-side: ask affected users to clear site data for wallet.web3auth.io (or open an incognito window) — this is the only straightforward way to remove the iframe’s cached OAuth tokens today.
  • Integration change: move to a headless/no-modal flow (custom auth/JWT or server-side verification) so you control auth/session lifecycle instead of relying on the modal iframe.
  • Temporary dev workaround: use incognito/new browser profile when testing to avoid the persistent iframe session.
  • Product route: file a feature request / bug with Web3Auth (or ask us to escalate) requesting a supported API to force-clear iframe sessions or a “always show fresh modal / ignore cached session” flag.

Next steps I can take: escalate this to the product/engineering team and attach your reproduction + logs, or help draft a concise feature request for Web3Auth. Which would you prefer?

Note: This response was generated by an AI bot and may require further verification. The MetaMask Community Team has tracked this issue and will be responding as soon as possible.

Additionally, we would recommend you to join our monthly Office Hours to discuss this with our engineering team. MetaMask Developer Office Hours

Both, please.

  1. Escalate to engineering with the reproduction + logs attached. This is a blocker for us — users can’t switch auth providers without manually clearing browser data, which isn’t viable.

  2. Feature request: We’d like a supported API for either:

    • A forceCleanSession: true flag on connect() / init() that tells the iframe to discard any cached OAuth tokens before showing the modal

    • A static method like Web3Auth.clearIframeSession(clientId) callable without needing connected: true

    • Or at minimum, making logout({ cleanup: true }) work even when connected: false (since the iframe clearly still has a session even though the SDK doesn’t think it’s connected)

In the meantime, we’ll look at moving to the headless/no-modal JWT flow as a workaround so we control the auth lifecycle directly. Any pointers on best practices for that migration (from modal social login to custom JWT-based connectTo) would be helpful.

Hi @Daveed1 ! Thanks for your feedback! Before we escalate your case, would you be able to update to the latest version 10.15.0 and have a try?

Any pointers on best practices for that migration (from modal social login to custom JWT-based connectTo) would be helpful.

The social logins and custom JWT are configured on the dashboard. You can refer to our docs below, disable the social logins then set up the custom JWT.

Confirmed on our integration: 10.15.0 required a second login for the first session to stick; reverting to 10.13.1 removed that. Iframe auto-reconnect after logout is still an issue; 10.15.0 did not fix it and introduced the double-login regression for us.

Sorry but I want to make sure I understand it correctly. For 10.15.0, may I know about the double-login you mentioned? It would be better if there are some screenshots or recordings to show the login process. It is recommended to always use the latest version so we would like to know what happened and then fix the issue.