@imtbl/auth 2.12.5-alpha.21 → 2.12.5-alpha.23

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/src/Auth.ts CHANGED
@@ -779,21 +779,15 @@ export class Auth {
779
779
  try {
780
780
  const newOidcUser = await this.userManager.signinSilent();
781
781
  if (newOidcUser) {
782
- const user = Auth.mapOidcUserToDomainModel(newOidcUser);
783
- // Emit TOKEN_REFRESHED event so consumers (e.g., auth-next-client) can sync
784
- // the new tokens to their session. This is critical for refresh token
785
- // rotation - without this, the server-side session may have stale tokens.
786
- this.eventEmitter.emit(AuthEvents.TOKEN_REFRESHED, user);
787
- resolve(user);
782
+ resolve(Auth.mapOidcUserToDomainModel(newOidcUser));
788
783
  return;
789
784
  }
790
785
  resolve(null);
791
786
  } catch (err) {
792
787
  let passportErrorType = PassportErrorType.AUTHENTICATION_ERROR;
793
788
  let errorMessage = 'Failed to refresh token';
794
- // Default to REMOVING user - safer to log out on unknown errors
795
- // Only keep user logged in for explicitly known transient errors
796
789
  let removeUser = true;
790
+
797
791
  if (err instanceof ErrorTimeout) {
798
792
  passportErrorType = PassportErrorType.SILENT_LOGIN_ERROR;
799
793
  errorMessage = `${errorMessage}: ${err.message}`;
@@ -808,13 +802,6 @@ export class Auth {
808
802
  }
809
803
 
810
804
  if (removeUser) {
811
- // Emit USER_REMOVED event BEFORE removing user so consumers can react
812
- // (e.g., auth-next-client can clear the NextAuth session)
813
- this.eventEmitter.emit(AuthEvents.USER_REMOVED, {
814
- reason: 'refresh_failed',
815
- error: errorMessage,
816
- });
817
-
818
805
  try {
819
806
  await this.userManager.removeUser();
820
807
  } catch (removeUserError) {
package/src/index.ts CHANGED
@@ -22,7 +22,6 @@ export type {
22
22
  IdTokenPayload,
23
23
  PKCEData,
24
24
  AuthEventMap,
25
- UserRemovedReason,
26
25
  } from './types';
27
26
  export {
28
27
  isUserZkEvm,
@@ -41,17 +40,3 @@ export {
41
40
  } from './errors';
42
41
 
43
42
  export { decodeJwtPayload } from './utils/jwt';
44
-
45
- // ============================================================================
46
- // Standalone Login Functions (stateless, for use with NextAuth or similar)
47
- // ============================================================================
48
-
49
- export {
50
- loginWithPopup,
51
- loginWithEmbedded,
52
- loginWithRedirect,
53
- handleLoginCallback,
54
- type LoginConfig,
55
- type TokenResponse,
56
- type StandaloneLoginOptions,
57
- } from './login/standalone';
package/src/types.ts CHANGED
@@ -163,44 +163,12 @@ export type LoginOptions = {
163
163
  export enum AuthEvents {
164
164
  LOGGED_OUT = 'loggedOut',
165
165
  LOGGED_IN = 'loggedIn',
166
- /**
167
- * Emitted when tokens are refreshed via signinSilent().
168
- * This is critical for refresh token rotation - when client-side refresh happens,
169
- * the new tokens must be synced to server-side session to prevent race conditions.
170
- */
171
- TOKEN_REFRESHED = 'tokenRefreshed',
172
- /**
173
- * Emitted when the user is removed from local storage due to a permanent auth error.
174
- * Only emitted for errors where the refresh token is truly invalid:
175
- * - invalid_grant: refresh token expired, revoked, or already used
176
- * - login_required: user must re-authenticate
177
- * - consent_required / interaction_required: user must interact with auth server
178
- *
179
- * NOT emitted for transient errors (network, timeout, server errors) - user stays logged in.
180
- * Consumers should sync this state by clearing their session (e.g., NextAuth signOut).
181
- */
182
- USER_REMOVED = 'userRemoved',
183
166
  }
184
167
 
185
- /**
186
- * Error reason for USER_REMOVED event.
187
- * Note: Network/timeout errors do NOT emit USER_REMOVED (user stays logged in),
188
- * so 'network_error' is not a valid reason.
189
- */
190
- export type UserRemovedReason =
191
- // OAuth permanent errors (invalid_grant, login_required, etc.)
192
- | 'refresh_token_invalid'
193
- // Unknown non-OAuth errors
194
- | 'refresh_failed'
195
- // Fallback for truly unknown error types
196
- | 'unknown';
197
-
198
168
  /**
199
169
  * Event map for typed event emitter
200
170
  */
201
171
  export interface AuthEventMap extends Record<string, any> {
202
172
  [AuthEvents.LOGGED_OUT]: [];
203
173
  [AuthEvents.LOGGED_IN]: [User];
204
- [AuthEvents.TOKEN_REFRESHED]: [User];
205
- [AuthEvents.USER_REMOVED]: [{ reason: UserRemovedReason; error?: string }];
206
174
  }
package/README.md DELETED
@@ -1,163 +0,0 @@
1
- # @imtbl/auth
2
-
3
- Authentication utilities for the Immutable SDK.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @imtbl/auth
9
- ```
10
-
11
- ## Overview
12
-
13
- This package provides two ways to handle Immutable authentication:
14
-
15
- 1. **Auth Class** - Full-featured authentication with session managed on client side.
16
- 2. **Standalone Login Functions** - Stateless login functions for use with external session managers (e.g., NextAuth)
17
-
18
- ## Standalone Login Functions
19
-
20
- For Next.js applications using NextAuth, use the standalone login functions. These handle OAuth flows and return tokens without managing session state.
21
-
22
- ### loginWithPopup
23
-
24
- Opens a popup window for authentication and returns tokens when complete.
25
-
26
- ```typescript
27
- import { loginWithPopup } from '@imtbl/auth';
28
- import { signIn } from 'next-auth/react';
29
-
30
- async function handleLogin() {
31
- const tokens = await loginWithPopup({
32
- clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
33
- redirectUri: `${window.location.origin}/callback`,
34
- });
35
-
36
- // Sign in to NextAuth with the tokens
37
- await signIn('immutable', {
38
- tokens: JSON.stringify(tokens),
39
- redirect: false,
40
- });
41
- }
42
- ```
43
-
44
- ### loginWithRedirect
45
-
46
- Redirects the page to the authentication provider. Use `handleLoginCallback` on the callback page.
47
-
48
- ```typescript
49
- import { loginWithRedirect } from '@imtbl/auth';
50
-
51
- function handleLogin() {
52
- loginWithRedirect({
53
- clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
54
- redirectUri: `${window.location.origin}/callback`,
55
- });
56
- }
57
- ```
58
-
59
- ### handleLoginCallback
60
-
61
- Handles the OAuth callback and exchanges the authorization code for tokens.
62
-
63
- ```typescript
64
- import { handleLoginCallback } from '@imtbl/auth';
65
- import { signIn } from 'next-auth/react';
66
-
67
- // In your callback page
68
- async function processCallback() {
69
- const tokens = await handleLoginCallback({
70
- clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
71
- redirectUri: `${window.location.origin}/callback`,
72
- });
73
-
74
- if (tokens) {
75
- await signIn('immutable', {
76
- tokens: JSON.stringify(tokens),
77
- redirect: false,
78
- });
79
- // Redirect to home or dashboard
80
- window.location.href = '/';
81
- }
82
- }
83
- ```
84
-
85
- ### LoginConfig
86
-
87
- Configuration options for standalone login functions:
88
-
89
- ```typescript
90
- interface LoginConfig {
91
- /** Your Immutable application client ID */
92
- clientId: string;
93
- /** The OAuth redirect URI for your application */
94
- redirectUri: string;
95
- /** Optional separate redirect URI for popup flows */
96
- popupRedirectUri?: string;
97
- /** OAuth audience (default: "platform_api") */
98
- audience?: string;
99
- /** OAuth scopes (default: "openid profile email offline_access transact") */
100
- scope?: string;
101
- /** Authentication domain (default: "https://auth.immutable.com") */
102
- authenticationDomain?: string;
103
- }
104
- ```
105
-
106
- ### TokenResponse
107
-
108
- The token data returned from successful authentication:
109
-
110
- ```typescript
111
- interface TokenResponse {
112
- /** OAuth access token for API calls */
113
- accessToken: string;
114
- /** OAuth refresh token for token renewal */
115
- refreshToken?: string;
116
- /** OpenID Connect ID token */
117
- idToken?: string;
118
- /** Unix timestamp (ms) when the access token expires */
119
- accessTokenExpires: number;
120
- /** User profile information */
121
- profile: {
122
- sub: string;
123
- email?: string;
124
- nickname?: string;
125
- };
126
- /** zkEVM wallet information if available */
127
- zkEvm?: {
128
- ethAddress: string;
129
- userAdminAddress: string;
130
- };
131
- }
132
- ```
133
-
134
- ## Auth Class
135
-
136
- For applications that need full authentication management (like the Passport SDK), use the `Auth` class:
137
-
138
- ```typescript
139
- import { Auth } from '@imtbl/auth';
140
-
141
- const auth = new Auth({
142
- clientId: 'your-client-id',
143
- redirectUri: 'https://your-app.com/callback',
144
- scope: 'openid profile email offline_access transact',
145
- });
146
-
147
- // Login with popup
148
- const user = await auth.login();
149
-
150
- // Get current user
151
- const user = await auth.getUser();
152
-
153
- // Logout
154
- await auth.logout();
155
- ```
156
-
157
- ## Integration with NextAuth
158
-
159
- For a complete Next.js authentication setup, use this package with:
160
- - `@imtbl/auth-next-server` - Server-side NextAuth configuration
161
- - `@imtbl/auth-next-client` - Client-side components and hooks
162
-
163
- See those packages for full integration documentation.
@@ -1,144 +0,0 @@
1
- /**
2
- * Standalone login functions for stateless authentication flows.
3
- * These functions handle OAuth login without managing session state,
4
- * making them ideal for use with external session managers like NextAuth.
5
- */
6
- import type { DirectLoginOptions } from '../types';
7
- /**
8
- * Configuration for standalone login functions
9
- */
10
- export interface LoginConfig {
11
- /** Your Immutable application client ID */
12
- clientId: string;
13
- /** The OAuth redirect URI for your application */
14
- redirectUri: string;
15
- /** Optional separate redirect URI for popup flows */
16
- popupRedirectUri?: string;
17
- /** OAuth audience (default: "platform_api") */
18
- audience?: string;
19
- /** OAuth scopes (default: "openid profile email offline_access transact") */
20
- scope?: string;
21
- /** Authentication domain (default: "https://auth.immutable.com") */
22
- authenticationDomain?: string;
23
- }
24
- /**
25
- * Token response from successful authentication
26
- */
27
- export interface TokenResponse {
28
- /** OAuth access token for API calls */
29
- accessToken: string;
30
- /** OAuth refresh token for token renewal */
31
- refreshToken?: string;
32
- /** OpenID Connect ID token */
33
- idToken?: string;
34
- /** Unix timestamp (ms) when the access token expires */
35
- accessTokenExpires: number;
36
- /** User profile information */
37
- profile: {
38
- sub: string;
39
- email?: string;
40
- nickname?: string;
41
- };
42
- /** zkEVM wallet information if available */
43
- zkEvm?: {
44
- ethAddress: string;
45
- userAdminAddress: string;
46
- };
47
- }
48
- /**
49
- * Extended login options for popup/redirect flows
50
- */
51
- export interface StandaloneLoginOptions {
52
- /** Direct login options (social provider, email, etc.) */
53
- directLoginOptions?: DirectLoginOptions;
54
- }
55
- /**
56
- * Login with a popup window.
57
- * Opens a popup for OAuth authentication and returns tokens when complete.
58
- *
59
- * @param config - Login configuration
60
- * @param options - Optional login options (direct login, etc.)
61
- * @returns Promise resolving to token response
62
- * @throws Error if popup is blocked or login fails
63
- *
64
- * @example
65
- * ```typescript
66
- * import { loginWithPopup } from '@imtbl/auth';
67
- *
68
- * const tokens = await loginWithPopup({
69
- * clientId: 'your-client-id',
70
- * redirectUri: 'https://your-app.com/callback',
71
- * });
72
- * console.log(tokens.accessToken);
73
- * ```
74
- */
75
- export declare function loginWithPopup(config: LoginConfig, options?: StandaloneLoginOptions): Promise<TokenResponse>;
76
- /**
77
- * Login with an embedded iframe modal.
78
- * First displays a modal for the user to select their login method (email, Google, etc.),
79
- * then opens a popup for OAuth authentication and returns tokens when complete.
80
- *
81
- * This provides a smoother user experience compared to loginWithPopup as the user
82
- * can choose their login method before the OAuth popup opens.
83
- *
84
- * @param config - Login configuration
85
- * @returns Promise resolving to token response
86
- * @throws Error if modal is closed or login fails
87
- *
88
- * @example
89
- * ```typescript
90
- * import { loginWithEmbedded } from '@imtbl/auth';
91
- *
92
- * const tokens = await loginWithEmbedded({
93
- * clientId: 'your-client-id',
94
- * redirectUri: 'https://your-app.com/callback',
95
- * });
96
- * console.log(tokens.accessToken);
97
- * ```
98
- */
99
- export declare function loginWithEmbedded(config: LoginConfig): Promise<TokenResponse>;
100
- /**
101
- * Login with redirect.
102
- * Redirects the current page to OAuth authentication.
103
- * After authentication, the user will be redirected back to your redirectUri.
104
- * Use `handleLoginCallback` to complete the flow.
105
- *
106
- * @param config - Login configuration
107
- * @param options - Optional login options (direct login, etc.)
108
- *
109
- * @example
110
- * ```typescript
111
- * import { loginWithRedirect } from '@imtbl/auth';
112
- *
113
- * // In your login button handler
114
- * loginWithRedirect({
115
- * clientId: 'your-client-id',
116
- * redirectUri: 'https://your-app.com/callback',
117
- * });
118
- * ```
119
- */
120
- export declare function loginWithRedirect(config: LoginConfig, options?: StandaloneLoginOptions): Promise<void>;
121
- /**
122
- * Handle the OAuth callback after redirect-based login.
123
- * Extracts the authorization code from the URL and exchanges it for tokens.
124
- *
125
- * @param config - Login configuration (must match what was used in loginWithRedirect)
126
- * @returns Promise resolving to token response, or undefined if not a valid callback
127
- *
128
- * @example
129
- * ```typescript
130
- * // In your callback page
131
- * import { handleLoginCallback } from '@imtbl/auth';
132
- *
133
- * const tokens = await handleLoginCallback({
134
- * clientId: 'your-client-id',
135
- * redirectUri: 'https://your-app.com/callback',
136
- * });
137
- *
138
- * if (tokens) {
139
- * // Login successful, tokens contains accessToken, refreshToken, etc.
140
- * await signIn('immutable', { tokens: JSON.stringify(tokens) });
141
- * }
142
- * ```
143
- */
144
- export declare function handleLoginCallback(config: LoginConfig): Promise<TokenResponse | undefined>;