Skip to content

Commit 7101656

Browse files
feat(passport, gamebridge): add support for direct login methods (google, apple, facebook) in ts sdk and game bridge (#2665)
1 parent b4dec7c commit 7101656

File tree

8 files changed

+396
-41
lines changed

8 files changed

+396
-41
lines changed

packages/game-bridge/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ window.callFunction = async (jsonData: string) => {
233233
scope,
234234
crossSdkBridgeEnabled: true,
235235
logoutMode,
236-
extraQueryParams: request.extraQueryParams,
237236
overrides: {
238237
authenticationDomain: 'https://auth.dev.immutable.com',
239238
magicPublishableApiKey: 'pk_live_4058236363130CA9', // Public key
@@ -269,7 +268,6 @@ window.callFunction = async (jsonData: string) => {
269268
crossSdkBridgeEnabled: true,
270269
jsonRpcReferrer: 'http://imtblgamesdk.local',
271270
logoutMode,
272-
extraQueryParams: request.extraQueryParams,
273271
};
274272
}
275273

@@ -351,7 +349,9 @@ window.callFunction = async (jsonData: string) => {
351349
break;
352350
}
353351
case PASSPORT_FUNCTIONS.getPKCEAuthUrl: {
354-
const url = await getPassportClient().loginWithPKCEFlow();
352+
const request = data ? JSON.parse(data) : {};
353+
const directLoginMethod = request?.directLoginMethod;
354+
const url = await getPassportClient().loginWithPKCEFlow(directLoginMethod);
355355
trackDuration(moduleName, 'performedGetPkceAuthUrl', mt(markStart));
356356
callbackToGame({
357357
responseFor: fxName,

packages/passport/sdk-sample-app/src/components/PassportMethods.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ function PassportMethods() {
1111
const { isLoading } = useStatusProvider();
1212
const {
1313
logout,
14-
login,
1514
popupRedirect,
15+
popupRedirectGoogle,
16+
popupRedirectApple,
17+
popupRedirectFacebook,
18+
login,
19+
loginGoogle,
20+
loginApple,
21+
loginFacebook,
1622
getIdToken,
1723
getAccessToken,
1824
getUserInfo,
@@ -50,12 +56,48 @@ function PassportMethods() {
5056
>
5157
Popup Login
5258
</WorkflowButton>
59+
<WorkflowButton
60+
disabled={isLoading}
61+
onClick={popupRedirectGoogle}
62+
>
63+
Popup Login (Google)
64+
</WorkflowButton>
65+
<WorkflowButton
66+
disabled={isLoading}
67+
onClick={popupRedirectApple}
68+
>
69+
Popup Login (Apple)
70+
</WorkflowButton>
71+
<WorkflowButton
72+
disabled={isLoading}
73+
onClick={popupRedirectFacebook}
74+
>
75+
Popup Login (Facebook)
76+
</WorkflowButton>
5377
<WorkflowButton
5478
disabled={isLoading}
5579
onClick={login}
5680
>
5781
Login
5882
</WorkflowButton>
83+
<WorkflowButton
84+
disabled={isLoading}
85+
onClick={loginGoogle}
86+
>
87+
Login (Google)
88+
</WorkflowButton>
89+
<WorkflowButton
90+
disabled={isLoading}
91+
onClick={loginApple}
92+
>
93+
Login (Apple)
94+
</WorkflowButton>
95+
<WorkflowButton
96+
disabled={isLoading}
97+
onClick={loginFacebook}
98+
>
99+
Login (Facebook)
100+
</WorkflowButton>
59101
<WorkflowButton
60102
disabled={isLoading}
61103
onClick={logout}

packages/passport/sdk-sample-app/src/context/PassportProvider.tsx

Lines changed: 131 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ const PassportContext = createContext<{
2121
getUserInfo: () => Promise<UserProfile | undefined>;
2222
getLinkedAddresses: () => Promise<string[] | undefined>;
2323
linkWallet: (params: LinkWalletParams) => Promise<LinkedWallet | undefined>;
24+
popupRedirectGoogle: () => void;
25+
popupRedirectApple: () => void;
26+
popupRedirectFacebook: () => void;
27+
loginGoogle: () => void;
28+
loginApple: () => void;
29+
loginFacebook: () => void;
2430
}>({
2531
imxProvider: undefined,
2632
zkEvmProvider: undefined,
@@ -34,6 +40,12 @@ const PassportContext = createContext<{
3440
getUserInfo: () => Promise.resolve(undefined),
3541
getLinkedAddresses: () => Promise.resolve(undefined),
3642
linkWallet: () => Promise.resolve(undefined),
43+
popupRedirectGoogle: () => undefined,
44+
popupRedirectApple: () => undefined,
45+
popupRedirectFacebook: () => undefined,
46+
loginGoogle: () => undefined,
47+
loginApple: () => undefined,
48+
loginFacebook: () => undefined,
3749
});
3850

3951
export function PassportProvider({
@@ -163,14 +175,109 @@ export function PassportProvider({
163175
}
164176
}, [addMessage, passportClient, setIsLoading]);
165177

178+
// Popup redirect methods (provider-specific)
179+
const popupRedirectGoogle = useCallback(async () => {
180+
try {
181+
setIsLoading(true);
182+
const userProfile = await passportClient.login({ directLoginMethod: 'google' });
183+
addMessage('Popup Login (Google)', userProfile);
184+
} catch (err) {
185+
addMessage('Popup Login (Google)', err);
186+
console.error(err);
187+
} finally {
188+
setIsLoading(false);
189+
}
190+
}, [addMessage, passportClient, setIsLoading]);
191+
192+
const popupRedirectApple = useCallback(async () => {
193+
try {
194+
setIsLoading(true);
195+
const userProfile = await passportClient.login({ directLoginMethod: 'apple' });
196+
addMessage('Popup Login (Apple)', userProfile);
197+
} catch (err) {
198+
addMessage('Popup Login (Apple)', err);
199+
console.error(err);
200+
} finally {
201+
setIsLoading(false);
202+
}
203+
}, [addMessage, passportClient, setIsLoading]);
204+
205+
const popupRedirectFacebook = useCallback(async () => {
206+
try {
207+
setIsLoading(true);
208+
const userProfile = await passportClient.login({ directLoginMethod: 'facebook' });
209+
addMessage('Popup Login (Facebook)', userProfile);
210+
} catch (err) {
211+
addMessage('Popup Login (Facebook)', err);
212+
console.error(err);
213+
} finally {
214+
setIsLoading(false);
215+
}
216+
}, [addMessage, passportClient, setIsLoading]);
217+
218+
// Login (redirect) methods
219+
const loginGoogle = useCallback(async () => {
220+
try {
221+
setIsLoading(true);
222+
const userProfile = await passportClient.login({
223+
directLoginMethod: 'google',
224+
useRedirectFlow: true,
225+
});
226+
addMessage('Login (Google)', userProfile);
227+
} catch (err) {
228+
addMessage('Login (Google)', err);
229+
console.error(err);
230+
} finally {
231+
setIsLoading(false);
232+
}
233+
}, [addMessage, passportClient, setIsLoading]);
234+
235+
const loginApple = useCallback(async () => {
236+
try {
237+
setIsLoading(true);
238+
const userProfile = await passportClient.login({
239+
directLoginMethod: 'apple',
240+
useRedirectFlow: true,
241+
});
242+
addMessage('Login (Apple)', userProfile);
243+
} catch (err) {
244+
addMessage('Login (Apple)', err);
245+
console.error(err);
246+
} finally {
247+
setIsLoading(false);
248+
}
249+
}, [addMessage, passportClient, setIsLoading]);
250+
251+
const loginFacebook = useCallback(async () => {
252+
try {
253+
setIsLoading(true);
254+
const userProfile = await passportClient.login({
255+
directLoginMethod: 'facebook',
256+
useRedirectFlow: true,
257+
});
258+
addMessage('Login (Facebook)', userProfile);
259+
} catch (err) {
260+
addMessage('Login (Facebook)', err);
261+
console.error(err);
262+
} finally {
263+
setIsLoading(false);
264+
}
265+
}, [addMessage, passportClient, setIsLoading]);
266+
166267
const providerValues = useMemo(() => ({
167268
imxProvider,
168269
zkEvmProvider,
169270
connectImx,
170271
connectZkEvm,
171272
logout,
172-
login,
173273
popupRedirect,
274+
popupRedirectGoogle,
275+
popupRedirectApple,
276+
popupRedirectFacebook,
277+
login,
278+
loginGoogle,
279+
loginApple,
280+
loginFacebook,
174281
getIdToken,
175282
getAccessToken,
176283
getUserInfo,
@@ -182,8 +289,14 @@ export function PassportProvider({
182289
connectImx,
183290
connectZkEvm,
184291
logout,
185-
login,
186292
popupRedirect,
293+
popupRedirectGoogle,
294+
popupRedirectApple,
295+
popupRedirectFacebook,
296+
login,
297+
loginGoogle,
298+
loginApple,
299+
loginFacebook,
187300
getIdToken,
188301
getAccessToken,
189302
getUserInfo,
@@ -204,9 +317,15 @@ export function usePassportProvider() {
204317
zkEvmProvider,
205318
connectImx,
206319
connectZkEvm,
207-
login,
208-
popupRedirect,
209320
logout,
321+
popupRedirect,
322+
popupRedirectGoogle,
323+
popupRedirectApple,
324+
popupRedirectFacebook,
325+
login,
326+
loginGoogle,
327+
loginApple,
328+
loginFacebook,
210329
getIdToken,
211330
getAccessToken,
212331
getUserInfo,
@@ -218,9 +337,15 @@ export function usePassportProvider() {
218337
zkEvmProvider,
219338
connectImx,
220339
connectZkEvm,
221-
login,
222-
popupRedirect,
223340
logout,
341+
popupRedirect,
342+
popupRedirectGoogle,
343+
popupRedirectApple,
344+
popupRedirectFacebook,
345+
login,
346+
loginGoogle,
347+
loginApple,
348+
loginFacebook,
224349
getIdToken,
225350
getAccessToken,
226351
getUserInfo,

packages/passport/sdk/src/Passport.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import MagicAdapter from './magic/magicAdapter';
1515
import { PassportImxProviderFactory } from './starkEx';
1616
import { PassportConfiguration } from './config';
1717
import {
18+
DirectLoginMethod,
1819
isUserImx,
1920
isUserZkEvm,
2021
LinkedWallet,
@@ -189,6 +190,8 @@ export class Passport {
189190
* @param {string} [options.anonymousId] - ID used to enrich Passport internal metrics
190191
* @param {boolean} [options.useSilentLogin] - If true, attempts silent authentication without user interaction.
191192
* Note: This takes precedence over useCachedSession if both are true
193+
* @param {boolean} [options.useRedirectFlow] - If true, uses redirect flow instead of popup flow
194+
* @param {DirectLoginMethod} [options.directLoginMethod] - If provided, directly redirects to the specified login method
192195
* @returns {Promise<UserProfile | null>} A promise that resolves to the user profile if logged in, null otherwise
193196
* @throws {Error} If retrieving the cached user session fails (except for "Unknown or invalid refresh token" errors)
194197
* and useCachedSession is true
@@ -198,6 +201,7 @@ export class Passport {
198201
anonymousId?: string;
199202
useSilentLogin?: boolean;
200203
useRedirectFlow?: boolean;
204+
directLoginMethod?: DirectLoginMethod;
201205
}): Promise<UserProfile | null> {
202206
// If there's already a login in progress, return that promise
203207
if (this.#loginPromise) {
@@ -225,9 +229,9 @@ export class Passport {
225229
user = await this.authManager.forceUserRefresh();
226230
} else if (!user && !useCachedSession) {
227231
if (options?.useRedirectFlow) {
228-
await this.authManager.loginWithRedirect(options?.anonymousId);
232+
await this.authManager.loginWithRedirect(options?.anonymousId, options?.directLoginMethod);
229233
} else {
230-
user = await this.authManager.login(options?.anonymousId);
234+
user = await this.authManager.login(options?.anonymousId, options?.directLoginMethod);
231235
}
232236
}
233237

@@ -268,10 +272,11 @@ export class Passport {
268272

269273
/**
270274
* Initiates a PKCE flow login.
275+
* @param {DirectLoginMethod} [directLoginMethod] - If provided, directly redirects to the specified login method
271276
* @returns {string} The authorization URL for the PKCE flow
272277
*/
273-
public loginWithPKCEFlow(): Promise<string> {
274-
return withMetricsAsync(async () => await this.authManager.getPKCEAuthorizationUrl(), 'loginWithPKCEFlow');
278+
public loginWithPKCEFlow(directLoginMethod?: DirectLoginMethod): Promise<string> {
279+
return withMetricsAsync(async () => await this.authManager.getPKCEAuthorizationUrl(directLoginMethod), 'loginWithPKCEFlow');
275280
}
276281

277282
/**

0 commit comments

Comments
 (0)