@imtbl/auth 2.10.7-alpha.2 → 2.10.7-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.js +391 -0
- package/dist/node/index.cjs +411 -0
- package/dist/node/index.js +33 -57
- package/dist/types/Auth.d.ts +136 -0
- package/dist/types/authManager.d.ts +3 -4
- package/dist/types/index.d.ts +4 -5
- package/dist/types/{confirmation → login}/embeddedLoginPrompt.d.ts +1 -1
- package/dist/types/overlay/{confirmationOverlay.d.ts → loginPopupOverlay.d.ts} +1 -1
- package/dist/types/types.d.ts +27 -0
- package/dist/types/utils/typedEventEmitter.d.ts +6 -0
- package/package.json +19 -13
- package/src/Auth.ts +252 -0
- package/src/authManager.ts +10 -12
- package/src/index.ts +9 -6
- package/src/{confirmation → login}/embeddedLoginPrompt.ts +6 -10
- package/src/overlay/{confirmationOverlay.ts → loginPopupOverlay.ts} +1 -1
- package/src/types.ts +30 -0
- package/src/utils/typedEventEmitter.ts +26 -0
- package/dist/browser/index.mjs +0 -397
- package/dist/node/index.mjs +0 -397
- package/dist/types/confirmation/confirmation.d.ts +0 -28
- package/dist/types/confirmation/index.d.ts +0 -3
- package/dist/types/confirmation/popup.d.ts +0 -8
- package/src/confirmation/confirmation.ts +0 -275
- package/src/confirmation/index.ts +0 -3
- package/src/confirmation/popup.ts +0 -41
- /package/dist/types/{confirmation → login}/types.d.ts +0 -0
- /package/src/{confirmation → login}/types.ts +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import AuthManager from './authManager';
|
|
2
|
+
import { IAuthConfiguration } from './config';
|
|
3
|
+
import { AuthModuleConfiguration, User, DirectLoginOptions, DeviceTokenResponse, LoginOptions, AuthEventMap } from './types';
|
|
4
|
+
import TypedEventEmitter from './utils/typedEventEmitter';
|
|
5
|
+
/**
|
|
6
|
+
* Public-facing Auth class for authentication
|
|
7
|
+
* Wraps AuthManager with a simpler API
|
|
8
|
+
*/
|
|
9
|
+
export declare class Auth {
|
|
10
|
+
private authManager;
|
|
11
|
+
private config;
|
|
12
|
+
/**
|
|
13
|
+
* Event emitter for authentication events (LOGGED_IN, LOGGED_OUT)
|
|
14
|
+
* Exposed for wallet and passport packages to subscribe to auth state changes
|
|
15
|
+
*/
|
|
16
|
+
readonly eventEmitter: TypedEventEmitter<AuthEventMap>;
|
|
17
|
+
/**
|
|
18
|
+
* Create a new Auth instance
|
|
19
|
+
*
|
|
20
|
+
* @param config - Auth configuration
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { Auth } from '@imtbl/auth';
|
|
25
|
+
*
|
|
26
|
+
* const auth = new Auth({
|
|
27
|
+
* authenticationDomain: 'https://auth.immutable.com',
|
|
28
|
+
* passportDomain: 'https://passport.immutable.com',
|
|
29
|
+
* clientId: 'your-client-id',
|
|
30
|
+
* redirectUri: 'https://your-app.com/callback',
|
|
31
|
+
* scope: 'openid profile email transact',
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
constructor(config: AuthModuleConfiguration);
|
|
36
|
+
/**
|
|
37
|
+
* Login with popup
|
|
38
|
+
* Opens a popup window for authentication
|
|
39
|
+
* @param directLoginOptions - Optional direct login options
|
|
40
|
+
* @returns Promise that resolves with the authenticated user
|
|
41
|
+
*/
|
|
42
|
+
login(directLoginOptions?: DirectLoginOptions): Promise<User>;
|
|
43
|
+
/**
|
|
44
|
+
* Login with redirect
|
|
45
|
+
* Redirects the page for authentication
|
|
46
|
+
* @param directLoginOptions - Optional direct login options
|
|
47
|
+
* @returns Promise that resolves when redirect is initiated
|
|
48
|
+
*/
|
|
49
|
+
loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Enhanced login method with extended options
|
|
52
|
+
* Supports cached sessions, silent login, and redirect flow
|
|
53
|
+
* @param options - Extended login options
|
|
54
|
+
* @returns Promise that resolves with the user or null
|
|
55
|
+
*/
|
|
56
|
+
loginWithOptions(options?: LoginOptions): Promise<User | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Login callback handler
|
|
59
|
+
* Call this in your redirect URI page
|
|
60
|
+
* @returns Promise that resolves with the authenticated user
|
|
61
|
+
*/
|
|
62
|
+
loginCallback(): Promise<User>;
|
|
63
|
+
/**
|
|
64
|
+
* Logout the current user
|
|
65
|
+
* @returns Promise that resolves when logout is complete
|
|
66
|
+
*/
|
|
67
|
+
logout(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Get the current authenticated user
|
|
70
|
+
* @returns Promise that resolves with the user or null if not authenticated
|
|
71
|
+
*/
|
|
72
|
+
getUser(): Promise<User | null>;
|
|
73
|
+
/**
|
|
74
|
+
* Get the ID token for the current user
|
|
75
|
+
* @returns Promise that resolves with the ID token or undefined
|
|
76
|
+
*/
|
|
77
|
+
getIdToken(): Promise<string | undefined>;
|
|
78
|
+
/**
|
|
79
|
+
* Get the access token for the current user
|
|
80
|
+
* @returns Promise that resolves with the access token or undefined
|
|
81
|
+
*/
|
|
82
|
+
getAccessToken(): Promise<string | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* Check if user is logged in
|
|
85
|
+
* @returns Promise that resolves with true if user is logged in
|
|
86
|
+
*/
|
|
87
|
+
isLoggedIn(): Promise<boolean>;
|
|
88
|
+
/**
|
|
89
|
+
* Force a silent user refresh (for silent login)
|
|
90
|
+
* @returns Promise that resolves with the user or null if refresh fails
|
|
91
|
+
*/
|
|
92
|
+
forceUserRefresh(): Promise<User | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Get the PKCE authorization URL for login flow
|
|
95
|
+
* @param directLoginOptions - Optional direct login options
|
|
96
|
+
* @param imPassportTraceId - Optional trace ID for tracking
|
|
97
|
+
* @returns Promise that resolves with the authorization URL
|
|
98
|
+
*/
|
|
99
|
+
loginWithPKCEFlow(directLoginOptions?: DirectLoginOptions, imPassportTraceId?: string): Promise<string>;
|
|
100
|
+
/**
|
|
101
|
+
* Handle the PKCE login callback
|
|
102
|
+
* @param authorizationCode - The authorization code from the OAuth provider
|
|
103
|
+
* @param state - The state parameter for CSRF protection
|
|
104
|
+
* @returns Promise that resolves with the authenticated user
|
|
105
|
+
*/
|
|
106
|
+
loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User>;
|
|
107
|
+
/**
|
|
108
|
+
* Store tokens from device flow and retrieve user
|
|
109
|
+
* @param tokenResponse - The token response from device flow
|
|
110
|
+
* @returns Promise that resolves with the authenticated user
|
|
111
|
+
*/
|
|
112
|
+
storeTokens(tokenResponse: DeviceTokenResponse): Promise<User>;
|
|
113
|
+
/**
|
|
114
|
+
* Get the logout URL
|
|
115
|
+
* @returns Promise that resolves with the logout URL or undefined if not available
|
|
116
|
+
*/
|
|
117
|
+
getLogoutUrl(): Promise<string | undefined>;
|
|
118
|
+
/**
|
|
119
|
+
* Handle the silent logout callback
|
|
120
|
+
* @param url - The URL containing logout information
|
|
121
|
+
* @returns Promise that resolves when callback is handled
|
|
122
|
+
*/
|
|
123
|
+
logoutSilentCallback(url: string): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Get internal AuthManager instance
|
|
126
|
+
* @internal
|
|
127
|
+
* @returns AuthManager instance for advanced use cases
|
|
128
|
+
*/
|
|
129
|
+
getAuthManager(): AuthManager;
|
|
130
|
+
/**
|
|
131
|
+
* Get auth configuration
|
|
132
|
+
* @internal
|
|
133
|
+
* @returns IAuthConfiguration instance
|
|
134
|
+
*/
|
|
135
|
+
getConfig(): IAuthConfiguration;
|
|
136
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DirectLoginOptions, User, DeviceTokenResponse, UserZkEvm, UserImx } from './types';
|
|
2
2
|
import { IAuthConfiguration } from './config';
|
|
3
|
-
import
|
|
3
|
+
import EmbeddedLoginPrompt from './login/embeddedLoginPrompt';
|
|
4
4
|
export default class AuthManager {
|
|
5
5
|
private userManager;
|
|
6
6
|
private deviceCredentialsManager;
|
|
@@ -15,16 +15,15 @@ export default class AuthManager {
|
|
|
15
15
|
private static mapOidcUserToDomainModel;
|
|
16
16
|
private static mapDeviceTokenResponseToOidcUser;
|
|
17
17
|
private buildExtraQueryParams;
|
|
18
|
-
loginWithRedirect(
|
|
18
|
+
loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void>;
|
|
19
19
|
/**
|
|
20
20
|
* login
|
|
21
|
-
* @param anonymousId Caller can pass an anonymousId if they want to associate their user's identity with immutable's internal instrumentation.
|
|
22
21
|
* @param directLoginOptions If provided, contains login method and marketing consent options
|
|
23
22
|
* @param directLoginOptions.directLoginMethod The login method to use (e.g., 'google', 'apple', 'email')
|
|
24
23
|
* @param directLoginOptions.marketingConsentStatus Marketing consent status ('opted_in' or 'unsubscribed')
|
|
25
24
|
* @param directLoginOptions.email Required when directLoginMethod is 'email'
|
|
26
25
|
*/
|
|
27
|
-
login(
|
|
26
|
+
login(directLoginOptions?: DirectLoginOptions): Promise<User>;
|
|
28
27
|
getUserOrLogin(): Promise<User>;
|
|
29
28
|
private static shouldUseSigninPopupCallback;
|
|
30
29
|
loginCallback(): Promise<undefined | User>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
export { Auth } from './Auth';
|
|
1
2
|
export { default as AuthManager } from './authManager';
|
|
2
3
|
export { AuthConfiguration, type IAuthConfiguration } from './config';
|
|
3
|
-
export type { User, UserProfile, UserImx, UserZkEvm, DirectLoginMethod, DirectLoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, IdTokenPayload, PKCEData, } from './types';
|
|
4
|
-
export { isUserZkEvm, isUserImx, RollupType, MarketingConsentStatus, } from './types';
|
|
4
|
+
export type { User, UserProfile, UserImx, UserZkEvm, DirectLoginMethod, DirectLoginOptions, LoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, IdTokenPayload, PKCEData, AuthEventMap, } from './types';
|
|
5
|
+
export { isUserZkEvm, isUserImx, RollupType, MarketingConsentStatus, AuthEvents, } from './types';
|
|
6
|
+
export { default as TypedEventEmitter } from './utils/typedEventEmitter';
|
|
5
7
|
export { PassportError, PassportErrorType, withPassportError } from './errors';
|
|
6
|
-
export { default as ConfirmationScreen } from './confirmation/confirmation';
|
|
7
|
-
export { default as EmbeddedLoginPrompt } from './confirmation/embeddedLoginPrompt';
|
|
8
|
-
export { default as ConfirmationOverlay } from './overlay/confirmationOverlay';
|
|
@@ -6,5 +6,5 @@ export default class EmbeddedLoginPrompt {
|
|
|
6
6
|
private getHref;
|
|
7
7
|
private static appendIFrameStylesIfNeeded;
|
|
8
8
|
private getEmbeddedLoginIFrame;
|
|
9
|
-
displayEmbeddedLoginPrompt(
|
|
9
|
+
displayEmbeddedLoginPrompt(): Promise<EmbeddedLoginPromptResult>;
|
|
10
10
|
}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -109,4 +109,31 @@ export type DirectLoginOptions = {
|
|
|
109
109
|
marketingConsentStatus?: MarketingConsentStatus;
|
|
110
110
|
email?: string;
|
|
111
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Extended login options with caching and silent login support
|
|
114
|
+
*/
|
|
115
|
+
export type LoginOptions = {
|
|
116
|
+
/** If true, attempts to use cached session without user interaction */
|
|
117
|
+
useCachedSession?: boolean;
|
|
118
|
+
/** If true, attempts silent authentication (force token refresh) */
|
|
119
|
+
useSilentLogin?: boolean;
|
|
120
|
+
/** If true, uses redirect flow instead of popup flow */
|
|
121
|
+
useRedirectFlow?: boolean;
|
|
122
|
+
/** Direct login options (social provider, email, etc.) */
|
|
123
|
+
directLoginOptions?: DirectLoginOptions;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Authentication events emitted by the Auth class
|
|
127
|
+
*/
|
|
128
|
+
export declare enum AuthEvents {
|
|
129
|
+
LOGGED_OUT = "loggedOut",
|
|
130
|
+
LOGGED_IN = "loggedIn"
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Event map for typed event emitter
|
|
134
|
+
*/
|
|
135
|
+
export interface AuthEventMap extends Record<string, any> {
|
|
136
|
+
[AuthEvents.LOGGED_OUT]: [];
|
|
137
|
+
[AuthEvents.LOGGED_IN]: [User];
|
|
138
|
+
}
|
|
112
139
|
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export default class TypedEventEmitter<TEvents extends Record<string, any>> {
|
|
2
|
+
private emitter;
|
|
3
|
+
emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]): void;
|
|
4
|
+
on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void): void;
|
|
5
|
+
removeListener<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void): void;
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/auth",
|
|
3
|
-
"version": "2.10.7-alpha.
|
|
3
|
+
"version": "2.10.7-alpha.4",
|
|
4
4
|
"description": "Authentication SDK for Immutable",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
7
7
|
"homepage": "https://github.com/immutable/ts-immutable-sdk#readme",
|
|
8
8
|
"license": "Apache-2.0",
|
|
9
|
-
"main": "dist/node/index.
|
|
10
|
-
"module": "dist/node/index.
|
|
11
|
-
"
|
|
9
|
+
"main": "dist/node/index.cjs",
|
|
10
|
+
"module": "dist/node/index.js",
|
|
11
|
+
"browser": "dist/browser/index.js",
|
|
12
|
+
"types": "./dist/types/index.d.ts",
|
|
12
13
|
"exports": {
|
|
13
|
-
"
|
|
14
|
+
"development": {
|
|
15
|
+
"types": "./src/index.ts",
|
|
16
|
+
"browser": "./dist/browser/index.js",
|
|
17
|
+
"require": "./dist/node/index.cjs",
|
|
18
|
+
"default": "./dist/node/index.js"
|
|
19
|
+
},
|
|
20
|
+
"default": {
|
|
14
21
|
"types": "./dist/types/index.d.ts",
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
"require": "./dist/node/index.js"
|
|
22
|
+
"browser": "./dist/browser/index.js",
|
|
23
|
+
"require": "./dist/node/index.cjs",
|
|
24
|
+
"default": "./dist/node/index.js"
|
|
20
25
|
}
|
|
21
26
|
},
|
|
22
27
|
"dependencies": {
|
|
23
|
-
"@imtbl/config": "2.10.7-alpha.
|
|
24
|
-
"@imtbl/metrics": "2.10.7-alpha.
|
|
28
|
+
"@imtbl/config": "2.10.7-alpha.4",
|
|
29
|
+
"@imtbl/metrics": "2.10.7-alpha.4",
|
|
25
30
|
"axios": "^1.6.5",
|
|
26
31
|
"jwt-decode": "^3.1.2",
|
|
27
32
|
"localforage": "^1.10.0",
|
|
@@ -29,7 +34,7 @@
|
|
|
29
34
|
"uuid": "^9.0.1"
|
|
30
35
|
},
|
|
31
36
|
"devDependencies": {
|
|
32
|
-
"@imtbl/toolkit": "2.10.7-alpha.
|
|
37
|
+
"@imtbl/toolkit": "2.10.7-alpha.4",
|
|
33
38
|
"@types/node": "^18.14.2",
|
|
34
39
|
"tsup": "^8.3.0",
|
|
35
40
|
"typescript": "^5.6.2"
|
|
@@ -38,6 +43,7 @@
|
|
|
38
43
|
"access": "public"
|
|
39
44
|
},
|
|
40
45
|
"repository": "immutable/ts-immutable-sdk.git",
|
|
46
|
+
"type": "module",
|
|
41
47
|
"scripts": {
|
|
42
48
|
"build": "pnpm transpile && pnpm typegen",
|
|
43
49
|
"transpile": "tsup src/index.ts --config ../../tsup.config.js",
|
package/src/Auth.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import AuthManager from './authManager';
|
|
2
|
+
import { AuthConfiguration, IAuthConfiguration } from './config';
|
|
3
|
+
import {
|
|
4
|
+
AuthModuleConfiguration, User, DirectLoginOptions, DeviceTokenResponse, LoginOptions, AuthEventMap, AuthEvents,
|
|
5
|
+
} from './types';
|
|
6
|
+
import EmbeddedLoginPrompt from './login/embeddedLoginPrompt';
|
|
7
|
+
import TypedEventEmitter from './utils/typedEventEmitter';
|
|
8
|
+
import { identify, track } from '@imtbl/metrics';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Public-facing Auth class for authentication
|
|
12
|
+
* Wraps AuthManager with a simpler API
|
|
13
|
+
*/
|
|
14
|
+
export class Auth {
|
|
15
|
+
private authManager: AuthManager;
|
|
16
|
+
|
|
17
|
+
private config: IAuthConfiguration;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Event emitter for authentication events (LOGGED_IN, LOGGED_OUT)
|
|
21
|
+
* Exposed for wallet and passport packages to subscribe to auth state changes
|
|
22
|
+
*/
|
|
23
|
+
public readonly eventEmitter: TypedEventEmitter<AuthEventMap>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a new Auth instance
|
|
27
|
+
*
|
|
28
|
+
* @param config - Auth configuration
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { Auth } from '@imtbl/auth';
|
|
33
|
+
*
|
|
34
|
+
* const auth = new Auth({
|
|
35
|
+
* authenticationDomain: 'https://auth.immutable.com',
|
|
36
|
+
* passportDomain: 'https://passport.immutable.com',
|
|
37
|
+
* clientId: 'your-client-id',
|
|
38
|
+
* redirectUri: 'https://your-app.com/callback',
|
|
39
|
+
* scope: 'openid profile email transact',
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
constructor(config: AuthModuleConfiguration) {
|
|
44
|
+
this.config = new AuthConfiguration(config);
|
|
45
|
+
const embeddedLoginPrompt = new EmbeddedLoginPrompt(this.config);
|
|
46
|
+
this.authManager = new AuthManager(this.config, embeddedLoginPrompt);
|
|
47
|
+
this.eventEmitter = new TypedEventEmitter<AuthEventMap>();
|
|
48
|
+
track('passport', 'initialise');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Login with popup
|
|
53
|
+
* Opens a popup window for authentication
|
|
54
|
+
* @param directLoginOptions - Optional direct login options
|
|
55
|
+
* @returns Promise that resolves with the authenticated user
|
|
56
|
+
*/
|
|
57
|
+
async login(directLoginOptions?: DirectLoginOptions): Promise<User> {
|
|
58
|
+
return this.authManager.login(directLoginOptions);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Login with redirect
|
|
63
|
+
* Redirects the page for authentication
|
|
64
|
+
* @param directLoginOptions - Optional direct login options
|
|
65
|
+
* @returns Promise that resolves when redirect is initiated
|
|
66
|
+
*/
|
|
67
|
+
async loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void> {
|
|
68
|
+
await this.authManager.loginWithRedirect(directLoginOptions);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Enhanced login method with extended options
|
|
73
|
+
* Supports cached sessions, silent login, and redirect flow
|
|
74
|
+
* @param options - Extended login options
|
|
75
|
+
* @returns Promise that resolves with the user or null
|
|
76
|
+
*/
|
|
77
|
+
async loginWithOptions(options?: LoginOptions): Promise<User | null> {
|
|
78
|
+
const { useCachedSession = false, useSilentLogin } = options || {};
|
|
79
|
+
let user: User | null = null;
|
|
80
|
+
|
|
81
|
+
// Try to get cached user
|
|
82
|
+
try {
|
|
83
|
+
user = await this.authManager.getUser();
|
|
84
|
+
} catch (error: any) {
|
|
85
|
+
if (useCachedSession) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
// Silently ignore errors if not requiring cached session
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If no cached user, try silent login or regular login
|
|
92
|
+
if (!user && useSilentLogin) {
|
|
93
|
+
user = await this.authManager.forceUserRefresh();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!user && !useCachedSession) {
|
|
97
|
+
if (options?.useRedirectFlow) {
|
|
98
|
+
await this.authManager.loginWithRedirect(options?.directLoginOptions);
|
|
99
|
+
return null; // Redirect doesn't return user immediately
|
|
100
|
+
}
|
|
101
|
+
user = await this.authManager.login(options?.directLoginOptions);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Emit LOGGED_IN event and identify user if logged in
|
|
105
|
+
if (user) {
|
|
106
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
107
|
+
identify({ passportId: user.profile.sub });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return user;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Login callback handler
|
|
115
|
+
* Call this in your redirect URI page
|
|
116
|
+
* @returns Promise that resolves with the authenticated user
|
|
117
|
+
*/
|
|
118
|
+
async loginCallback(): Promise<User> {
|
|
119
|
+
const user = await this.authManager.loginCallback();
|
|
120
|
+
if (!user) {
|
|
121
|
+
throw new Error('Login callback failed - no user returned');
|
|
122
|
+
}
|
|
123
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
124
|
+
identify({ passportId: user.profile.sub });
|
|
125
|
+
return user;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Logout the current user
|
|
130
|
+
* @returns Promise that resolves when logout is complete
|
|
131
|
+
*/
|
|
132
|
+
async logout(): Promise<void> {
|
|
133
|
+
await this.authManager.logout();
|
|
134
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_OUT);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the current authenticated user
|
|
139
|
+
* @returns Promise that resolves with the user or null if not authenticated
|
|
140
|
+
*/
|
|
141
|
+
async getUser(): Promise<User | null> {
|
|
142
|
+
return this.authManager.getUser();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get the ID token for the current user
|
|
147
|
+
* @returns Promise that resolves with the ID token or undefined
|
|
148
|
+
*/
|
|
149
|
+
async getIdToken(): Promise<string | undefined> {
|
|
150
|
+
const user = await this.authManager.getUser();
|
|
151
|
+
return user?.idToken;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get the access token for the current user
|
|
156
|
+
* @returns Promise that resolves with the access token or undefined
|
|
157
|
+
*/
|
|
158
|
+
async getAccessToken(): Promise<string | undefined> {
|
|
159
|
+
const user = await this.authManager.getUser();
|
|
160
|
+
return user?.accessToken;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if user is logged in
|
|
165
|
+
* @returns Promise that resolves with true if user is logged in
|
|
166
|
+
*/
|
|
167
|
+
async isLoggedIn(): Promise<boolean> {
|
|
168
|
+
const user = await this.getUser();
|
|
169
|
+
return user !== null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Force a silent user refresh (for silent login)
|
|
174
|
+
* @returns Promise that resolves with the user or null if refresh fails
|
|
175
|
+
*/
|
|
176
|
+
async forceUserRefresh(): Promise<User | null> {
|
|
177
|
+
return this.authManager.forceUserRefresh();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get the PKCE authorization URL for login flow
|
|
182
|
+
* @param directLoginOptions - Optional direct login options
|
|
183
|
+
* @param imPassportTraceId - Optional trace ID for tracking
|
|
184
|
+
* @returns Promise that resolves with the authorization URL
|
|
185
|
+
*/
|
|
186
|
+
async loginWithPKCEFlow(directLoginOptions?: DirectLoginOptions, imPassportTraceId?: string): Promise<string> {
|
|
187
|
+
return this.authManager.getPKCEAuthorizationUrl(directLoginOptions, imPassportTraceId);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Handle the PKCE login callback
|
|
192
|
+
* @param authorizationCode - The authorization code from the OAuth provider
|
|
193
|
+
* @param state - The state parameter for CSRF protection
|
|
194
|
+
* @returns Promise that resolves with the authenticated user
|
|
195
|
+
*/
|
|
196
|
+
async loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User> {
|
|
197
|
+
const user = await this.authManager.loginWithPKCEFlowCallback(authorizationCode, state);
|
|
198
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
199
|
+
identify({ passportId: user.profile.sub });
|
|
200
|
+
return user;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Store tokens from device flow and retrieve user
|
|
205
|
+
* @param tokenResponse - The token response from device flow
|
|
206
|
+
* @returns Promise that resolves with the authenticated user
|
|
207
|
+
*/
|
|
208
|
+
async storeTokens(tokenResponse: DeviceTokenResponse): Promise<User> {
|
|
209
|
+
const user = await this.authManager.storeTokens(tokenResponse);
|
|
210
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
211
|
+
identify({ passportId: user.profile.sub });
|
|
212
|
+
return user;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get the logout URL
|
|
217
|
+
* @returns Promise that resolves with the logout URL or undefined if not available
|
|
218
|
+
*/
|
|
219
|
+
async getLogoutUrl(): Promise<string | undefined> {
|
|
220
|
+
await this.authManager.removeUser();
|
|
221
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_OUT);
|
|
222
|
+
const url = await this.authManager.getLogoutUrl();
|
|
223
|
+
return url || undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Handle the silent logout callback
|
|
228
|
+
* @param url - The URL containing logout information
|
|
229
|
+
* @returns Promise that resolves when callback is handled
|
|
230
|
+
*/
|
|
231
|
+
async logoutSilentCallback(url: string): Promise<void> {
|
|
232
|
+
return this.authManager.logoutSilentCallback(url);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get internal AuthManager instance
|
|
237
|
+
* @internal
|
|
238
|
+
* @returns AuthManager instance for advanced use cases
|
|
239
|
+
*/
|
|
240
|
+
getAuthManager(): AuthManager {
|
|
241
|
+
return this.authManager;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get auth configuration
|
|
246
|
+
* @internal
|
|
247
|
+
* @returns IAuthConfiguration instance
|
|
248
|
+
*/
|
|
249
|
+
getConfig(): IAuthConfiguration {
|
|
250
|
+
return this.config;
|
|
251
|
+
}
|
|
252
|
+
}
|
package/src/authManager.ts
CHANGED
|
@@ -28,9 +28,9 @@ import {
|
|
|
28
28
|
isUserImx,
|
|
29
29
|
} from './types';
|
|
30
30
|
import { IAuthConfiguration } from './config';
|
|
31
|
-
import
|
|
31
|
+
import LoginPopupOverlay from './overlay/loginPopupOverlay';
|
|
32
|
+
import EmbeddedLoginPrompt from './login/embeddedLoginPrompt';
|
|
32
33
|
import { LocalForageAsyncStorage } from './storage/LocalForageAsyncStorage';
|
|
33
|
-
import { EmbeddedLoginPrompt } from './confirmation';
|
|
34
34
|
|
|
35
35
|
const LOGIN_POPUP_CLOSED_POLLING_DURATION = 500;
|
|
36
36
|
|
|
@@ -94,7 +94,7 @@ const getAuthConfiguration = (config: IAuthConfiguration): UserManagerSettings =
|
|
|
94
94
|
return baseConfiguration;
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
function base64URLEncode(str: ArrayBuffer) {
|
|
97
|
+
function base64URLEncode(str: ArrayBuffer | Uint8Array) {
|
|
98
98
|
return btoa(String.fromCharCode(...new Uint8Array(str)))
|
|
99
99
|
.replace(/\+/g, '-')
|
|
100
100
|
.replace(/\//g, '_')
|
|
@@ -186,14 +186,13 @@ export default class AuthManager {
|
|
|
186
186
|
};
|
|
187
187
|
|
|
188
188
|
private buildExtraQueryParams(
|
|
189
|
-
anonymousId?: string,
|
|
190
189
|
directLoginOptions?: DirectLoginOptions,
|
|
191
190
|
imPassportTraceId?: string,
|
|
192
191
|
): Record<string, string> {
|
|
193
192
|
const params: Record<string, string> = {
|
|
194
193
|
...(this.userManager.settings?.extraQueryParams ?? {}),
|
|
195
194
|
rid: getDetail(Detail.RUNTIME_ID) || '',
|
|
196
|
-
third_party_a_id:
|
|
195
|
+
third_party_a_id: '',
|
|
197
196
|
};
|
|
198
197
|
|
|
199
198
|
if (directLoginOptions) {
|
|
@@ -221,10 +220,10 @@ export default class AuthManager {
|
|
|
221
220
|
return params;
|
|
222
221
|
}
|
|
223
222
|
|
|
224
|
-
public async loginWithRedirect(
|
|
223
|
+
public async loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void> {
|
|
225
224
|
await this.userManager.clearStaleState();
|
|
226
225
|
return withPassportError<void>(async () => {
|
|
227
|
-
const extraQueryParams = this.buildExtraQueryParams(
|
|
226
|
+
const extraQueryParams = this.buildExtraQueryParams(directLoginOptions);
|
|
228
227
|
|
|
229
228
|
await this.userManager.signinRedirect({
|
|
230
229
|
extraQueryParams,
|
|
@@ -234,13 +233,12 @@ export default class AuthManager {
|
|
|
234
233
|
|
|
235
234
|
/**
|
|
236
235
|
* login
|
|
237
|
-
* @param anonymousId Caller can pass an anonymousId if they want to associate their user's identity with immutable's internal instrumentation.
|
|
238
236
|
* @param directLoginOptions If provided, contains login method and marketing consent options
|
|
239
237
|
* @param directLoginOptions.directLoginMethod The login method to use (e.g., 'google', 'apple', 'email')
|
|
240
238
|
* @param directLoginOptions.marketingConsentStatus Marketing consent status ('opted_in' or 'unsubscribed')
|
|
241
239
|
* @param directLoginOptions.email Required when directLoginMethod is 'email'
|
|
242
240
|
*/
|
|
243
|
-
public async login(
|
|
241
|
+
public async login(directLoginOptions?: DirectLoginOptions): Promise<User> {
|
|
244
242
|
return withPassportError<User>(async () => {
|
|
245
243
|
// If directLoginOptions are provided, then the consumer has rendered their own initial login screen.
|
|
246
244
|
// If not, display the embedded login prompt and pass the returned direct login options and imPassportTraceId to the login popup.
|
|
@@ -252,14 +250,14 @@ export default class AuthManager {
|
|
|
252
250
|
const {
|
|
253
251
|
imPassportTraceId: embeddedLoginPromptImPassportTraceId,
|
|
254
252
|
...embeddedLoginPromptDirectLoginOptions
|
|
255
|
-
} = await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt(
|
|
253
|
+
} = await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt();
|
|
256
254
|
directLoginOptionsToUse = embeddedLoginPromptDirectLoginOptions;
|
|
257
255
|
imPassportTraceId = embeddedLoginPromptImPassportTraceId;
|
|
258
256
|
}
|
|
259
257
|
|
|
260
258
|
const popupWindowTarget = window.crypto.randomUUID();
|
|
261
259
|
const signinPopup = async () => {
|
|
262
|
-
const extraQueryParams = this.buildExtraQueryParams(
|
|
260
|
+
const extraQueryParams = this.buildExtraQueryParams(directLoginOptionsToUse, imPassportTraceId);
|
|
263
261
|
|
|
264
262
|
const userPromise = this.userManager.signinPopup({
|
|
265
263
|
extraQueryParams,
|
|
@@ -316,7 +314,7 @@ export default class AuthManager {
|
|
|
316
314
|
|
|
317
315
|
// Popup was blocked; append the blocked popup overlay to allow the user to try again.
|
|
318
316
|
let popupHasBeenOpened: boolean = false;
|
|
319
|
-
const overlay = new
|
|
317
|
+
const overlay = new LoginPopupOverlay(this.config.popupOverlayOptions || {}, true);
|
|
320
318
|
overlay.append(
|
|
321
319
|
async () => {
|
|
322
320
|
try {
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Export Auth class (public API)
|
|
2
|
+
export { Auth } from './Auth';
|
|
3
|
+
|
|
1
4
|
// Export AuthManager for use by other packages
|
|
2
5
|
export { default as AuthManager } from './authManager';
|
|
3
6
|
|
|
@@ -12,6 +15,7 @@ export type {
|
|
|
12
15
|
UserZkEvm,
|
|
13
16
|
DirectLoginMethod,
|
|
14
17
|
DirectLoginOptions,
|
|
18
|
+
LoginOptions,
|
|
15
19
|
DeviceTokenResponse,
|
|
16
20
|
OidcConfiguration,
|
|
17
21
|
AuthModuleConfiguration,
|
|
@@ -19,15 +23,14 @@ export type {
|
|
|
19
23
|
PassportMetadata,
|
|
20
24
|
IdTokenPayload,
|
|
21
25
|
PKCEData,
|
|
26
|
+
AuthEventMap,
|
|
22
27
|
} from './types';
|
|
23
28
|
export {
|
|
24
|
-
isUserZkEvm, isUserImx, RollupType, MarketingConsentStatus,
|
|
29
|
+
isUserZkEvm, isUserImx, RollupType, MarketingConsentStatus, AuthEvents,
|
|
25
30
|
} from './types';
|
|
26
31
|
|
|
32
|
+
// Export TypedEventEmitter
|
|
33
|
+
export { default as TypedEventEmitter } from './utils/typedEventEmitter';
|
|
34
|
+
|
|
27
35
|
// Export errors
|
|
28
36
|
export { PassportError, PassportErrorType, withPassportError } from './errors';
|
|
29
|
-
|
|
30
|
-
// Export confirmation and overlay classes
|
|
31
|
-
export { default as ConfirmationScreen } from './confirmation/confirmation';
|
|
32
|
-
export { default as EmbeddedLoginPrompt } from './confirmation/embeddedLoginPrompt';
|
|
33
|
-
export { default as ConfirmationOverlay } from './overlay/confirmationOverlay';
|