Skip to content

Commit ee7a2ab

Browse files
committed
step1-split wallet and auth
1 parent 3669e79 commit ee7a2ab

File tree

100 files changed

+1080
-9171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1080
-9171
lines changed

packages/auth/package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@imtbl/auth",
3+
"version": "0.0.0",
4+
"description": "Authentication SDK for Immutable",
5+
"main": "dist/node/index.js",
6+
"module": "dist/node/index.mjs",
7+
"types": "dist/types/index.d.ts",
8+
"exports": {
9+
".": {
10+
"types": "./dist/types/index.d.ts",
11+
"import": {
12+
"browser": "./dist/browser/index.mjs",
13+
"default": "./dist/node/index.mjs"
14+
},
15+
"require": "./dist/node/index.js"
16+
}
17+
},
18+
"scripts": {
19+
"build": "pnpm transpile && pnpm typegen",
20+
"transpile": "tsup src/index.ts --config ../../tsup.config.js",
21+
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types"
22+
},
23+
"dependencies": {
24+
"@imtbl/config": "workspace:*",
25+
"@imtbl/metrics": "workspace:*",
26+
"axios": "^1.6.2",
27+
"jwt-decode": "^3.1.2",
28+
"localforage": "^1.10.0",
29+
"oidc-client-ts": "^2.4.0",
30+
"uuid": "^9.0.1"
31+
},
32+
"devDependencies": {
33+
"@imtbl/toolkit": "workspace:*",
34+
"tsup": "^8.3.0",
35+
"typescript": "^5.6.2"
36+
}
37+
}
38+

packages/passport/sdk/src/authManager.ts renamed to packages/auth/src/authManager.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import localForage from 'localforage';
1414
import DeviceCredentialsManager from './storage/device_credentials_manager';
1515
import logger from './utils/logger';
1616
import { isAccessTokenExpiredOrExpiring } from './utils/token';
17-
import { PassportError, PassportErrorType, withPassportError } from './errors/passportError';
17+
import { AuthError, AuthErrorType, withAuthError } from './errors';
1818
import {
1919
DirectLoginOptions,
2020
PassportMetadata,
@@ -27,7 +27,7 @@ import {
2727
UserImx,
2828
isUserImx,
2929
} from './types';
30-
import { PassportConfiguration } from './config';
30+
import { IAuthConfiguration } from './config';
3131
import ConfirmationOverlay from './overlay/confirmationOverlay';
3232
import { LocalForageAsyncStorage } from './storage/LocalForageAsyncStorage';
3333
import { EmbeddedLoginPrompt } from './confirmation';
@@ -48,12 +48,12 @@ const getLogoutEndpointPath = (crossSdkBridgeEnabled: boolean): string => (
4848
crossSdkBridgeEnabled ? crossSdkBridgeLogoutEndpoint : logoutEndpoint
4949
);
5050

51-
const getAuthConfiguration = (config: PassportConfiguration): UserManagerSettings => {
51+
const getAuthConfiguration = (config: IAuthConfiguration): UserManagerSettings => {
5252
const { authenticationDomain, oidcConfiguration } = config;
5353

5454
let store;
5555
if (config.crossSdkBridgeEnabled) {
56-
store = new LocalForageAsyncStorage('ImmutableSDKPassport', localForage.INDEXEDDB);
56+
store = new LocalForageAsyncStorage('ImmutableSDKAuth', localForage.INDEXEDDB);
5757
} else if (typeof window !== 'undefined') {
5858
store = window.localStorage;
5959
} else {
@@ -110,7 +110,7 @@ export default class AuthManager {
110110

111111
private deviceCredentialsManager: DeviceCredentialsManager;
112112

113-
private readonly config: PassportConfiguration;
113+
private readonly config: IAuthConfiguration;
114114

115115
private readonly embeddedLoginPrompt: EmbeddedLoginPrompt;
116116

@@ -121,7 +121,7 @@ export default class AuthManager {
121121
*/
122122
private refreshingPromise: Promise<User | null> | null = null;
123123

124-
constructor(config: PassportConfiguration, embeddedLoginPrompt: EmbeddedLoginPrompt) {
124+
constructor(config: IAuthConfiguration, embeddedLoginPrompt: EmbeddedLoginPrompt) {
125125
this.config = config;
126126
this.userManager = new UserManager(getAuthConfiguration(config));
127127
this.deviceCredentialsManager = new DeviceCredentialsManager();
@@ -221,13 +221,13 @@ export default class AuthManager {
221221

222222
public async loginWithRedirect(anonymousId?: string, directLoginOptions?: DirectLoginOptions): Promise<void> {
223223
await this.userManager.clearStaleState();
224-
return withPassportError<void>(async () => {
224+
return withAuthError<void>(async () => {
225225
const extraQueryParams = this.buildExtraQueryParams(anonymousId, directLoginOptions);
226226

227227
await this.userManager.signinRedirect({
228228
extraQueryParams,
229229
});
230-
}, PassportErrorType.AUTHENTICATION_ERROR);
230+
}, AuthErrorType.AUTHENTICATION_ERROR);
231231
}
232232

233233
/**
@@ -239,19 +239,21 @@ export default class AuthManager {
239239
* @param directLoginOptions.email Required when directLoginMethod is 'email'
240240
*/
241241
public async login(anonymousId?: string, directLoginOptions?: DirectLoginOptions): Promise<User> {
242-
return withPassportError<User>(async () => {
242+
return withAuthError<User>(async () => {
243243
// If directLoginOptions are provided, then the consumer has rendered their own initial login screen.
244244
// If not, display the embedded login prompt and pass the returned direct login options and imPassportTraceId to the login popup.
245245
let directLoginOptionsToUse: DirectLoginOptions | undefined;
246246
let imPassportTraceId: string | undefined;
247247
if (directLoginOptions) {
248248
directLoginOptionsToUse = directLoginOptions;
249-
} else if (!this.config.popupOverlayOptions.disableHeadlessLoginPromptOverlay) {
249+
} else if (!this.config.popupOverlayOptions?.disableHeadlessLoginPromptOverlay) {
250250
const {
251251
imPassportTraceId: embeddedLoginPromptImPassportTraceId,
252252
...embeddedLoginPromptDirectLoginOptions
253-
} = await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt(anonymousId);
254-
directLoginOptionsToUse = embeddedLoginPromptDirectLoginOptions;
253+
} = this.embeddedLoginPrompt
254+
? await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt(anonymousId)
255+
: { imPassportTraceId: undefined };
256+
directLoginOptionsToUse = (embeddedLoginPromptDirectLoginOptions as any).directLoginMethod ? embeddedLoginPromptDirectLoginOptions as DirectLoginOptions : undefined;
255257
imPassportTraceId = embeddedLoginPromptImPassportTraceId;
256258
}
257259

@@ -314,7 +316,7 @@ export default class AuthManager {
314316

315317
// Popup was blocked; append the blocked popup overlay to allow the user to try again.
316318
let popupHasBeenOpened: boolean = false;
317-
const overlay = new ConfirmationOverlay(this.config.popupOverlayOptions, true);
319+
const overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {}, true);
318320
overlay.append(
319321
async () => {
320322
try {
@@ -346,7 +348,7 @@ export default class AuthManager {
346348
);
347349
});
348350
});
349-
}, PassportErrorType.AUTHENTICATION_ERROR);
351+
}, AuthErrorType.AUTHENTICATION_ERROR);
350352
}
351353

352354
public async getUserOrLogin(): Promise<User> {
@@ -378,7 +380,7 @@ export default class AuthManager {
378380
}
379381

380382
public async loginCallback(): Promise<undefined | User> {
381-
return withPassportError<undefined | User>(async () => {
383+
return withAuthError<undefined | User>(async () => {
382384
// ID-3950: https://github.com/authts/oidc-client-ts/issues/2043
383385
// When using `signinPopup` to initiate a login, call the `signinPopupCallback` method and
384386
// set the `keepOpen` flag to `true`, as the `login` method is now responsible for closing the popup.
@@ -393,7 +395,7 @@ export default class AuthManager {
393395
}
394396

395397
return AuthManager.mapOidcUserToDomainModel(oidcUser);
396-
}, PassportErrorType.AUTHENTICATION_ERROR);
398+
}, AuthErrorType.AUTHENTICATION_ERROR);
397399
}
398400

399401
public async getPKCEAuthorizationUrl(
@@ -448,7 +450,7 @@ export default class AuthManager {
448450
}
449451

450452
public async loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User> {
451-
return withPassportError<User>(async () => {
453+
return withAuthError<User>(async () => {
452454
const pkceData = this.deviceCredentialsManager.getPKCEData();
453455
if (!pkceData) {
454456
throw new Error('No code verifier or state for PKCE');
@@ -464,7 +466,7 @@ export default class AuthManager {
464466
await this.userManager.storeUser(oidcUser);
465467

466468
return user;
467-
}, PassportErrorType.AUTHENTICATION_ERROR);
469+
}, AuthErrorType.AUTHENTICATION_ERROR);
468470
}
469471

470472
private async getPKCEToken(authorizationCode: string, codeVerifier: string): Promise<DeviceTokenResponse> {
@@ -484,25 +486,25 @@ export default class AuthManager {
484486
}
485487

486488
public async storeTokens(tokenResponse: DeviceTokenResponse): Promise<User> {
487-
return withPassportError<User>(async () => {
489+
return withAuthError<User>(async () => {
488490
const oidcUser = AuthManager.mapDeviceTokenResponseToOidcUser(tokenResponse);
489491
const user = AuthManager.mapOidcUserToDomainModel(oidcUser);
490492
await this.userManager.storeUser(oidcUser);
491493

492494
return user;
493-
}, PassportErrorType.AUTHENTICATION_ERROR);
495+
}, AuthErrorType.AUTHENTICATION_ERROR);
494496
}
495497

496498
public async logout(): Promise<void> {
497-
return withPassportError<void>(async () => {
499+
return withAuthError<void>(async () => {
498500
await this.userManager.revokeTokens(['refresh_token']);
499501

500502
if (this.logoutMode === 'silent') {
501503
await this.userManager.signoutSilent();
502504
} else {
503505
await this.userManager.signoutRedirect();
504506
}
505-
}, PassportErrorType.LOGOUT_ERROR);
507+
}, AuthErrorType.LOGOUT_ERROR);
506508
}
507509

508510
public async logoutSilentCallback(url: string): Promise<void> {
@@ -554,16 +556,16 @@ export default class AuthManager {
554556
}
555557
resolve(null);
556558
} catch (err) {
557-
let passportErrorType = PassportErrorType.AUTHENTICATION_ERROR;
559+
let passportErrorType = AuthErrorType.AUTHENTICATION_ERROR;
558560
let errorMessage = 'Failed to refresh token';
559561
let removeUser = true;
560562

561563
if (err instanceof ErrorTimeout) {
562-
passportErrorType = PassportErrorType.SILENT_LOGIN_ERROR;
564+
passportErrorType = AuthErrorType.SILENT_LOGIN_ERROR;
563565
errorMessage = `${errorMessage}: ${err.message}`;
564566
removeUser = false;
565567
} else if (err instanceof ErrorResponse) {
566-
passportErrorType = PassportErrorType.NOT_LOGGED_IN_ERROR;
568+
passportErrorType = AuthErrorType.NOT_LOGGED_IN_ERROR;
567569
errorMessage = `${errorMessage}: ${err.message || err.error_description}`;
568570
} else if (err instanceof Error) {
569571
errorMessage = `${errorMessage}: ${err.message}`;
@@ -581,7 +583,7 @@ export default class AuthManager {
581583
}
582584
}
583585

584-
reject(new PassportError(errorMessage, passportErrorType));
586+
reject(new AuthError(errorMessage, passportErrorType));
585587
} finally {
586588
this.refreshingPromise = null; // Reset the promise after completion
587589
}

packages/auth/src/config.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
OidcConfiguration,
3+
AuthModuleConfiguration,
4+
PopupOverlayOptions,
5+
} from './types';
6+
import { AuthError, AuthErrorType } from './errors';
7+
8+
const validateConfiguration = <T>(
9+
configuration: T,
10+
requiredKeys: Array<keyof T>,
11+
prefix?: string,
12+
) => {
13+
const missingKeys = requiredKeys
14+
.map((key) => !configuration[key] && key)
15+
.filter((n) => n)
16+
.join(', ');
17+
if (missingKeys !== '') {
18+
const errorMessage = prefix
19+
? `${prefix} - ${missingKeys} cannot be null`
20+
: `${missingKeys} cannot be null`;
21+
throw new AuthError(
22+
errorMessage,
23+
AuthErrorType.INVALID_CONFIGURATION,
24+
);
25+
}
26+
};
27+
28+
/**
29+
* Interface that any configuration must implement to work with AuthManager
30+
*/
31+
export interface IAuthConfiguration {
32+
readonly authenticationDomain: string;
33+
readonly passportDomain: string;
34+
readonly oidcConfiguration: OidcConfiguration;
35+
readonly crossSdkBridgeEnabled: boolean;
36+
readonly popupOverlayOptions?: PopupOverlayOptions;
37+
}
38+
39+
export class AuthConfiguration implements IAuthConfiguration {
40+
readonly authenticationDomain: string;
41+
readonly passportDomain: string;
42+
readonly oidcConfiguration: OidcConfiguration;
43+
readonly crossSdkBridgeEnabled: boolean;
44+
readonly popupOverlayOptions?: PopupOverlayOptions;
45+
46+
constructor({
47+
authenticationDomain,
48+
passportDomain,
49+
crossSdkBridgeEnabled,
50+
popupOverlayOptions,
51+
...oidcConfiguration
52+
}: AuthModuleConfiguration) {
53+
validateConfiguration(oidcConfiguration, [
54+
'clientId',
55+
'redirectUri',
56+
]);
57+
58+
this.oidcConfiguration = oidcConfiguration;
59+
this.crossSdkBridgeEnabled = crossSdkBridgeEnabled || false;
60+
this.popupOverlayOptions = popupOverlayOptions;
61+
62+
// Default to production auth domain if not provided
63+
this.authenticationDomain = authenticationDomain || 'https://auth.immutable.com';
64+
this.passportDomain = passportDomain || 'https://passport.immutable.com';
65+
}
66+
}
67+

packages/passport/sdk/src/confirmation/confirmation.ts renamed to packages/auth/src/confirmation/confirmation.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
ConfirmationSendMessage,
99
} from './types';
1010
import { openPopupCenter } from './popup';
11-
import { PassportConfiguration } from '../config';
11+
import { IAuthConfiguration } from '../config';
1212
import ConfirmationOverlay from '../overlay/confirmationOverlay';
1313

1414
const CONFIRMATION_WINDOW_TITLE = 'Confirm this transaction';
@@ -24,7 +24,7 @@ type MessageHandler = (arg0: MessageEvent) => void;
2424
type MessageType = 'erc191' | 'eip712';
2525

2626
export default class ConfirmationScreen {
27-
private config: PassportConfiguration;
27+
private config: IAuthConfiguration;
2828

2929
private confirmationWindow: Window | undefined;
3030

@@ -36,7 +36,7 @@ export default class ConfirmationScreen {
3636

3737
private timer: NodeJS.Timeout | undefined;
3838

39-
constructor(config: PassportConfiguration) {
39+
constructor(config: IAuthConfiguration) {
4040
this.config = config;
4141
this.overlayClosed = false;
4242
}
@@ -194,12 +194,12 @@ export default class ConfirmationScreen {
194194
width: popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
195195
height: popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
196196
});
197-
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions);
197+
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {});
198198
} catch (error) {
199199
// If an error is thrown here then the popup is blocked
200200
const errorMessage = error instanceof Error ? error.message : String(error);
201201
trackError('passport', 'confirmationPopupDenied', new Error(errorMessage));
202-
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions, true);
202+
this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {}, true);
203203
}
204204

205205
this.overlay.append(

packages/passport/sdk/src/confirmation/embeddedLoginPrompt.ts renamed to packages/auth/src/confirmation/embeddedLoginPrompt.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
EmbeddedLoginPromptResult,
55
EmbeddedLoginPromptReceiveMessage,
66
} from './types';
7-
import { PassportConfiguration } from '../config';
7+
import { IAuthConfiguration } from '../config';
88
import EmbeddedLoginPromptOverlay from '../overlay/embeddedLoginPromptOverlay';
99

1010
const LOGIN_PROMPT_WINDOW_HEIGHT = 660;
@@ -14,9 +14,9 @@ const LOGIN_PROMPT_KEYFRAME_STYLES_ID = 'passport-embedded-login-keyframes';
1414
const LOGIN_PROMPT_IFRAME_ID = 'passport-embedded-login-iframe';
1515

1616
export default class EmbeddedLoginPrompt {
17-
private config: PassportConfiguration;
17+
private config: IAuthConfiguration;
1818

19-
constructor(config: PassportConfiguration) {
19+
constructor(config: IAuthConfiguration) {
2020
this.config = config;
2121
}
2222

0 commit comments

Comments
 (0)