22 * EIP-1193 compatible provider for Immutable zkEVM
33 */
44
5- import type { User , Auth } from '@imtbl/auth' ;
5+ import { type User , Auth } from '@imtbl/auth' ;
66import {
77 toHex , fromHex , createPublicClient , http , isAddress , hexToString ,
88} from 'viem' ;
@@ -287,6 +287,20 @@ export class PassportEVMProvider implements Provider {
287287 } ) ;
288288 }
289289
290+ /**
291+ * Creates a shared auth client for wallet-only mode
292+ * Used when apps don't provide their own OAuth client
293+ * @internal
294+ */
295+ // eslint-disable-next-line class-methods-use-this
296+ private createSharedAuthClient ( ) : Auth {
297+ return new Auth ( {
298+ clientId : 'immutable-passport-wallet-only' , // Shared OAuth client ID for wallet-only mode
299+ redirectUri : 'https://passport.immutable.com/wallet-callback' , // This callback page is hosted by Passport and handles OAuth redirects
300+ scope : 'openid transact' , // Wallet-only scope, no profile/email access
301+ } ) ;
302+ }
303+
290304 /**
291305 * Sets signer (internal use only)
292306 * @internal
@@ -380,29 +394,42 @@ export class PassportEVMProvider implements Provider {
380394
381395 /**
382396 * Ensures user is authenticated, triggers login automatically if auth client provided
397+ * If no auth client is provided, creates a shared auth client for wallet-only mode
383398 */
384399 private async ensureAuthenticated ( ) : Promise < void > {
385400 if ( this . authenticatedUser ) {
386401 return ;
387402 }
388403
389- if ( this . auth ) {
390- const user = await this . auth . loginPopup ( ) ;
391- if ( user ) {
392- this . setAuthenticatedUser ( user ) ;
393- return ;
394- }
404+ // If no auth client provided, create shared client for wallet-only mode
405+ if ( ! this . auth ) {
406+ this . auth = this . createSharedAuthClient ( ) ;
407+ }
408+
409+ // Attempt to get existing user first (checks localStorage/session)
410+ const existingUser = await this . auth . getUser ( ) ;
411+ if ( existingUser ) {
412+ this . setAuthenticatedUser ( existingUser ) ;
413+ return ;
414+ }
415+
416+ // No existing user, trigger login popup
417+ const user = await this . auth . loginPopup ( ) ;
418+ if ( user ) {
419+ this . setAuthenticatedUser ( user ) ;
420+ return ;
395421 }
396422
397423 throw new JsonRpcError (
398424 ProviderErrorCode . UNAUTHORIZED ,
399- 'User not authenticated. Please provide an auth client or login first .' ,
425+ 'User not authenticated. Login popup was closed or cancelled .' ,
400426 ) ;
401427 }
402428
403429 /**
404430 * Handles eth_requestAccounts
405- * Automatically triggers login if auth client is provided and user not authenticated
431+ * Automatically triggers login if user not authenticated
432+ * If no auth client is provided, uses shared client ID for wallet-only mode
406433 */
407434 private async handleRequestAccounts ( ) : Promise < string [ ] > {
408435 // Check if we already have a wallet address
@@ -412,7 +439,7 @@ export class PassportEVMProvider implements Provider {
412439 return [ address ] ;
413440 }
414441
415- // Ensure authenticated (will auto-login if auth client provided)
442+ // Ensure authenticated (will auto-login using shared client if no auth provided)
416443 await this . ensureAuthenticated ( ) ;
417444
418445 // Ensure signer is set
0 commit comments