Pop Login Issue Reproduction in internet identity

ICP Login Not Opening in iOS Safari - Help Needed

The Problem

When users click the login button on iOS Safari, the Internet Identity popup window doesn’t open. It works fine on desktop browsers but completely fails on mobile Safari.

Current Implementation

export const login = async (): Promise<boolean> => {
  try {
    await IdentityManager.forceRefresh();
    const client = await BackendUtils.getAuthClient();

    return new Promise((resolve, reject) => {
      const config = EnvironmentManager.getConfig();

      client.login({
        maxTimeToLive: BigInt(365 * 24 * 60 * 60 * 1000000000),
        identityProvider: config.identityProvider,
        derivationOrigin: config.derivationOrigin,
        onSuccess: async () => {
          await initializeSmartActors();
          window.location.reload(); // This happens after successful login
          resolve(true);
        },
        onError: (error) => {
          console.error("Login error:", error);
          reject(error);
        },
      });
    });
  } catch (error) {
    console.error("Login initialization failed:", error);
    return false;
  }
};

What I’ve Tried

  1. The login function is async and has some initialization before calling client.login()

  2. On desktop browsers, the Internet Identity window opens fine

  3. On iOS Safari, nothing happens - no popup, no error

Questions

  1. Is the async initialization before client.login() blocking the popup? Safari requires popups to be triggered directly from user interaction

  2. Should I call client.login() synchronously in the click handler?

  3. Is there a recommended pattern for mobile Safari compatibility?

Additional Context

I also noticed these potential issues in my code:

  • window.location.reload() called inside the library code (should this be caller’s responsibility?)

  • No retry logic for signature errors

  • Actor initialization might have race conditions

But the main blocker is the iOS Safari login popup issue. Any help would be appreciated!

Environment

  • @dfinity/auth-client: [version]

  • @dfinity/agent: [version]

  • Testing on: iOS Safari, Chrome iOS

  • Works on: Desktop Chrome, Firefox, Safari

You got big problem with iOS Safari, login popup not show. Me think hard, help you fix. Let’s smash this!

Problem: Button click, no popup on iOS Safari. Work good on desktop, but mobile Safari? Nada. No error, just quiet.

Your Code: You share login function. It async, wait for stuff, then call client.login(). Me see you use @dfinity/auth-client, Internet Identity for login. Popup should open, but iOS Safari say “no way.”

Why Problem Happen? Me think iOS Safari picky. Safari on iPhone hate popup if not come straight from user tap. Async stuff (await IdentityManager.forceRefresh() and BackendUtils.getAuthClient()) maybe make delay. Safari think, “This not user tap anymore!” and block popup. Desktop not care, but mobile Safari strict.

Answer Your Questions:

  1. Async blocking popup? Ugh, yes! Safari want popup right when user tap. If you await stuff first, it too slow, Safari say “no popup for you.” Async break the “user action” rule.

  2. Call client.login() synchronous? Me say yes, but careful. If you call client.login() right in click handler, no await, popup might work. But you need client ready before tap. Make client early, then call client.login() in tap.

  3. Pattern for mobile Safari? Me know good way! Safari like simple. Make client when app start, not in click. Then, in click handler, call client.login() quick. No wait, no async in tap. Also, check if popup blocked—tell user tap again or show error.

Fix Ideas:

  1. Move Client Init Outside Click Make client ready when app load, not in login function. Like this:

    javascript

    let client = null;
    // App start, make client
    async function initApp() {
      try {
        await IdentityManager.forceRefresh();
        client = await BackendUtils.getAuthClient();
      } catch (error) {
        console.error("Client init bad:", error);
      }
    }
    
    // Call initApp when app start
    initApp();
    
    // In button click, use client
    export const login = (): Promise<boolean> => {
      if (!client) {
        console.error("Client not ready!");
        return Promise.resolve(false);
      }
      const config = EnvironmentManager.getConfig();
      return new Promise((resolve, reject) => {
        client.login({
          maxTimeToLive: BigInt(365 * 24 * 60 * 60 * 1000000000),
          identityProvider: config.identityProvider,
          derivationOrigin: config.derivationOrigin,
          onSuccess: async () => {
            await initializeSmartActors();
            window.location.reload();
            resolve(true);
          },
          onError: (error) => {
            console.error("Login error:", error);
            reject(error);
          },
        });
      });
    };
    

    This way, client.login() run fast in click, no async delay. Safari happy.

  2. Check Popup Blocker iOS Safari might block popup anyway. Add check:

    javascript

    export const login = (): Promise<boolean> => {
      if (!client) {
        console.error("Client not ready!");
        return Promise.resolve(false);
      }
      const config = EnvironmentManager.getConfig();
      return new Promise((resolve, reject) => {
        const popup = client.login({
          maxTimeToLive: BigInt(365 * 24 * 60 * 60 * 1000000000),
          identityProvider: config.identityProvider,
          derivationOrigin: config.derivationOrigin,
          onSuccess: async () => {
            await initializeSmartActors();
            window.location.reload();
            resolve(true);
          },
          onError: (error) => {
            console.error("Login error:", error);
            reject(error);
          },
        });
        if (!popup) {
          alert("Popup blocked! Tap again.");
          reject(new Error("Popup blocked"));
        }
      });
    };
    

    Tell user if popup fail, maybe they try again.

  3. Other Code Problem You mention window.location.reload(), actor init, and no retry. Me think:

    • Reload: Bad idea in library. Let caller decide reload. Maybe return true and let app handle reload.

    • Retry logic: Good idea for signature error. Add try-catch in onSuccess or retry client.login() if fail.

    • Race condition: initializeSmartActors() might mess up if async. Check if it need wait or lock.

Other Tip:

  • Test @dfinity/auth-client version. Old version maybe buggy on iOS. Update to latest, check changelog.

  • iOS Safari and Chrome iOS use same engine (WebKit). If Chrome iOS work, maybe setting issue. Check Safari setting for popup block.

  • Look console log in iOS Safari. Use Mac Safari debug tool to see error.

Caveman Plan:

  1. Init client when app start, not in click.

  2. Call client.login() fast in click handler, no await.

  3. Check if popup blocked, tell user.

  4. Fix reload, maybe remove from library.

  5. Test latest @dfinity/auth-client.

You try this, smash popup problem! If still stuck, me look more. What @dfinity/auth-client version you use? Any console log in iOS Safari?

1 Like

Me try make fancy complex code with cache and validation before login. You say “No! Safari hate delay! Just call login FAST!” You right! Problem go away like magic! Me feel dumb like caveman try catch fish with rock. You show me use spear instead. BOOM! Fish caught! Thank you wise friend! You save day! Now popup work on iPhone Safari! Me very happy! You best!