@imtbl/auth 2.10.7-alpha.3 → 2.10.7-alpha.5
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 +31 -37
- package/dist/node/index.cjs +44 -50
- package/dist/node/index.js +32 -37
- package/dist/types/Auth.d.ts +129 -0
- package/dist/types/authManager.d.ts +5 -6
- 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 +36 -16
- package/dist/types/utils/metrics.d.ts +2 -0
- package/dist/types/utils/typedEventEmitter.d.ts +6 -0
- package/package.json +4 -4
- package/src/Auth.ts +264 -0
- package/src/authManager.ts +17 -33
- package/src/index.ts +9 -7
- package/src/{confirmation → login}/embeddedLoginPrompt.ts +6 -10
- package/src/overlay/{confirmationOverlay.ts → loginPopupOverlay.ts} +1 -1
- package/src/types.ts +36 -16
- package/src/utils/metrics.ts +29 -0
- package/src/utils/typedEventEmitter.ts +26 -0
- 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,129 @@
|
|
|
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 the user with extended options
|
|
38
|
+
* Supports cached sessions, silent login, redirect flow, and direct login
|
|
39
|
+
* @param options - Extended login options
|
|
40
|
+
* @returns Promise that resolves with the user or null
|
|
41
|
+
*/
|
|
42
|
+
login(options?: LoginOptions): Promise<User | null>;
|
|
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
|
+
* Login callback handler
|
|
52
|
+
* Call this in your redirect URI page
|
|
53
|
+
* @returns Promise that resolves with the authenticated user
|
|
54
|
+
*/
|
|
55
|
+
loginCallback(): Promise<User>;
|
|
56
|
+
/**
|
|
57
|
+
* Logout the current user
|
|
58
|
+
* @returns Promise that resolves when logout is complete
|
|
59
|
+
*/
|
|
60
|
+
logout(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the current authenticated user
|
|
63
|
+
* @returns Promise that resolves with the user or null if not authenticated
|
|
64
|
+
*/
|
|
65
|
+
getUser(): Promise<User | null>;
|
|
66
|
+
/**
|
|
67
|
+
* Get the ID token for the current user
|
|
68
|
+
* @returns Promise that resolves with the ID token or undefined
|
|
69
|
+
*/
|
|
70
|
+
getIdToken(): Promise<string | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Get the access token for the current user
|
|
73
|
+
* @returns Promise that resolves with the access token or undefined
|
|
74
|
+
*/
|
|
75
|
+
getAccessToken(): Promise<string | undefined>;
|
|
76
|
+
/**
|
|
77
|
+
* Check if user is logged in
|
|
78
|
+
* @returns Promise that resolves with true if user is logged in
|
|
79
|
+
*/
|
|
80
|
+
isLoggedIn(): Promise<boolean>;
|
|
81
|
+
/**
|
|
82
|
+
* Force a silent user refresh (for silent login)
|
|
83
|
+
* @returns Promise that resolves with the user or null if refresh fails
|
|
84
|
+
*/
|
|
85
|
+
forceUserRefresh(): Promise<User | null>;
|
|
86
|
+
/**
|
|
87
|
+
* Get the PKCE authorization URL for login flow
|
|
88
|
+
* @param directLoginOptions - Optional direct login options
|
|
89
|
+
* @param imPassportTraceId - Optional trace ID for tracking
|
|
90
|
+
* @returns Promise that resolves with the authorization URL
|
|
91
|
+
*/
|
|
92
|
+
loginWithPKCEFlow(directLoginOptions?: DirectLoginOptions, imPassportTraceId?: string): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Handle the PKCE login callback
|
|
95
|
+
* @param authorizationCode - The authorization code from the OAuth provider
|
|
96
|
+
* @param state - The state parameter for CSRF protection
|
|
97
|
+
* @returns Promise that resolves with the authenticated user
|
|
98
|
+
*/
|
|
99
|
+
loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User>;
|
|
100
|
+
/**
|
|
101
|
+
* Store tokens from device flow and retrieve user
|
|
102
|
+
* @param tokenResponse - The token response from device flow
|
|
103
|
+
* @returns Promise that resolves with the authenticated user
|
|
104
|
+
*/
|
|
105
|
+
storeTokens(tokenResponse: DeviceTokenResponse): Promise<User>;
|
|
106
|
+
/**
|
|
107
|
+
* Get the logout URL
|
|
108
|
+
* @returns Promise that resolves with the logout URL or undefined if not available
|
|
109
|
+
*/
|
|
110
|
+
getLogoutUrl(): Promise<string | undefined>;
|
|
111
|
+
/**
|
|
112
|
+
* Handle the silent logout callback
|
|
113
|
+
* @param url - The URL containing logout information
|
|
114
|
+
* @returns Promise that resolves when callback is handled
|
|
115
|
+
*/
|
|
116
|
+
logoutSilentCallback(url: string): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Get internal AuthManager instance
|
|
119
|
+
* @internal
|
|
120
|
+
* @returns AuthManager instance for advanced use cases
|
|
121
|
+
*/
|
|
122
|
+
getAuthManager(): AuthManager;
|
|
123
|
+
/**
|
|
124
|
+
* Get auth configuration
|
|
125
|
+
* @internal
|
|
126
|
+
* @returns IAuthConfiguration instance
|
|
127
|
+
*/
|
|
128
|
+
getConfig(): IAuthConfiguration;
|
|
129
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DirectLoginOptions, User, DeviceTokenResponse, UserZkEvm
|
|
1
|
+
import { DirectLoginOptions, User, DeviceTokenResponse, UserZkEvm } 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,16 @@ export default class AuthManager {
|
|
|
15
15
|
private static mapOidcUserToDomainModel;
|
|
16
16
|
private static mapDeviceTokenResponseToOidcUser;
|
|
17
17
|
private buildExtraQueryParams;
|
|
18
|
-
|
|
18
|
+
getClientId(): Promise<string>;
|
|
19
|
+
loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void>;
|
|
19
20
|
/**
|
|
20
21
|
* login
|
|
21
|
-
* @param anonymousId Caller can pass an anonymousId if they want to associate their user's identity with immutable's internal instrumentation.
|
|
22
22
|
* @param directLoginOptions If provided, contains login method and marketing consent options
|
|
23
23
|
* @param directLoginOptions.directLoginMethod The login method to use (e.g., 'google', 'apple', 'email')
|
|
24
24
|
* @param directLoginOptions.marketingConsentStatus Marketing consent status ('opted_in' or 'unsubscribed')
|
|
25
25
|
* @param directLoginOptions.email Required when directLoginMethod is 'email'
|
|
26
26
|
*/
|
|
27
|
-
login(
|
|
27
|
+
login(directLoginOptions?: DirectLoginOptions): Promise<User>;
|
|
28
28
|
getUserOrLogin(): Promise<User>;
|
|
29
29
|
private static shouldUseSigninPopupCallback;
|
|
30
30
|
loginCallback(): Promise<undefined | User>;
|
|
@@ -58,5 +58,4 @@ export default class AuthManager {
|
|
|
58
58
|
*/
|
|
59
59
|
getUser<T extends User>(typeAssertion?: (user: User) => user is T): Promise<T | null>;
|
|
60
60
|
getUserZkEvm(): Promise<UserZkEvm>;
|
|
61
|
-
getUserImx(): Promise<UserImx>;
|
|
62
61
|
}
|
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,
|
|
4
|
-
export { isUserZkEvm,
|
|
4
|
+
export type { User, UserProfile, UserZkEvm, DirectLoginMethod, DirectLoginOptions, LoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, IdTokenPayload, PKCEData, AuthEventMap, } from './types';
|
|
5
|
+
export { isUserZkEvm, 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
|
@@ -10,7 +10,6 @@ export type UserProfile = {
|
|
|
10
10
|
sub: string;
|
|
11
11
|
};
|
|
12
12
|
export declare enum RollupType {
|
|
13
|
-
IMX = "imx",
|
|
14
13
|
ZKEVM = "zkEvm"
|
|
15
14
|
}
|
|
16
15
|
export type User = {
|
|
@@ -19,22 +18,14 @@ export type User = {
|
|
|
19
18
|
refreshToken?: string;
|
|
20
19
|
profile: UserProfile;
|
|
21
20
|
expired?: boolean;
|
|
22
|
-
[RollupType.IMX]?: {
|
|
23
|
-
ethAddress: string;
|
|
24
|
-
starkAddress: string;
|
|
25
|
-
userAdminAddress: string;
|
|
26
|
-
};
|
|
27
21
|
[RollupType.ZKEVM]?: {
|
|
28
22
|
ethAddress: string;
|
|
29
23
|
userAdminAddress: string;
|
|
30
24
|
};
|
|
31
25
|
};
|
|
32
26
|
export type PassportMetadata = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
imx_user_admin_address: string;
|
|
36
|
-
zkevm_eth_address: string;
|
|
37
|
-
zkevm_user_admin_address: string;
|
|
27
|
+
zkevm_eth_address?: string;
|
|
28
|
+
zkevm_user_admin_address?: string;
|
|
38
29
|
};
|
|
39
30
|
export interface OidcConfiguration {
|
|
40
31
|
clientId: string;
|
|
@@ -72,10 +63,8 @@ export interface AuthModuleConfiguration extends OidcConfiguration {
|
|
|
72
63
|
type WithRequired<T, K extends keyof T> = T & {
|
|
73
64
|
[P in K]-?: T[P];
|
|
74
65
|
};
|
|
75
|
-
export type UserImx = WithRequired<User, RollupType.IMX>;
|
|
76
66
|
export type UserZkEvm = WithRequired<User, RollupType.ZKEVM>;
|
|
77
67
|
export declare const isUserZkEvm: (user: User) => user is UserZkEvm;
|
|
78
|
-
export declare const isUserImx: (user: User) => user is UserImx;
|
|
79
68
|
export type DeviceTokenResponse = {
|
|
80
69
|
access_token: string;
|
|
81
70
|
refresh_token?: string;
|
|
@@ -105,8 +94,39 @@ export declare enum MarketingConsentStatus {
|
|
|
105
94
|
Unsubscribed = "unsubscribed"
|
|
106
95
|
}
|
|
107
96
|
export type DirectLoginOptions = {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
email
|
|
97
|
+
marketingConsentStatus: MarketingConsentStatus;
|
|
98
|
+
} & ({
|
|
99
|
+
directLoginMethod: 'email';
|
|
100
|
+
email: string;
|
|
101
|
+
} | {
|
|
102
|
+
directLoginMethod: Exclude<DirectLoginMethod, 'email'>;
|
|
103
|
+
email?: never;
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* Extended login options with caching and silent login support
|
|
107
|
+
*/
|
|
108
|
+
export type LoginOptions = {
|
|
109
|
+
/** If true, attempts to use cached session without user interaction */
|
|
110
|
+
useCachedSession?: boolean;
|
|
111
|
+
/** If true, attempts silent authentication (force token refresh) */
|
|
112
|
+
useSilentLogin?: boolean;
|
|
113
|
+
/** If true, uses redirect flow instead of popup flow */
|
|
114
|
+
useRedirectFlow?: boolean;
|
|
115
|
+
/** Direct login options (social provider, email, etc.) */
|
|
116
|
+
directLoginOptions?: DirectLoginOptions;
|
|
111
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* Authentication events emitted by the Auth class
|
|
120
|
+
*/
|
|
121
|
+
export declare enum AuthEvents {
|
|
122
|
+
LOGGED_OUT = "loggedOut",
|
|
123
|
+
LOGGED_IN = "loggedIn"
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Event map for typed event emitter
|
|
127
|
+
*/
|
|
128
|
+
export interface AuthEventMap extends Record<string, any> {
|
|
129
|
+
[AuthEvents.LOGGED_OUT]: [];
|
|
130
|
+
[AuthEvents.LOGGED_IN]: [User];
|
|
131
|
+
}
|
|
112
132
|
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/auth",
|
|
3
|
-
"version": "2.10.7-alpha.
|
|
3
|
+
"version": "2.10.7-alpha.5",
|
|
4
4
|
"description": "Authentication SDK for Immutable",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@imtbl/config": "2.10.7-alpha.
|
|
29
|
-
"@imtbl/metrics": "2.10.7-alpha.
|
|
28
|
+
"@imtbl/config": "2.10.7-alpha.5",
|
|
29
|
+
"@imtbl/metrics": "2.10.7-alpha.5",
|
|
30
30
|
"axios": "^1.6.5",
|
|
31
31
|
"jwt-decode": "^3.1.2",
|
|
32
32
|
"localforage": "^1.10.0",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"uuid": "^9.0.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@imtbl/toolkit": "2.10.7-alpha.
|
|
37
|
+
"@imtbl/toolkit": "2.10.7-alpha.5",
|
|
38
38
|
"@types/node": "^18.14.2",
|
|
39
39
|
"tsup": "^8.3.0",
|
|
40
40
|
"typescript": "^5.6.2"
|
package/src/Auth.ts
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
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 { withMetricsAsync } from './utils/metrics';
|
|
9
|
+
import { identify, track, trackError } from '@imtbl/metrics';
|
|
10
|
+
import logger from './utils/logger';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Public-facing Auth class for authentication
|
|
14
|
+
* Wraps AuthManager with a simpler API
|
|
15
|
+
*/
|
|
16
|
+
export class Auth {
|
|
17
|
+
private authManager: AuthManager;
|
|
18
|
+
|
|
19
|
+
private config: IAuthConfiguration;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Event emitter for authentication events (LOGGED_IN, LOGGED_OUT)
|
|
23
|
+
* Exposed for wallet and passport packages to subscribe to auth state changes
|
|
24
|
+
*/
|
|
25
|
+
public readonly eventEmitter: TypedEventEmitter<AuthEventMap>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a new Auth instance
|
|
29
|
+
*
|
|
30
|
+
* @param config - Auth configuration
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* import { Auth } from '@imtbl/auth';
|
|
35
|
+
*
|
|
36
|
+
* const auth = new Auth({
|
|
37
|
+
* authenticationDomain: 'https://auth.immutable.com',
|
|
38
|
+
* passportDomain: 'https://passport.immutable.com',
|
|
39
|
+
* clientId: 'your-client-id',
|
|
40
|
+
* redirectUri: 'https://your-app.com/callback',
|
|
41
|
+
* scope: 'openid profile email transact',
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
constructor(config: AuthModuleConfiguration) {
|
|
46
|
+
this.config = new AuthConfiguration(config);
|
|
47
|
+
const embeddedLoginPrompt = new EmbeddedLoginPrompt(this.config);
|
|
48
|
+
this.authManager = new AuthManager(this.config, embeddedLoginPrompt);
|
|
49
|
+
this.eventEmitter = new TypedEventEmitter<AuthEventMap>();
|
|
50
|
+
track('passport', 'initialise');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Login the user with extended options
|
|
55
|
+
* Supports cached sessions, silent login, redirect flow, and direct login
|
|
56
|
+
* @param options - Extended login options
|
|
57
|
+
* @returns Promise that resolves with the user or null
|
|
58
|
+
*/
|
|
59
|
+
async login(options?: LoginOptions): Promise<User | null> {
|
|
60
|
+
return withMetricsAsync(async () => {
|
|
61
|
+
const { useCachedSession = false, useSilentLogin } = options || {};
|
|
62
|
+
let user: User | null = null;
|
|
63
|
+
|
|
64
|
+
// Try to get cached user
|
|
65
|
+
try {
|
|
66
|
+
user = await this.authManager.getUser();
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
if (error instanceof Error && !error.message.includes('Unknown or invalid refresh token')) {
|
|
69
|
+
trackError('passport', 'login', error);
|
|
70
|
+
}
|
|
71
|
+
if (useCachedSession) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
logger.warn('Failed to retrieve a cached user session', error);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// If no cached user, try silent login or regular login
|
|
78
|
+
if (!user && useSilentLogin) {
|
|
79
|
+
user = await this.authManager.forceUserRefresh();
|
|
80
|
+
} else if (!user && !useCachedSession) {
|
|
81
|
+
if (options?.useRedirectFlow) {
|
|
82
|
+
await this.authManager.loginWithRedirect(options?.directLoginOptions);
|
|
83
|
+
return null; // Redirect doesn't return user immediately
|
|
84
|
+
}
|
|
85
|
+
user = await this.authManager.login(options?.directLoginOptions);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Emit LOGGED_IN event and identify user if logged in
|
|
89
|
+
if (user) {
|
|
90
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
91
|
+
identify({ passportId: user.profile.sub });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return user;
|
|
95
|
+
}, 'login');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Login with redirect
|
|
100
|
+
* Redirects the page for authentication
|
|
101
|
+
* @param directLoginOptions - Optional direct login options
|
|
102
|
+
* @returns Promise that resolves when redirect is initiated
|
|
103
|
+
*/
|
|
104
|
+
async loginWithRedirect(directLoginOptions?: DirectLoginOptions): Promise<void> {
|
|
105
|
+
await this.authManager.loginWithRedirect(directLoginOptions);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Login callback handler
|
|
110
|
+
* Call this in your redirect URI page
|
|
111
|
+
* @returns Promise that resolves with the authenticated user
|
|
112
|
+
*/
|
|
113
|
+
async loginCallback(): Promise<User> {
|
|
114
|
+
return withMetricsAsync(async () => {
|
|
115
|
+
const user = await this.authManager.loginCallback();
|
|
116
|
+
if (!user) {
|
|
117
|
+
throw new Error('Login callback failed - no user returned');
|
|
118
|
+
}
|
|
119
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
120
|
+
identify({ passportId: user.profile.sub });
|
|
121
|
+
return user;
|
|
122
|
+
}, 'loginCallback');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Logout the current user
|
|
127
|
+
* @returns Promise that resolves when logout is complete
|
|
128
|
+
*/
|
|
129
|
+
async logout(): Promise<void> {
|
|
130
|
+
await withMetricsAsync(async () => {
|
|
131
|
+
await this.authManager.logout();
|
|
132
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_OUT);
|
|
133
|
+
}, 'logout');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get the current authenticated user
|
|
138
|
+
* @returns Promise that resolves with the user or null if not authenticated
|
|
139
|
+
*/
|
|
140
|
+
async getUser(): Promise<User | null> {
|
|
141
|
+
return withMetricsAsync(async () => this.authManager.getUser(), 'getUserInfo', false);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get the ID token for the current user
|
|
146
|
+
* @returns Promise that resolves with the ID token or undefined
|
|
147
|
+
*/
|
|
148
|
+
async getIdToken(): Promise<string | undefined> {
|
|
149
|
+
return withMetricsAsync(async () => {
|
|
150
|
+
const user = await this.authManager.getUser();
|
|
151
|
+
return user?.idToken;
|
|
152
|
+
}, 'getIdToken', false);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get the access token for the current user
|
|
157
|
+
* @returns Promise that resolves with the access token or undefined
|
|
158
|
+
*/
|
|
159
|
+
async getAccessToken(): Promise<string | undefined> {
|
|
160
|
+
return withMetricsAsync(async () => {
|
|
161
|
+
const user = await this.authManager.getUser();
|
|
162
|
+
return user?.accessToken;
|
|
163
|
+
}, 'getAccessToken', false, false);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Check if user is logged in
|
|
168
|
+
* @returns Promise that resolves with true if user is logged in
|
|
169
|
+
*/
|
|
170
|
+
async isLoggedIn(): Promise<boolean> {
|
|
171
|
+
const user = await this.getUser();
|
|
172
|
+
return user !== null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Force a silent user refresh (for silent login)
|
|
177
|
+
* @returns Promise that resolves with the user or null if refresh fails
|
|
178
|
+
*/
|
|
179
|
+
async forceUserRefresh(): Promise<User | null> {
|
|
180
|
+
return this.authManager.forceUserRefresh();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get the PKCE authorization URL for login flow
|
|
185
|
+
* @param directLoginOptions - Optional direct login options
|
|
186
|
+
* @param imPassportTraceId - Optional trace ID for tracking
|
|
187
|
+
* @returns Promise that resolves with the authorization URL
|
|
188
|
+
*/
|
|
189
|
+
async loginWithPKCEFlow(directLoginOptions?: DirectLoginOptions, imPassportTraceId?: string): Promise<string> {
|
|
190
|
+
return withMetricsAsync(
|
|
191
|
+
async () => this.authManager.getPKCEAuthorizationUrl(directLoginOptions, imPassportTraceId),
|
|
192
|
+
'loginWithPKCEFlow',
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Handle the PKCE login callback
|
|
198
|
+
* @param authorizationCode - The authorization code from the OAuth provider
|
|
199
|
+
* @param state - The state parameter for CSRF protection
|
|
200
|
+
* @returns Promise that resolves with the authenticated user
|
|
201
|
+
*/
|
|
202
|
+
async loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User> {
|
|
203
|
+
return withMetricsAsync(async () => {
|
|
204
|
+
const user = await this.authManager.loginWithPKCEFlowCallback(authorizationCode, state);
|
|
205
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
206
|
+
identify({ passportId: user.profile.sub });
|
|
207
|
+
return user;
|
|
208
|
+
}, 'loginWithPKCEFlowCallback');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Store tokens from device flow and retrieve user
|
|
213
|
+
* @param tokenResponse - The token response from device flow
|
|
214
|
+
* @returns Promise that resolves with the authenticated user
|
|
215
|
+
*/
|
|
216
|
+
async storeTokens(tokenResponse: DeviceTokenResponse): Promise<User> {
|
|
217
|
+
return withMetricsAsync(async () => {
|
|
218
|
+
const user = await this.authManager.storeTokens(tokenResponse);
|
|
219
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
|
|
220
|
+
identify({ passportId: user.profile.sub });
|
|
221
|
+
return user;
|
|
222
|
+
}, 'storeTokens');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get the logout URL
|
|
227
|
+
* @returns Promise that resolves with the logout URL or undefined if not available
|
|
228
|
+
*/
|
|
229
|
+
async getLogoutUrl(): Promise<string | undefined> {
|
|
230
|
+
return withMetricsAsync(async () => {
|
|
231
|
+
await this.authManager.removeUser();
|
|
232
|
+
this.eventEmitter.emit(AuthEvents.LOGGED_OUT);
|
|
233
|
+
const url = await this.authManager.getLogoutUrl();
|
|
234
|
+
return url || undefined;
|
|
235
|
+
}, 'getLogoutUrl');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Handle the silent logout callback
|
|
240
|
+
* @param url - The URL containing logout information
|
|
241
|
+
* @returns Promise that resolves when callback is handled
|
|
242
|
+
*/
|
|
243
|
+
async logoutSilentCallback(url: string): Promise<void> {
|
|
244
|
+
return withMetricsAsync(() => this.authManager.logoutSilentCallback(url), 'logoutSilentCallback');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get internal AuthManager instance
|
|
249
|
+
* @internal
|
|
250
|
+
* @returns AuthManager instance for advanced use cases
|
|
251
|
+
*/
|
|
252
|
+
getAuthManager(): AuthManager {
|
|
253
|
+
return this.authManager;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get auth configuration
|
|
258
|
+
* @internal
|
|
259
|
+
* @returns IAuthConfiguration instance
|
|
260
|
+
*/
|
|
261
|
+
getConfig(): IAuthConfiguration {
|
|
262
|
+
return this.config;
|
|
263
|
+
}
|
|
264
|
+
}
|