@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/dist/browser/index.js +27 -79
- package/dist/node/index.cjs +40 -96
- package/dist/node/index.js +27 -79
- package/dist/types/index.d.ts +1 -2
- package/dist/types/types.d.ts +1 -29
- package/package.json +6 -6
- package/src/Auth.test.ts +0 -225
- package/src/Auth.ts +2 -15
- package/src/index.ts +0 -15
- package/src/types.ts +0 -32
- package/README.md +0 -163
- package/dist/types/login/standalone.d.ts +0 -144
- package/src/login/standalone.ts +0 -748
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
|
-
|
|
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>;
|