@imtbl/auth-next-client 2.12.5-alpha.13
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/.eslintrc.cjs +18 -0
- package/LICENSE.md +176 -0
- package/dist/node/callback.d.ts +56 -0
- package/dist/node/constants.d.ts +32 -0
- package/dist/node/index.cjs +501 -0
- package/dist/node/index.d.ts +15 -0
- package/dist/node/index.js +486 -0
- package/dist/node/provider.d.ts +66 -0
- package/dist/node/types.d.ts +133 -0
- package/dist/node/utils/token.d.ts +8 -0
- package/jest.config.ts +16 -0
- package/package.json +70 -0
- package/src/callback.tsx +281 -0
- package/src/constants.ts +39 -0
- package/src/index.ts +45 -0
- package/src/provider.tsx +547 -0
- package/src/types.ts +148 -0
- package/src/utils/token.ts +39 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +19 -0
- package/tsconfig.types.json +8 -0
- package/tsup.config.ts +33 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var src_exports = {};
|
|
23
|
+
__export(src_exports, {
|
|
24
|
+
CallbackPage: () => CallbackPage,
|
|
25
|
+
ImmutableAuthProvider: () => ImmutableAuthProvider,
|
|
26
|
+
MarketingConsentStatus: () => import_auth4.MarketingConsentStatus,
|
|
27
|
+
useAccessToken: () => useAccessToken,
|
|
28
|
+
useHydratedData: () => useHydratedData,
|
|
29
|
+
useImmutableAuth: () => useImmutableAuth
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(src_exports);
|
|
32
|
+
|
|
33
|
+
// src/provider.tsx
|
|
34
|
+
var import_react = require("react");
|
|
35
|
+
var import_react2 = require("next-auth/react");
|
|
36
|
+
var import_auth2 = require("@imtbl/auth");
|
|
37
|
+
|
|
38
|
+
// src/utils/token.ts
|
|
39
|
+
var import_auth = require("@imtbl/auth");
|
|
40
|
+
|
|
41
|
+
// src/constants.ts
|
|
42
|
+
var DEFAULT_AUTH_DOMAIN = "https://auth.immutable.com";
|
|
43
|
+
var DEFAULT_AUDIENCE = "platform_api";
|
|
44
|
+
var DEFAULT_SCOPE = "openid profile email offline_access transact";
|
|
45
|
+
var IMMUTABLE_PROVIDER_ID = "immutable";
|
|
46
|
+
var DEFAULT_NEXTAUTH_BASE_PATH = "/api/auth";
|
|
47
|
+
var DEFAULT_TOKEN_EXPIRY_SECONDS = 900;
|
|
48
|
+
var DEFAULT_TOKEN_EXPIRY_MS = DEFAULT_TOKEN_EXPIRY_SECONDS * 1e3;
|
|
49
|
+
|
|
50
|
+
// src/utils/token.ts
|
|
51
|
+
function getTokenExpiry(accessToken) {
|
|
52
|
+
if (!accessToken) {
|
|
53
|
+
return Date.now() + DEFAULT_TOKEN_EXPIRY_MS;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const payload = (0, import_auth.decodeJwtPayload)(accessToken);
|
|
57
|
+
if (payload.exp && typeof payload.exp === "number") {
|
|
58
|
+
return payload.exp * 1e3;
|
|
59
|
+
}
|
|
60
|
+
return Date.now() + DEFAULT_TOKEN_EXPIRY_MS;
|
|
61
|
+
} catch {
|
|
62
|
+
return Date.now() + DEFAULT_TOKEN_EXPIRY_MS;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/provider.tsx
|
|
67
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
68
|
+
var ImmutableAuthContext = (0, import_react.createContext)(null);
|
|
69
|
+
function ImmutableAuthInner({
|
|
70
|
+
children,
|
|
71
|
+
config,
|
|
72
|
+
basePath
|
|
73
|
+
}) {
|
|
74
|
+
const [auth, setAuth] = (0, import_react.useState)(null);
|
|
75
|
+
const prevConfigRef = (0, import_react.useRef)(null);
|
|
76
|
+
const authInstanceRef = (0, import_react.useRef)(null);
|
|
77
|
+
const [isAuthReady, setIsAuthReady] = (0, import_react.useState)(false);
|
|
78
|
+
const { data: session, update: updateSession } = (0, import_react2.useSession)();
|
|
79
|
+
(0, import_react.useEffect)(() => {
|
|
80
|
+
if (typeof window === "undefined") return void 0;
|
|
81
|
+
const configKey = [
|
|
82
|
+
config.clientId,
|
|
83
|
+
config.redirectUri,
|
|
84
|
+
config.popupRedirectUri || "",
|
|
85
|
+
config.logoutRedirectUri || "",
|
|
86
|
+
config.audience || DEFAULT_AUDIENCE,
|
|
87
|
+
config.scope || DEFAULT_SCOPE,
|
|
88
|
+
config.authenticationDomain || DEFAULT_AUTH_DOMAIN,
|
|
89
|
+
config.passportDomain || ""
|
|
90
|
+
].join(":");
|
|
91
|
+
if (prevConfigRef.current === configKey && authInstanceRef.current !== null) {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
prevConfigRef.current = configKey;
|
|
95
|
+
const newAuth = new import_auth2.Auth({
|
|
96
|
+
clientId: config.clientId,
|
|
97
|
+
redirectUri: config.redirectUri,
|
|
98
|
+
popupRedirectUri: config.popupRedirectUri,
|
|
99
|
+
logoutRedirectUri: config.logoutRedirectUri,
|
|
100
|
+
audience: config.audience || DEFAULT_AUDIENCE,
|
|
101
|
+
scope: config.scope || DEFAULT_SCOPE,
|
|
102
|
+
authenticationDomain: config.authenticationDomain || DEFAULT_AUTH_DOMAIN,
|
|
103
|
+
passportDomain: config.passportDomain
|
|
104
|
+
});
|
|
105
|
+
authInstanceRef.current = newAuth;
|
|
106
|
+
setAuth(newAuth);
|
|
107
|
+
setIsAuthReady(true);
|
|
108
|
+
return () => {
|
|
109
|
+
authInstanceRef.current = null;
|
|
110
|
+
setAuth(null);
|
|
111
|
+
setIsAuthReady(false);
|
|
112
|
+
};
|
|
113
|
+
}, [config]);
|
|
114
|
+
(0, import_react.useEffect)(() => {
|
|
115
|
+
if (!auth || !isAuthReady) return void 0;
|
|
116
|
+
const handleLoggedIn = async (authUser) => {
|
|
117
|
+
if (session?.accessToken && authUser.accessToken !== session.accessToken) {
|
|
118
|
+
await updateSession({
|
|
119
|
+
accessToken: authUser.accessToken,
|
|
120
|
+
refreshToken: authUser.refreshToken,
|
|
121
|
+
idToken: authUser.idToken,
|
|
122
|
+
accessTokenExpires: getTokenExpiry(authUser.accessToken),
|
|
123
|
+
zkEvm: authUser.zkEvm
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const handleTokenRefreshed = async (authUser) => {
|
|
128
|
+
await updateSession({
|
|
129
|
+
accessToken: authUser.accessToken,
|
|
130
|
+
refreshToken: authUser.refreshToken,
|
|
131
|
+
idToken: authUser.idToken,
|
|
132
|
+
accessTokenExpires: getTokenExpiry(authUser.accessToken),
|
|
133
|
+
zkEvm: authUser.zkEvm
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
const handleUserRemoved = async (payload) => {
|
|
137
|
+
console.warn("[auth-next-client] User removed from Auth SDK:", payload.reason, payload.error);
|
|
138
|
+
await (0, import_react2.signOut)({ redirect: false });
|
|
139
|
+
};
|
|
140
|
+
const handleLoggedOut = async () => {
|
|
141
|
+
await (0, import_react2.signOut)({ redirect: false });
|
|
142
|
+
};
|
|
143
|
+
auth.eventEmitter.on(import_auth2.AuthEvents.LOGGED_IN, handleLoggedIn);
|
|
144
|
+
auth.eventEmitter.on(import_auth2.AuthEvents.TOKEN_REFRESHED, handleTokenRefreshed);
|
|
145
|
+
auth.eventEmitter.on(import_auth2.AuthEvents.USER_REMOVED, handleUserRemoved);
|
|
146
|
+
auth.eventEmitter.on(import_auth2.AuthEvents.LOGGED_OUT, handleLoggedOut);
|
|
147
|
+
return () => {
|
|
148
|
+
auth.eventEmitter.removeListener(import_auth2.AuthEvents.LOGGED_IN, handleLoggedIn);
|
|
149
|
+
auth.eventEmitter.removeListener(import_auth2.AuthEvents.TOKEN_REFRESHED, handleTokenRefreshed);
|
|
150
|
+
auth.eventEmitter.removeListener(import_auth2.AuthEvents.USER_REMOVED, handleUserRemoved);
|
|
151
|
+
auth.eventEmitter.removeListener(import_auth2.AuthEvents.LOGGED_OUT, handleLoggedOut);
|
|
152
|
+
};
|
|
153
|
+
}, [auth, isAuthReady, session, updateSession]);
|
|
154
|
+
const contextValue = (0, import_react.useMemo)(
|
|
155
|
+
() => ({ auth, config, basePath }),
|
|
156
|
+
[auth, config, basePath]
|
|
157
|
+
);
|
|
158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImmutableAuthContext.Provider, { value: contextValue, children });
|
|
159
|
+
}
|
|
160
|
+
function ImmutableAuthProvider({
|
|
161
|
+
children,
|
|
162
|
+
config,
|
|
163
|
+
session,
|
|
164
|
+
basePath = DEFAULT_NEXTAUTH_BASE_PATH
|
|
165
|
+
}) {
|
|
166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.SessionProvider, { session, basePath, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImmutableAuthInner, { config, basePath, children }) });
|
|
167
|
+
}
|
|
168
|
+
function useImmutableAuth() {
|
|
169
|
+
const context = (0, import_react.useContext)(ImmutableAuthContext);
|
|
170
|
+
const { data: sessionData, status } = (0, import_react2.useSession)();
|
|
171
|
+
const [isLoggingIn, setIsLoggingIn] = (0, import_react.useState)(false);
|
|
172
|
+
if (!context) {
|
|
173
|
+
throw new Error("useImmutableAuth must be used within ImmutableAuthProvider");
|
|
174
|
+
}
|
|
175
|
+
const session = sessionData;
|
|
176
|
+
const { auth } = context;
|
|
177
|
+
const isLoading = status === "loading";
|
|
178
|
+
const isAuthenticated = status === "authenticated" && !!session;
|
|
179
|
+
const user = session?.user ? {
|
|
180
|
+
sub: session.user.sub,
|
|
181
|
+
email: session.user.email,
|
|
182
|
+
nickname: session.user.nickname
|
|
183
|
+
} : null;
|
|
184
|
+
const handleSignIn = (0, import_react.useCallback)(async (options) => {
|
|
185
|
+
if (!auth) {
|
|
186
|
+
throw new Error("Auth not initialized");
|
|
187
|
+
}
|
|
188
|
+
setIsLoggingIn(true);
|
|
189
|
+
try {
|
|
190
|
+
const authUser = await auth.login(options);
|
|
191
|
+
if (!authUser) {
|
|
192
|
+
throw new Error("Login failed");
|
|
193
|
+
}
|
|
194
|
+
const tokenData = {
|
|
195
|
+
accessToken: authUser.accessToken,
|
|
196
|
+
refreshToken: authUser.refreshToken,
|
|
197
|
+
idToken: authUser.idToken,
|
|
198
|
+
accessTokenExpires: getTokenExpiry(authUser.accessToken),
|
|
199
|
+
profile: {
|
|
200
|
+
sub: authUser.profile.sub,
|
|
201
|
+
email: authUser.profile.email,
|
|
202
|
+
nickname: authUser.profile.nickname
|
|
203
|
+
},
|
|
204
|
+
zkEvm: authUser.zkEvm
|
|
205
|
+
};
|
|
206
|
+
const result = await (0, import_react2.signIn)(IMMUTABLE_PROVIDER_ID, {
|
|
207
|
+
tokens: JSON.stringify(tokenData),
|
|
208
|
+
redirect: false
|
|
209
|
+
});
|
|
210
|
+
if (result?.error) {
|
|
211
|
+
throw new Error(`NextAuth sign-in failed: ${result.error}`);
|
|
212
|
+
}
|
|
213
|
+
if (!result?.ok) {
|
|
214
|
+
throw new Error("NextAuth sign-in failed: unknown error");
|
|
215
|
+
}
|
|
216
|
+
} finally {
|
|
217
|
+
setIsLoggingIn(false);
|
|
218
|
+
}
|
|
219
|
+
}, [auth]);
|
|
220
|
+
const handleSignOut = (0, import_react.useCallback)(async () => {
|
|
221
|
+
if (auth) {
|
|
222
|
+
try {
|
|
223
|
+
await auth.getLogoutUrl();
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.warn("[auth-next-client] Logout cleanup error:", error);
|
|
226
|
+
await (0, import_react2.signOut)({ redirect: false });
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
await (0, import_react2.signOut)({ redirect: false });
|
|
230
|
+
}
|
|
231
|
+
}, [auth]);
|
|
232
|
+
const getAccessToken = (0, import_react.useCallback)(async () => {
|
|
233
|
+
if (auth) {
|
|
234
|
+
try {
|
|
235
|
+
const token = await auth.getAccessToken();
|
|
236
|
+
if (token) {
|
|
237
|
+
return token;
|
|
238
|
+
}
|
|
239
|
+
} catch {
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (session?.error) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
session.error === "TokenExpired" ? "Session expired. Please log in again." : `Authentication error: ${session.error}`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (session?.accessToken) {
|
|
248
|
+
return session.accessToken;
|
|
249
|
+
}
|
|
250
|
+
throw new Error("No access token available");
|
|
251
|
+
}, [auth, session]);
|
|
252
|
+
return {
|
|
253
|
+
user,
|
|
254
|
+
session,
|
|
255
|
+
isLoading,
|
|
256
|
+
isLoggingIn,
|
|
257
|
+
isAuthenticated,
|
|
258
|
+
signIn: handleSignIn,
|
|
259
|
+
signOut: handleSignOut,
|
|
260
|
+
getAccessToken,
|
|
261
|
+
auth
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function useAccessToken() {
|
|
265
|
+
const { getAccessToken } = useImmutableAuth();
|
|
266
|
+
return getAccessToken;
|
|
267
|
+
}
|
|
268
|
+
function useHydratedData(props, fetcher) {
|
|
269
|
+
const { getAccessToken, auth } = useImmutableAuth();
|
|
270
|
+
const {
|
|
271
|
+
ssr,
|
|
272
|
+
data: serverData,
|
|
273
|
+
fetchError
|
|
274
|
+
} = props;
|
|
275
|
+
const needsClientFetch = !ssr || Boolean(fetchError);
|
|
276
|
+
const [data, setData] = (0, import_react.useState)(serverData);
|
|
277
|
+
const [isLoading, setIsLoading] = (0, import_react.useState)(needsClientFetch);
|
|
278
|
+
const [error, setError] = (0, import_react.useState)(
|
|
279
|
+
fetchError ? new Error(fetchError) : null
|
|
280
|
+
);
|
|
281
|
+
const hasFetchedRef = (0, import_react.useRef)(false);
|
|
282
|
+
const fetchIdRef = (0, import_react.useRef)(0);
|
|
283
|
+
const prevPropsRef = (0, import_react.useRef)({ serverData, ssr, fetchError });
|
|
284
|
+
(0, import_react.useEffect)(() => {
|
|
285
|
+
const prevProps = prevPropsRef.current;
|
|
286
|
+
const propsChanged = prevProps.serverData !== serverData || prevProps.ssr !== ssr || prevProps.fetchError !== fetchError;
|
|
287
|
+
if (propsChanged) {
|
|
288
|
+
prevPropsRef.current = { serverData, ssr, fetchError };
|
|
289
|
+
hasFetchedRef.current = false;
|
|
290
|
+
fetchIdRef.current += 1;
|
|
291
|
+
if (ssr && !fetchError) {
|
|
292
|
+
setData(serverData);
|
|
293
|
+
setIsLoading(false);
|
|
294
|
+
setError(null);
|
|
295
|
+
} else {
|
|
296
|
+
setData(null);
|
|
297
|
+
setIsLoading(true);
|
|
298
|
+
setError(fetchError ? new Error(fetchError) : null);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}, [serverData, ssr, fetchError]);
|
|
302
|
+
const fetchData = (0, import_react.useCallback)(async () => {
|
|
303
|
+
const currentFetchId = fetchIdRef.current;
|
|
304
|
+
setIsLoading(true);
|
|
305
|
+
setError(null);
|
|
306
|
+
try {
|
|
307
|
+
const token = await getAccessToken();
|
|
308
|
+
const result = await fetcher(token);
|
|
309
|
+
if (fetchIdRef.current === currentFetchId) {
|
|
310
|
+
setData(result);
|
|
311
|
+
}
|
|
312
|
+
} catch (err) {
|
|
313
|
+
if (fetchIdRef.current === currentFetchId) {
|
|
314
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
315
|
+
}
|
|
316
|
+
} finally {
|
|
317
|
+
if (fetchIdRef.current === currentFetchId) {
|
|
318
|
+
setIsLoading(false);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}, [fetcher, getAccessToken]);
|
|
322
|
+
(0, import_react.useEffect)(() => {
|
|
323
|
+
if (hasFetchedRef.current) return;
|
|
324
|
+
if (!needsClientFetch) return;
|
|
325
|
+
if (!ssr && !auth) return;
|
|
326
|
+
hasFetchedRef.current = true;
|
|
327
|
+
fetchData();
|
|
328
|
+
}, [needsClientFetch, ssr, auth, fetchData]);
|
|
329
|
+
return {
|
|
330
|
+
data,
|
|
331
|
+
isLoading,
|
|
332
|
+
error,
|
|
333
|
+
refetch: fetchData
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/callback.tsx
|
|
338
|
+
var import_react3 = require("react");
|
|
339
|
+
var import_navigation = require("next/navigation");
|
|
340
|
+
var import_react4 = require("next-auth/react");
|
|
341
|
+
var import_auth3 = require("@imtbl/auth");
|
|
342
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
343
|
+
function getSearchParams() {
|
|
344
|
+
if (typeof window === "undefined") {
|
|
345
|
+
return new URLSearchParams();
|
|
346
|
+
}
|
|
347
|
+
return new URLSearchParams(window.location.search);
|
|
348
|
+
}
|
|
349
|
+
function CallbackPage({
|
|
350
|
+
config,
|
|
351
|
+
redirectTo = "/",
|
|
352
|
+
loadingComponent = null,
|
|
353
|
+
errorComponent,
|
|
354
|
+
onSuccess,
|
|
355
|
+
onError
|
|
356
|
+
}) {
|
|
357
|
+
const router = (0, import_navigation.useRouter)();
|
|
358
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
359
|
+
const callbackProcessedRef = (0, import_react3.useRef)(false);
|
|
360
|
+
(0, import_react3.useEffect)(() => {
|
|
361
|
+
const searchParams = getSearchParams();
|
|
362
|
+
const handleCallback = async () => {
|
|
363
|
+
try {
|
|
364
|
+
const auth = new import_auth3.Auth({
|
|
365
|
+
clientId: config.clientId,
|
|
366
|
+
redirectUri: config.redirectUri,
|
|
367
|
+
popupRedirectUri: config.popupRedirectUri,
|
|
368
|
+
logoutRedirectUri: config.logoutRedirectUri,
|
|
369
|
+
audience: config.audience || DEFAULT_AUDIENCE,
|
|
370
|
+
scope: config.scope || DEFAULT_SCOPE,
|
|
371
|
+
authenticationDomain: config.authenticationDomain || DEFAULT_AUTH_DOMAIN,
|
|
372
|
+
passportDomain: config.passportDomain
|
|
373
|
+
});
|
|
374
|
+
const authUser = await auth.loginCallback();
|
|
375
|
+
if (window.opener) {
|
|
376
|
+
if (!authUser) {
|
|
377
|
+
throw new Error("Authentication failed: no user data received from login callback");
|
|
378
|
+
}
|
|
379
|
+
const user = {
|
|
380
|
+
sub: authUser.profile.sub,
|
|
381
|
+
email: authUser.profile.email,
|
|
382
|
+
nickname: authUser.profile.nickname
|
|
383
|
+
};
|
|
384
|
+
if (onSuccess) {
|
|
385
|
+
await onSuccess(user);
|
|
386
|
+
}
|
|
387
|
+
window.close();
|
|
388
|
+
} else if (authUser) {
|
|
389
|
+
const tokenData = {
|
|
390
|
+
accessToken: authUser.accessToken,
|
|
391
|
+
refreshToken: authUser.refreshToken,
|
|
392
|
+
idToken: authUser.idToken,
|
|
393
|
+
accessTokenExpires: getTokenExpiry(authUser.accessToken),
|
|
394
|
+
profile: {
|
|
395
|
+
sub: authUser.profile.sub,
|
|
396
|
+
email: authUser.profile.email,
|
|
397
|
+
nickname: authUser.profile.nickname
|
|
398
|
+
},
|
|
399
|
+
zkEvm: authUser.zkEvm
|
|
400
|
+
};
|
|
401
|
+
const result = await (0, import_react4.signIn)(IMMUTABLE_PROVIDER_ID, {
|
|
402
|
+
tokens: JSON.stringify(tokenData),
|
|
403
|
+
redirect: false
|
|
404
|
+
});
|
|
405
|
+
if (result?.error) {
|
|
406
|
+
throw new Error(`NextAuth sign-in failed: ${result.error}`);
|
|
407
|
+
}
|
|
408
|
+
if (!result?.ok) {
|
|
409
|
+
throw new Error("NextAuth sign-in failed: unknown error");
|
|
410
|
+
}
|
|
411
|
+
const user = {
|
|
412
|
+
sub: authUser.profile.sub,
|
|
413
|
+
email: authUser.profile.email,
|
|
414
|
+
nickname: authUser.profile.nickname
|
|
415
|
+
};
|
|
416
|
+
if (onSuccess) {
|
|
417
|
+
await onSuccess(user);
|
|
418
|
+
}
|
|
419
|
+
const resolvedRedirectTo = typeof redirectTo === "function" ? redirectTo(user) || "/" : redirectTo;
|
|
420
|
+
router.replace(resolvedRedirectTo);
|
|
421
|
+
} else {
|
|
422
|
+
throw new Error("Authentication failed: no user data received from login callback");
|
|
423
|
+
}
|
|
424
|
+
} catch (err) {
|
|
425
|
+
const errorMessage2 = err instanceof Error ? err.message : "Authentication failed";
|
|
426
|
+
if (onError) {
|
|
427
|
+
onError(errorMessage2);
|
|
428
|
+
}
|
|
429
|
+
setError(errorMessage2);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
const handleOAuthError = () => {
|
|
433
|
+
const errorCode = searchParams.get("error");
|
|
434
|
+
const errorDescription = searchParams.get("error_description");
|
|
435
|
+
const errorMessage2 = errorDescription || errorCode || "Authentication failed";
|
|
436
|
+
if (onError) {
|
|
437
|
+
onError(errorMessage2);
|
|
438
|
+
}
|
|
439
|
+
setError(errorMessage2);
|
|
440
|
+
};
|
|
441
|
+
if (callbackProcessedRef.current) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const hasError = searchParams.get("error");
|
|
445
|
+
const hasCode = searchParams.get("code");
|
|
446
|
+
if (hasError) {
|
|
447
|
+
callbackProcessedRef.current = true;
|
|
448
|
+
handleOAuthError();
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (hasCode) {
|
|
452
|
+
callbackProcessedRef.current = true;
|
|
453
|
+
handleCallback();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
callbackProcessedRef.current = true;
|
|
457
|
+
const errorMessage = "Invalid callback: missing OAuth parameters. Please try logging in again.";
|
|
458
|
+
if (onError) {
|
|
459
|
+
onError(errorMessage);
|
|
460
|
+
}
|
|
461
|
+
setError(errorMessage);
|
|
462
|
+
}, [router, config, redirectTo, onSuccess, onError]);
|
|
463
|
+
if (error) {
|
|
464
|
+
if (errorComponent) {
|
|
465
|
+
return errorComponent(error);
|
|
466
|
+
}
|
|
467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { padding: "2rem", textAlign: "center" }, children: [
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: { color: "#dc3545" }, children: "Authentication Error" }),
|
|
469
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: error }),
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
471
|
+
"button",
|
|
472
|
+
{
|
|
473
|
+
onClick: () => router.push("/"),
|
|
474
|
+
type: "button",
|
|
475
|
+
style: {
|
|
476
|
+
padding: "0.5rem 1rem",
|
|
477
|
+
marginTop: "1rem",
|
|
478
|
+
cursor: "pointer"
|
|
479
|
+
},
|
|
480
|
+
children: "Return to Home"
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
] });
|
|
484
|
+
}
|
|
485
|
+
if (loadingComponent) {
|
|
486
|
+
return loadingComponent;
|
|
487
|
+
}
|
|
488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "2rem", textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: "Completing authentication..." }) });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/index.ts
|
|
492
|
+
var import_auth4 = require("@imtbl/auth");
|
|
493
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
494
|
+
0 && (module.exports = {
|
|
495
|
+
CallbackPage,
|
|
496
|
+
ImmutableAuthProvider,
|
|
497
|
+
MarketingConsentStatus,
|
|
498
|
+
useAccessToken,
|
|
499
|
+
useHydratedData,
|
|
500
|
+
useImmutableAuth
|
|
501
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @imtbl/auth-next-client
|
|
3
|
+
*
|
|
4
|
+
* Client-side components for Immutable Auth.js v5 integration with Next.js.
|
|
5
|
+
* This package provides React components and hooks for authentication.
|
|
6
|
+
*
|
|
7
|
+
* Note: This package depends on @imtbl/auth and should only be used in
|
|
8
|
+
* browser/client environments. For server-side utilities, use @imtbl/auth-next-server.
|
|
9
|
+
*/
|
|
10
|
+
export { ImmutableAuthProvider, useImmutableAuth, useAccessToken, useHydratedData, type UseHydratedDataResult, type HydratedDataProps, } from './provider';
|
|
11
|
+
export { CallbackPage, type CallbackPageProps } from './callback';
|
|
12
|
+
export type { ImmutableAuthProviderProps, UseImmutableAuthReturn, ImmutableUserClient, ImmutableTokenDataClient, ZkEvmInfo, } from './types';
|
|
13
|
+
export type { ImmutableAuthConfig, ImmutableTokenData, ImmutableUser, AuthProps, AuthPropsWithData, ProtectedAuthProps, ProtectedAuthPropsWithData, } from '@imtbl/auth-next-server';
|
|
14
|
+
export type { LoginOptions, DirectLoginOptions } from '@imtbl/auth';
|
|
15
|
+
export { MarketingConsentStatus } from '@imtbl/auth';
|