@imtbl/sdk 2.12.5-alpha.10 → 2.12.5-alpha.11
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/auth_nextjs_server.cjs +386 -7
- package/dist/auth_nextjs_server.js +373 -1
- package/dist/index.browser.cdn.js +4 -4
- package/package.json +14 -13
|
@@ -1,12 +1,391 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var server = require('
|
|
3
|
+
var server = require('next/server');
|
|
4
|
+
var NextAuthImport = require('next-auth');
|
|
5
|
+
var CredentialsImport = require('next-auth/providers/credentials');
|
|
4
6
|
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
5
8
|
|
|
9
|
+
var NextAuthImport__default = /*#__PURE__*/_interopDefault(NextAuthImport);
|
|
10
|
+
var CredentialsImport__default = /*#__PURE__*/_interopDefault(CredentialsImport);
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
12
|
+
// ../packages/auth-nextjs/dist/node/server/index.js
|
|
13
|
+
function matchPathPrefix(pathname, pattern) {
|
|
14
|
+
if (pathname === pattern) return true;
|
|
15
|
+
const prefix = pattern.endsWith("/") ? pattern : `${pattern}/`;
|
|
16
|
+
return pathname.startsWith(prefix);
|
|
17
|
+
}
|
|
18
|
+
var DEFAULT_AUTH_DOMAIN = "https://auth.immutable.com";
|
|
19
|
+
var IMMUTABLE_PROVIDER_ID = "immutable";
|
|
20
|
+
var TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
21
|
+
var DEFAULT_SESSION_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
|
|
22
|
+
function isTokenExpired(accessTokenExpires, bufferSeconds = TOKEN_EXPIRY_BUFFER_SECONDS) {
|
|
23
|
+
if (typeof accessTokenExpires !== "number" || Number.isNaN(accessTokenExpires)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return Date.now() >= accessTokenExpires - bufferSeconds * 1e3;
|
|
27
|
+
}
|
|
28
|
+
var Credentials = CredentialsImport__default.default.default || CredentialsImport__default.default;
|
|
29
|
+
async function validateTokens(accessToken, authDomain) {
|
|
30
|
+
try {
|
|
31
|
+
const response = await fetch(`${authDomain}/userinfo`, {
|
|
32
|
+
method: "GET",
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: `Bearer ${accessToken}`
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
console.error("[auth-nextjs] Token validation failed:", response.status, response.statusText);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return await response.json();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("[auth-nextjs] Token validation error:", error);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function createAuthConfig(config) {
|
|
48
|
+
const authDomain = config.authenticationDomain || DEFAULT_AUTH_DOMAIN;
|
|
49
|
+
return {
|
|
50
|
+
providers: [
|
|
51
|
+
Credentials({
|
|
52
|
+
id: IMMUTABLE_PROVIDER_ID,
|
|
53
|
+
name: "Immutable",
|
|
54
|
+
credentials: {
|
|
55
|
+
tokens: { label: "Tokens", type: "text" }
|
|
56
|
+
},
|
|
57
|
+
async authorize(credentials) {
|
|
58
|
+
if (!credentials?.tokens || typeof credentials.tokens !== "string") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
let tokenData;
|
|
62
|
+
try {
|
|
63
|
+
tokenData = JSON.parse(credentials.tokens);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("[auth-nextjs] Failed to parse token data:", error);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (!tokenData.accessToken || typeof tokenData.accessToken !== "string" || !tokenData.profile || typeof tokenData.profile !== "object" || !tokenData.profile.sub || typeof tokenData.profile.sub !== "string" || typeof tokenData.accessTokenExpires !== "number" || Number.isNaN(tokenData.accessTokenExpires)) {
|
|
69
|
+
console.error("[auth-nextjs] Invalid token data structure - missing required fields");
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const userInfo = await validateTokens(tokenData.accessToken, authDomain);
|
|
73
|
+
if (!userInfo) {
|
|
74
|
+
console.error("[auth-nextjs] Token validation failed - rejecting authentication");
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (userInfo.sub !== tokenData.profile.sub) {
|
|
78
|
+
console.error(
|
|
79
|
+
"[auth-nextjs] User ID mismatch - userinfo sub:",
|
|
80
|
+
userInfo.sub,
|
|
81
|
+
"provided sub:",
|
|
82
|
+
tokenData.profile.sub
|
|
83
|
+
);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
id: userInfo.sub,
|
|
88
|
+
sub: userInfo.sub,
|
|
89
|
+
email: userInfo.email ?? tokenData.profile.email,
|
|
90
|
+
nickname: userInfo.nickname ?? tokenData.profile.nickname,
|
|
91
|
+
accessToken: tokenData.accessToken,
|
|
92
|
+
refreshToken: tokenData.refreshToken,
|
|
93
|
+
idToken: tokenData.idToken,
|
|
94
|
+
accessTokenExpires: tokenData.accessTokenExpires,
|
|
95
|
+
zkEvm: tokenData.zkEvm
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
],
|
|
100
|
+
callbacks: {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
102
|
+
async jwt({
|
|
103
|
+
token,
|
|
104
|
+
user,
|
|
105
|
+
trigger,
|
|
106
|
+
session: sessionUpdate
|
|
107
|
+
}) {
|
|
108
|
+
if (user) {
|
|
109
|
+
return {
|
|
110
|
+
...token,
|
|
111
|
+
sub: user.sub,
|
|
112
|
+
email: user.email,
|
|
113
|
+
nickname: user.nickname,
|
|
114
|
+
accessToken: user.accessToken,
|
|
115
|
+
refreshToken: user.refreshToken,
|
|
116
|
+
idToken: user.idToken,
|
|
117
|
+
accessTokenExpires: user.accessTokenExpires,
|
|
118
|
+
zkEvm: user.zkEvm
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (trigger === "update" && sessionUpdate) {
|
|
122
|
+
const update = sessionUpdate;
|
|
123
|
+
return {
|
|
124
|
+
...token,
|
|
125
|
+
...update.accessToken ? { accessToken: update.accessToken } : {},
|
|
126
|
+
...update.refreshToken ? { refreshToken: update.refreshToken } : {},
|
|
127
|
+
...update.idToken ? { idToken: update.idToken } : {},
|
|
128
|
+
...update.accessTokenExpires ? { accessTokenExpires: update.accessTokenExpires } : {},
|
|
129
|
+
...update.zkEvm ? { zkEvm: update.zkEvm } : {},
|
|
130
|
+
// Clear any stale error when valid tokens are synced from client-side
|
|
131
|
+
error: void 0
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (!isTokenExpired(token.accessTokenExpires)) {
|
|
135
|
+
return token;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...token,
|
|
139
|
+
error: "TokenExpired"
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
143
|
+
async session({ session, token }) {
|
|
144
|
+
return {
|
|
145
|
+
...session,
|
|
146
|
+
user: {
|
|
147
|
+
...session.user,
|
|
148
|
+
sub: token.sub,
|
|
149
|
+
email: token.email,
|
|
150
|
+
nickname: token.nickname
|
|
151
|
+
},
|
|
152
|
+
accessToken: token.accessToken,
|
|
153
|
+
refreshToken: token.refreshToken,
|
|
154
|
+
idToken: token.idToken,
|
|
155
|
+
accessTokenExpires: token.accessTokenExpires,
|
|
156
|
+
zkEvm: token.zkEvm,
|
|
157
|
+
...token.error && { error: token.error }
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
session: {
|
|
162
|
+
strategy: "jwt",
|
|
163
|
+
// Session max age in seconds (365 days default)
|
|
164
|
+
maxAge: DEFAULT_SESSION_MAX_AGE_SECONDS
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
var createAuthOptions = createAuthConfig;
|
|
169
|
+
var NextAuth = NextAuthImport__default.default.default || NextAuthImport__default.default;
|
|
170
|
+
function createImmutableAuth(config, overrides) {
|
|
171
|
+
const authConfig = createAuthConfig(config);
|
|
172
|
+
if (!overrides) {
|
|
173
|
+
return NextAuth(authConfig);
|
|
174
|
+
}
|
|
175
|
+
const composedCallbacks = {
|
|
176
|
+
...authConfig.callbacks
|
|
177
|
+
};
|
|
178
|
+
if (overrides.callbacks) {
|
|
179
|
+
if (overrides.callbacks.jwt) {
|
|
180
|
+
const internalJwt = authConfig.callbacks?.jwt;
|
|
181
|
+
const userJwt = overrides.callbacks.jwt;
|
|
182
|
+
composedCallbacks.jwt = async (params) => {
|
|
183
|
+
const token = internalJwt ? await internalJwt(params) : params.token;
|
|
184
|
+
return userJwt({ ...params, token });
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (overrides.callbacks.session) {
|
|
188
|
+
const internalSession = authConfig.callbacks?.session;
|
|
189
|
+
const userSession = overrides.callbacks.session;
|
|
190
|
+
composedCallbacks.session = async (params) => {
|
|
191
|
+
const session = internalSession ? await internalSession(params) : params.session;
|
|
192
|
+
return userSession({ ...params, session });
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (overrides.callbacks.signIn) {
|
|
196
|
+
composedCallbacks.signIn = overrides.callbacks.signIn;
|
|
197
|
+
}
|
|
198
|
+
if (overrides.callbacks.redirect) {
|
|
199
|
+
composedCallbacks.redirect = overrides.callbacks.redirect;
|
|
200
|
+
}
|
|
201
|
+
if (overrides.callbacks.authorized) {
|
|
202
|
+
composedCallbacks.authorized = overrides.callbacks.authorized;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const mergedSession = overrides.session ? {
|
|
206
|
+
...authConfig.session,
|
|
207
|
+
...overrides.session,
|
|
208
|
+
// Always enforce JWT strategy - this is required for token storage/refresh
|
|
209
|
+
strategy: "jwt"
|
|
210
|
+
} : authConfig.session;
|
|
211
|
+
const mergedConfig = {
|
|
212
|
+
...authConfig,
|
|
213
|
+
...overrides,
|
|
214
|
+
callbacks: composedCallbacks,
|
|
215
|
+
session: mergedSession
|
|
216
|
+
};
|
|
217
|
+
return NextAuth(mergedConfig);
|
|
218
|
+
}
|
|
219
|
+
async function getAuthProps(auth) {
|
|
220
|
+
const session = await auth();
|
|
221
|
+
if (!session) {
|
|
222
|
+
return { session: null, ssr: false };
|
|
223
|
+
}
|
|
224
|
+
if (session.error === "TokenExpired") {
|
|
225
|
+
return { session: null, ssr: false };
|
|
226
|
+
}
|
|
227
|
+
if (session.error) {
|
|
228
|
+
return { session: null, ssr: false, authError: session.error };
|
|
229
|
+
}
|
|
230
|
+
return { session, ssr: true };
|
|
231
|
+
}
|
|
232
|
+
async function getAuthenticatedData(auth, fetcher) {
|
|
233
|
+
const session = await auth();
|
|
234
|
+
if (!session) {
|
|
235
|
+
return { session: null, ssr: false, data: null };
|
|
236
|
+
}
|
|
237
|
+
if (session.error === "TokenExpired") {
|
|
238
|
+
return { session: null, ssr: false, data: null };
|
|
239
|
+
}
|
|
240
|
+
if (session.error) {
|
|
241
|
+
return {
|
|
242
|
+
session: null,
|
|
243
|
+
ssr: false,
|
|
244
|
+
data: null,
|
|
245
|
+
authError: session.error
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const data = await fetcher(session.accessToken);
|
|
250
|
+
return { session, ssr: true, data };
|
|
251
|
+
} catch (err) {
|
|
252
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
253
|
+
return {
|
|
254
|
+
session,
|
|
255
|
+
ssr: true,
|
|
256
|
+
data: null,
|
|
257
|
+
fetchError: errorMessage
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function getValidSession(auth) {
|
|
262
|
+
const session = await auth();
|
|
263
|
+
if (!session) {
|
|
264
|
+
return { status: "unauthenticated", session: null };
|
|
265
|
+
}
|
|
266
|
+
if (!session.error) {
|
|
267
|
+
return { status: "authenticated", session };
|
|
268
|
+
}
|
|
269
|
+
if (session.error === "TokenExpired") {
|
|
270
|
+
return { status: "token_expired", session };
|
|
271
|
+
}
|
|
272
|
+
return { status: "error", session, error: session.error };
|
|
273
|
+
}
|
|
274
|
+
function createProtectedDataFetcher(auth, onAuthError) {
|
|
275
|
+
return async function getProtectedData(fetcher) {
|
|
276
|
+
const result = await getAuthenticatedData(auth, fetcher);
|
|
277
|
+
if (result.authError) {
|
|
278
|
+
onAuthError(result.authError);
|
|
279
|
+
}
|
|
280
|
+
const { authError: handledAuthError, ...props } = result;
|
|
281
|
+
return props;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function createProtectedAuthProps(auth, onAuthError) {
|
|
285
|
+
return async function getProtectedAuth() {
|
|
286
|
+
const result = await getAuthProps(auth);
|
|
287
|
+
if (result.authError) {
|
|
288
|
+
onAuthError(result.authError);
|
|
289
|
+
}
|
|
290
|
+
const { authError: handledAuthError, ...props } = result;
|
|
291
|
+
return props;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function createProtectedFetchers(auth, onAuthError) {
|
|
295
|
+
return {
|
|
296
|
+
getAuthProps: createProtectedAuthProps(auth, onAuthError),
|
|
297
|
+
getData: createProtectedDataFetcher(auth, onAuthError)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
async function withServerAuth(auth, serverRender, options = {}) {
|
|
301
|
+
const result = await getValidSession(auth);
|
|
302
|
+
switch (result.status) {
|
|
303
|
+
case "authenticated":
|
|
304
|
+
return serverRender(result.session);
|
|
305
|
+
case "token_expired":
|
|
306
|
+
if (options.onTokenExpired !== void 0) {
|
|
307
|
+
return typeof options.onTokenExpired === "function" ? options.onTokenExpired() : options.onTokenExpired;
|
|
308
|
+
}
|
|
309
|
+
return serverRender(result.session);
|
|
310
|
+
case "unauthenticated":
|
|
311
|
+
if (options.onUnauthenticated !== void 0) {
|
|
312
|
+
return typeof options.onUnauthenticated === "function" ? options.onUnauthenticated() : options.onUnauthenticated;
|
|
313
|
+
}
|
|
314
|
+
throw new Error("Unauthorized: No active session");
|
|
315
|
+
case "error":
|
|
316
|
+
if (options.onError !== void 0) {
|
|
317
|
+
return typeof options.onError === "function" ? options.onError(result.error) : options.onError;
|
|
318
|
+
}
|
|
319
|
+
throw new Error(`Unauthorized: ${result.error}`);
|
|
320
|
+
default:
|
|
321
|
+
throw new Error("Unknown auth state");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function createAuthMiddleware(auth, options = {}) {
|
|
325
|
+
const { loginUrl = "/login", protectedPaths, publicPaths } = options;
|
|
326
|
+
return async function middleware(request) {
|
|
327
|
+
const { pathname } = request.nextUrl;
|
|
328
|
+
if (publicPaths) {
|
|
329
|
+
const isPublic = publicPaths.some((pattern) => {
|
|
330
|
+
if (typeof pattern === "string") {
|
|
331
|
+
return matchPathPrefix(pathname, pattern);
|
|
332
|
+
}
|
|
333
|
+
return pattern.test(pathname);
|
|
334
|
+
});
|
|
335
|
+
if (isPublic) {
|
|
336
|
+
return server.NextResponse.next();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (protectedPaths) {
|
|
340
|
+
const isProtected = protectedPaths.some((pattern) => {
|
|
341
|
+
if (typeof pattern === "string") {
|
|
342
|
+
return matchPathPrefix(pathname, pattern);
|
|
343
|
+
}
|
|
344
|
+
return pattern.test(pathname);
|
|
345
|
+
});
|
|
346
|
+
if (!isProtected) {
|
|
347
|
+
return server.NextResponse.next();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const session = await auth();
|
|
351
|
+
if (!session) {
|
|
352
|
+
const url = new URL(loginUrl, request.url);
|
|
353
|
+
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
354
|
+
url.searchParams.set("returnTo", returnTo);
|
|
355
|
+
return server.NextResponse.redirect(url);
|
|
356
|
+
}
|
|
357
|
+
if (session.error && session.error !== "TokenExpired") {
|
|
358
|
+
const url = new URL(loginUrl, request.url);
|
|
359
|
+
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
360
|
+
url.searchParams.set("returnTo", returnTo);
|
|
361
|
+
url.searchParams.set("error", session.error);
|
|
362
|
+
return server.NextResponse.redirect(url);
|
|
363
|
+
}
|
|
364
|
+
return server.NextResponse.next();
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function withAuth(auth, handler) {
|
|
368
|
+
return async (...args) => {
|
|
369
|
+
const session = await auth();
|
|
370
|
+
if (!session) {
|
|
371
|
+
throw new Error("Unauthorized: No active session");
|
|
372
|
+
}
|
|
373
|
+
if (session.error && session.error !== "TokenExpired") {
|
|
374
|
+
throw new Error(`Unauthorized: ${session.error}`);
|
|
375
|
+
}
|
|
376
|
+
return handler(session, ...args);
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
exports.createAuthConfig = createAuthConfig;
|
|
381
|
+
exports.createAuthMiddleware = createAuthMiddleware;
|
|
382
|
+
exports.createAuthOptions = createAuthOptions;
|
|
383
|
+
exports.createImmutableAuth = createImmutableAuth;
|
|
384
|
+
exports.createProtectedAuthProps = createProtectedAuthProps;
|
|
385
|
+
exports.createProtectedDataFetcher = createProtectedDataFetcher;
|
|
386
|
+
exports.createProtectedFetchers = createProtectedFetchers;
|
|
387
|
+
exports.getAuthProps = getAuthProps;
|
|
388
|
+
exports.getAuthenticatedData = getAuthenticatedData;
|
|
389
|
+
exports.getValidSession = getValidSession;
|
|
390
|
+
exports.withAuth = withAuth;
|
|
391
|
+
exports.withServerAuth = withServerAuth;
|