@imtbl/auth-nextjs 2.12.4-alpha.5 → 2.12.4-alpha.6
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/README.md +133 -120
- package/dist/node/{chunk-OPPMGNFZ.js → chunk-BRDI4KXS.js} +75 -14
- package/dist/node/client/index.cjs +9 -18
- package/dist/node/client/index.js +8 -17
- package/dist/node/index.cjs +39 -21
- package/dist/node/index.js +15 -46
- package/dist/node/server/index.cjs +107 -59
- package/dist/node/server/index.js +48 -47
- package/dist/types/client/callback.d.ts +9 -4
- package/dist/types/client/provider.d.ts +20 -6
- package/dist/types/config.d.ts +9 -11
- package/dist/types/index.d.ts +28 -14
- package/dist/types/refresh.d.ts +1 -1
- package/dist/types/server/index.d.ts +104 -2
- package/dist/types/types.d.ts +19 -32
- package/package.json +5 -5
- package/dist/types/server/with-page-auth.d.ts +0 -94
package/README.md
CHANGED
|
@@ -1,38 +1,58 @@
|
|
|
1
1
|
# @imtbl/auth-nextjs
|
|
2
2
|
|
|
3
|
-
Next.js authentication integration for Immutable SDK using
|
|
3
|
+
Next.js App Router authentication integration for Immutable SDK using Auth.js v5.
|
|
4
4
|
|
|
5
|
-
This package bridges `@imtbl/auth` popup-based authentication with
|
|
5
|
+
This package bridges `@imtbl/auth` popup-based authentication with Auth.js session management, providing:
|
|
6
6
|
|
|
7
7
|
- Server-side session storage in encrypted JWT cookies
|
|
8
8
|
- Automatic token refresh on both server and client
|
|
9
|
-
- Full SSR support with `
|
|
9
|
+
- Full SSR support with `auth()` function
|
|
10
10
|
- React hooks for easy client-side authentication
|
|
11
|
+
- Middleware support for protecting routes
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Next.js 14+ with App Router
|
|
16
|
+
- Auth.js v5 (next-auth@5.x)
|
|
17
|
+
- React 18+
|
|
11
18
|
|
|
12
19
|
## Installation
|
|
13
20
|
|
|
14
21
|
```bash
|
|
15
|
-
pnpm add @imtbl/auth-nextjs next-auth
|
|
22
|
+
pnpm add @imtbl/auth-nextjs next-auth@beta
|
|
16
23
|
```
|
|
17
24
|
|
|
18
25
|
## Quick Start
|
|
19
26
|
|
|
20
|
-
### 1.
|
|
27
|
+
### 1. Create Auth Configuration
|
|
21
28
|
|
|
22
29
|
```typescript
|
|
23
|
-
//
|
|
24
|
-
import {
|
|
30
|
+
// lib/auth.ts
|
|
31
|
+
import { createImmutableAuth } from "@imtbl/auth-nextjs";
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
const config = {
|
|
27
34
|
clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
|
|
28
35
|
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
29
|
-
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const { handlers, auth, signIn, signOut } = createImmutableAuth(config);
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
### 2.
|
|
41
|
+
### 2. Set Up Auth API Route
|
|
33
42
|
|
|
34
43
|
```typescript
|
|
35
|
-
//
|
|
44
|
+
// app/api/auth/[...nextauth]/route.ts
|
|
45
|
+
import { handlers } from "@/lib/auth";
|
|
46
|
+
|
|
47
|
+
export const { GET, POST } = handlers;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Create Callback Page
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// app/callback/page.tsx
|
|
54
|
+
"use client";
|
|
55
|
+
|
|
36
56
|
import { CallbackPage } from "@imtbl/auth-nextjs/client";
|
|
37
57
|
|
|
38
58
|
const config = {
|
|
@@ -45,10 +65,12 @@ export default function Callback() {
|
|
|
45
65
|
}
|
|
46
66
|
```
|
|
47
67
|
|
|
48
|
-
###
|
|
68
|
+
### 4. Add Provider to Layout
|
|
49
69
|
|
|
50
70
|
```typescript
|
|
51
|
-
//
|
|
71
|
+
// app/providers.tsx
|
|
72
|
+
"use client";
|
|
73
|
+
|
|
52
74
|
import { ImmutableAuthProvider } from "@imtbl/auth-nextjs/client";
|
|
53
75
|
|
|
54
76
|
const config = {
|
|
@@ -56,21 +78,39 @@ const config = {
|
|
|
56
78
|
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
57
79
|
};
|
|
58
80
|
|
|
59
|
-
export
|
|
81
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
60
82
|
return (
|
|
61
|
-
<ImmutableAuthProvider config={config}
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
<ImmutableAuthProvider config={config}>{children}</ImmutableAuthProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// app/layout.tsx
|
|
88
|
+
import { Providers } from "./providers";
|
|
89
|
+
|
|
90
|
+
export default function RootLayout({
|
|
91
|
+
children,
|
|
92
|
+
}: {
|
|
93
|
+
children: React.ReactNode;
|
|
94
|
+
}) {
|
|
95
|
+
return (
|
|
96
|
+
<html>
|
|
97
|
+
<body>
|
|
98
|
+
<Providers>{children}</Providers>
|
|
99
|
+
</body>
|
|
100
|
+
</html>
|
|
64
101
|
);
|
|
65
102
|
}
|
|
66
103
|
```
|
|
67
104
|
|
|
68
|
-
###
|
|
105
|
+
### 5. Use in Components
|
|
69
106
|
|
|
70
107
|
```typescript
|
|
108
|
+
// app/components/LoginButton.tsx
|
|
109
|
+
"use client";
|
|
110
|
+
|
|
71
111
|
import { useImmutableAuth } from "@imtbl/auth-nextjs/client";
|
|
72
112
|
|
|
73
|
-
function LoginButton() {
|
|
113
|
+
export function LoginButton() {
|
|
74
114
|
const { user, isLoading, signIn, signOut } = useImmutableAuth();
|
|
75
115
|
|
|
76
116
|
if (isLoading) return <div>Loading...</div>;
|
|
@@ -84,52 +124,42 @@ function LoginButton() {
|
|
|
84
124
|
);
|
|
85
125
|
}
|
|
86
126
|
|
|
87
|
-
return <button onClick={signIn}>Login with Immutable</button>;
|
|
127
|
+
return <button onClick={() => signIn()}>Login with Immutable</button>;
|
|
88
128
|
}
|
|
89
129
|
```
|
|
90
130
|
|
|
91
|
-
###
|
|
131
|
+
### 6. Access Session in Server Components
|
|
92
132
|
|
|
93
133
|
```typescript
|
|
94
|
-
//
|
|
95
|
-
import {
|
|
96
|
-
import
|
|
134
|
+
// app/profile/page.tsx
|
|
135
|
+
import { auth } from "@/lib/auth";
|
|
136
|
+
import { redirect } from "next/navigation";
|
|
97
137
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
101
|
-
};
|
|
138
|
+
export default async function ProfilePage() {
|
|
139
|
+
const session = await auth();
|
|
102
140
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
141
|
+
if (!session) {
|
|
142
|
+
redirect("/login");
|
|
143
|
+
}
|
|
107
144
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return { props: { user: session?.user ?? null } };
|
|
111
|
-
};
|
|
145
|
+
return <h1>Welcome, {session.user.email}</h1>;
|
|
146
|
+
}
|
|
112
147
|
```
|
|
113
148
|
|
|
114
|
-
###
|
|
149
|
+
### 7. Protect Routes with Middleware (Optional)
|
|
115
150
|
|
|
116
151
|
```typescript
|
|
117
|
-
//
|
|
118
|
-
import {
|
|
119
|
-
|
|
120
|
-
const config = {
|
|
121
|
-
clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
|
|
122
|
-
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
123
|
-
};
|
|
152
|
+
// middleware.ts
|
|
153
|
+
import { createAuthMiddleware } from "@imtbl/auth-nextjs/server";
|
|
154
|
+
import { auth } from "@/lib/auth";
|
|
124
155
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default DashboardPage;
|
|
156
|
+
export default createAuthMiddleware(auth, {
|
|
157
|
+
loginUrl: "/login",
|
|
158
|
+
});
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
|
|
160
|
+
export const config = {
|
|
161
|
+
matcher: ["/dashboard/:path*", "/profile/:path*"],
|
|
162
|
+
};
|
|
133
163
|
```
|
|
134
164
|
|
|
135
165
|
## Configuration Options
|
|
@@ -152,9 +182,8 @@ The `ImmutableAuthConfig` object accepts the following properties:
|
|
|
152
182
|
NEXT_PUBLIC_IMMUTABLE_CLIENT_ID=your-client-id
|
|
153
183
|
NEXT_PUBLIC_BASE_URL=http://localhost:3000
|
|
154
184
|
|
|
155
|
-
# Required by
|
|
156
|
-
|
|
157
|
-
NEXTAUTH_URL=http://localhost:3000
|
|
185
|
+
# Required by Auth.js for cookie encryption
|
|
186
|
+
AUTH_SECRET=generate-with-openssl-rand-base64-32
|
|
158
187
|
```
|
|
159
188
|
|
|
160
189
|
Generate a secret:
|
|
@@ -167,99 +196,83 @@ openssl rand -base64 32
|
|
|
167
196
|
|
|
168
197
|
### Main Exports (`@imtbl/auth-nextjs`)
|
|
169
198
|
|
|
170
|
-
| Export
|
|
171
|
-
|
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
199
|
+
| Export | Description |
|
|
200
|
+
| --------------------------------------- | ------------------------------------------------------------------- |
|
|
201
|
+
| `createImmutableAuth(config, options?)` | Creates Auth.js instance with `{ handlers, auth, signIn, signOut }` |
|
|
202
|
+
| `createAuthConfig(config)` | Creates Auth.js config (for advanced use) |
|
|
203
|
+
| `refreshAccessToken(token, config)` | Utility to refresh an expired access token |
|
|
204
|
+
| `isTokenExpired(expires, buffer?)` | Utility to check if a token is expired |
|
|
175
205
|
|
|
176
206
|
**Types:**
|
|
177
207
|
|
|
178
|
-
| Type
|
|
179
|
-
|
|
|
180
|
-
| `ImmutableAuthConfig`
|
|
181
|
-
| `ImmutableAuthOverrides`
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
208
|
+
| Type | Description |
|
|
209
|
+
| ------------------------ | ----------------------------------------- |
|
|
210
|
+
| `ImmutableAuthConfig` | Configuration options |
|
|
211
|
+
| `ImmutableAuthOverrides` | Auth.js options override type |
|
|
212
|
+
| `ImmutableAuthResult` | Return type of createImmutableAuth |
|
|
213
|
+
| `ImmutableUser` | User profile type |
|
|
214
|
+
| `ImmutableTokenData` | Token data passed to credentials provider |
|
|
215
|
+
| `ZkEvmInfo` | zkEVM wallet information type |
|
|
186
216
|
|
|
187
217
|
### Client Exports (`@imtbl/auth-nextjs/client`)
|
|
188
218
|
|
|
189
|
-
| Export | Description
|
|
190
|
-
| ----------------------- |
|
|
191
|
-
| `ImmutableAuthProvider` | React context provider (wraps
|
|
192
|
-
| `useImmutableAuth()` | Hook for authentication state and methods (see below)
|
|
193
|
-
| `useAccessToken()` | Hook returning `getAccessToken` function
|
|
194
|
-
| `CallbackPage` | Pre-built callback page component for OAuth redirects
|
|
219
|
+
| Export | Description |
|
|
220
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
221
|
+
| `ImmutableAuthProvider` | React context provider (wraps Auth.js SessionProvider) |
|
|
222
|
+
| `useImmutableAuth()` | Hook for authentication state and methods (see below) |
|
|
223
|
+
| `useAccessToken()` | Hook returning `getAccessToken` function |
|
|
224
|
+
| `CallbackPage` | Pre-built callback page component for OAuth redirects |
|
|
195
225
|
|
|
196
226
|
**`useImmutableAuth()` Return Value:**
|
|
197
227
|
|
|
198
228
|
| Property | Type | Description |
|
|
199
229
|
| ----------------- | ----------------------- | ------------------------------------------------ |
|
|
200
230
|
| `user` | `ImmutableUser \| null` | Current user profile (null if not authenticated) |
|
|
201
|
-
| `session` | `Session \| null` | Full
|
|
231
|
+
| `session` | `Session \| null` | Full Auth.js session with tokens |
|
|
202
232
|
| `isLoading` | `boolean` | Whether authentication state is loading |
|
|
203
233
|
| `isAuthenticated` | `boolean` | Whether user is authenticated |
|
|
204
|
-
| `signIn` | `() => Promise
|
|
205
|
-
| `signOut` | `() => Promise<void>` | Sign out from both
|
|
234
|
+
| `signIn` | `(options?) => Promise` | Sign in with Immutable (opens popup) |
|
|
235
|
+
| `signOut` | `() => Promise<void>` | Sign out from both Auth.js and Immutable |
|
|
206
236
|
| `getAccessToken` | `() => Promise<string>` | Get a valid access token (refreshes if needed) |
|
|
207
237
|
| `auth` | `Auth \| null` | The underlying Auth instance (for advanced use) |
|
|
208
238
|
|
|
209
|
-
**Types:**
|
|
210
|
-
|
|
211
|
-
| Type | Description |
|
|
212
|
-
| ---------------------------- | -------------------------------- |
|
|
213
|
-
| `ImmutableAuthProviderProps` | Props for the provider component |
|
|
214
|
-
| `UseImmutableAuthReturn` | Return type of useImmutableAuth |
|
|
215
|
-
| `CallbackPageProps` | Props for CallbackPage component |
|
|
216
|
-
| `ImmutableAuthConfig` | Re-exported configuration type |
|
|
217
|
-
| `ImmutableUser` | Re-exported user type |
|
|
218
|
-
|
|
219
239
|
### Server Exports (`@imtbl/auth-nextjs/server`)
|
|
220
240
|
|
|
221
|
-
| Export
|
|
222
|
-
|
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
|
|
226
|
-
**`withPageAuthRequired` Options:**
|
|
227
|
-
|
|
228
|
-
| Option | Type | Default | Description |
|
|
229
|
-
| -------------------- | ----------------------- | ------------ | ---------------------------------------------------- |
|
|
230
|
-
| `loginUrl` | `string` | `"/login"` | URL to redirect to when not authenticated |
|
|
231
|
-
| `returnTo` | `string \| false` | current page | URL to redirect to after login (`false` to disable) |
|
|
232
|
-
| `getServerSideProps` | `(ctx, session) => ...` | - | Custom getServerSideProps that runs after auth check |
|
|
233
|
-
|
|
234
|
-
**Example with custom getServerSideProps:**
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
export const getServerSideProps = withPageAuthRequired(config, {
|
|
238
|
-
loginUrl: "/auth/signin",
|
|
239
|
-
async getServerSideProps(ctx, session) {
|
|
240
|
-
// session is guaranteed to exist here
|
|
241
|
-
const data = await fetchData(session.accessToken);
|
|
242
|
-
return { props: { data } };
|
|
243
|
-
},
|
|
244
|
-
});
|
|
245
|
-
```
|
|
241
|
+
| Export | Description |
|
|
242
|
+
| ----------------------------------- | ------------------------------------------------ |
|
|
243
|
+
| `createImmutableAuth` | Re-exported for convenience |
|
|
244
|
+
| `createAuthMiddleware(auth, opts?)` | Create middleware for protecting routes |
|
|
245
|
+
| `withAuth(auth, handler)` | HOC for protecting Server Actions/Route Handlers |
|
|
246
246
|
|
|
247
|
-
|
|
247
|
+
**`createAuthMiddleware` Options:**
|
|
248
248
|
|
|
249
|
-
| Type
|
|
250
|
-
|
|
|
251
|
-
| `
|
|
252
|
-
| `
|
|
253
|
-
| `
|
|
249
|
+
| Option | Type | Default | Description |
|
|
250
|
+
| ---------------- | ---------------------- | ---------- | -------------------------------------- |
|
|
251
|
+
| `loginUrl` | `string` | `"/login"` | URL to redirect when not authenticated |
|
|
252
|
+
| `protectedPaths` | `(string \| RegExp)[]` | - | Paths that require authentication |
|
|
253
|
+
| `publicPaths` | `(string \| RegExp)[]` | - | Paths to exclude from protection |
|
|
254
254
|
|
|
255
255
|
## How It Works
|
|
256
256
|
|
|
257
257
|
1. **Login**: User clicks login → `@imtbl/auth` opens popup → tokens returned
|
|
258
|
-
2. **Session Creation**: Tokens passed to
|
|
259
|
-
3. **Token Refresh**:
|
|
260
|
-
4. **SSR**: `
|
|
258
|
+
2. **Session Creation**: Tokens passed to Auth.js credentials provider → stored in encrypted JWT cookie
|
|
259
|
+
3. **Token Refresh**: Auth.js JWT callback automatically refreshes expired tokens using refresh_token
|
|
260
|
+
4. **SSR**: `auth()` reads and decrypts cookie, providing full session with tokens
|
|
261
261
|
5. **Auto-hydration**: If localStorage is cleared but session cookie exists, the Auth instance is automatically hydrated from session tokens
|
|
262
262
|
|
|
263
|
+
## Migration from v4 (Pages Router)
|
|
264
|
+
|
|
265
|
+
If you're migrating from the Pages Router version:
|
|
266
|
+
|
|
267
|
+
| v4 (Pages Router) | v5 (App Router) |
|
|
268
|
+
| --------------------------------------- | --------------------------------------------- |
|
|
269
|
+
| `ImmutableAuth(config)` | `createImmutableAuth(config)` |
|
|
270
|
+
| `getImmutableSession(req, res, config)` | `auth()` (from createImmutableAuth) |
|
|
271
|
+
| `withPageAuthRequired(config)` | `createAuthMiddleware(auth)` or layout checks |
|
|
272
|
+
| `pages/api/auth/[...nextauth].ts` | `app/api/auth/[...nextauth]/route.ts` |
|
|
273
|
+
| `pages/_app.tsx` with provider | `app/layout.tsx` with provider |
|
|
274
|
+
| `NEXTAUTH_SECRET` | `AUTH_SECRET` |
|
|
275
|
+
|
|
263
276
|
## License
|
|
264
277
|
|
|
265
278
|
Apache-2.0
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import NextAuthImport from "next-auth";
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
import CredentialsImport from "next-auth/providers/credentials";
|
|
6
|
+
|
|
1
7
|
// src/constants.ts
|
|
2
8
|
var DEFAULT_AUTH_DOMAIN = "https://auth.immutable.com";
|
|
9
|
+
var DEFAULT_AUDIENCE = "platform_api";
|
|
10
|
+
var DEFAULT_SCOPE = "openid profile email offline_access transact";
|
|
3
11
|
var IMMUTABLE_PROVIDER_ID = "immutable";
|
|
12
|
+
var DEFAULT_NEXTAUTH_BASE_PATH = "/api/auth";
|
|
4
13
|
var DEFAULT_TOKEN_EXPIRY_SECONDS = 900;
|
|
5
14
|
var DEFAULT_TOKEN_EXPIRY_MS = DEFAULT_TOKEN_EXPIRY_SECONDS * 1e3;
|
|
6
15
|
var TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
@@ -68,8 +77,7 @@ function isTokenExpired(accessTokenExpires, bufferSeconds = TOKEN_EXPIRY_BUFFER_
|
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
// src/config.ts
|
|
71
|
-
|
|
72
|
-
var CredentialsProvider = Credentials.default || Credentials;
|
|
80
|
+
var Credentials = CredentialsImport.default || CredentialsImport;
|
|
73
81
|
async function validateTokens(accessToken, authDomain) {
|
|
74
82
|
try {
|
|
75
83
|
const response = await fetch(`${authDomain}/userinfo`, {
|
|
@@ -88,18 +96,18 @@ async function validateTokens(accessToken, authDomain) {
|
|
|
88
96
|
return null;
|
|
89
97
|
}
|
|
90
98
|
}
|
|
91
|
-
function
|
|
99
|
+
function createAuthConfig(config) {
|
|
92
100
|
const authDomain = config.authenticationDomain || DEFAULT_AUTH_DOMAIN;
|
|
93
101
|
return {
|
|
94
102
|
providers: [
|
|
95
|
-
|
|
103
|
+
Credentials({
|
|
96
104
|
id: IMMUTABLE_PROVIDER_ID,
|
|
97
105
|
name: "Immutable",
|
|
98
106
|
credentials: {
|
|
99
107
|
tokens: { label: "Tokens", type: "text" }
|
|
100
108
|
},
|
|
101
109
|
async authorize(credentials) {
|
|
102
|
-
if (!credentials?.tokens) {
|
|
110
|
+
if (!credentials?.tokens || typeof credentials.tokens !== "string") {
|
|
103
111
|
return null;
|
|
104
112
|
}
|
|
105
113
|
let tokenData;
|
|
@@ -142,6 +150,7 @@ function createAuthOptions(config) {
|
|
|
142
150
|
})
|
|
143
151
|
],
|
|
144
152
|
callbacks: {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
154
|
async jwt({
|
|
146
155
|
token,
|
|
147
156
|
user,
|
|
@@ -162,13 +171,14 @@ function createAuthOptions(config) {
|
|
|
162
171
|
};
|
|
163
172
|
}
|
|
164
173
|
if (trigger === "update" && sessionUpdate) {
|
|
174
|
+
const update = sessionUpdate;
|
|
165
175
|
return {
|
|
166
176
|
...token,
|
|
167
|
-
...
|
|
168
|
-
...
|
|
169
|
-
...
|
|
170
|
-
...
|
|
171
|
-
...
|
|
177
|
+
...update.accessToken ? { accessToken: update.accessToken } : {},
|
|
178
|
+
...update.refreshToken ? { refreshToken: update.refreshToken } : {},
|
|
179
|
+
...update.idToken ? { idToken: update.idToken } : {},
|
|
180
|
+
...update.accessTokenExpires ? { accessTokenExpires: update.accessTokenExpires } : {},
|
|
181
|
+
...update.zkEvm ? { zkEvm: update.zkEvm } : {}
|
|
172
182
|
};
|
|
173
183
|
}
|
|
174
184
|
if (!isTokenExpired(token.accessTokenExpires)) {
|
|
@@ -176,10 +186,12 @@ function createAuthOptions(config) {
|
|
|
176
186
|
}
|
|
177
187
|
return refreshAccessToken(token, config);
|
|
178
188
|
},
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
179
190
|
async session({ session, token }) {
|
|
180
191
|
return {
|
|
181
192
|
...session,
|
|
182
193
|
user: {
|
|
194
|
+
...session.user,
|
|
183
195
|
sub: token.sub,
|
|
184
196
|
email: token.email,
|
|
185
197
|
nickname: token.nickname
|
|
@@ -197,14 +209,63 @@ function createAuthOptions(config) {
|
|
|
197
209
|
strategy: "jwt",
|
|
198
210
|
// Session max age in seconds (30 days default)
|
|
199
211
|
maxAge: DEFAULT_SESSION_MAX_AGE_SECONDS
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/index.ts
|
|
217
|
+
import { MarketingConsentStatus } from "@imtbl/auth";
|
|
218
|
+
var NextAuth = NextAuthImport.default || NextAuthImport;
|
|
219
|
+
function createImmutableAuth(config, overrides) {
|
|
220
|
+
const authConfig = createAuthConfig(config);
|
|
221
|
+
if (!overrides) {
|
|
222
|
+
return NextAuth(authConfig);
|
|
223
|
+
}
|
|
224
|
+
const composedCallbacks = {
|
|
225
|
+
...authConfig.callbacks
|
|
226
|
+
};
|
|
227
|
+
if (overrides.callbacks) {
|
|
228
|
+
if (overrides.callbacks.jwt) {
|
|
229
|
+
const internalJwt = authConfig.callbacks?.jwt;
|
|
230
|
+
const userJwt = overrides.callbacks.jwt;
|
|
231
|
+
composedCallbacks.jwt = async (params) => {
|
|
232
|
+
const token = internalJwt ? await internalJwt(params) : params.token;
|
|
233
|
+
return userJwt({ ...params, token });
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (overrides.callbacks.session) {
|
|
237
|
+
const internalSession = authConfig.callbacks?.session;
|
|
238
|
+
const userSession = overrides.callbacks.session;
|
|
239
|
+
composedCallbacks.session = async (params) => {
|
|
240
|
+
const session = internalSession ? await internalSession(params) : params.session;
|
|
241
|
+
return userSession({ ...params, session });
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (overrides.callbacks.signIn) {
|
|
245
|
+
composedCallbacks.signIn = overrides.callbacks.signIn;
|
|
246
|
+
}
|
|
247
|
+
if (overrides.callbacks.redirect) {
|
|
248
|
+
composedCallbacks.redirect = overrides.callbacks.redirect;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const mergedConfig = {
|
|
252
|
+
...authConfig,
|
|
253
|
+
...overrides,
|
|
254
|
+
callbacks: composedCallbacks
|
|
203
255
|
};
|
|
256
|
+
return NextAuth(mergedConfig);
|
|
204
257
|
}
|
|
258
|
+
var ImmutableAuth = createImmutableAuth;
|
|
205
259
|
|
|
206
260
|
export {
|
|
261
|
+
DEFAULT_AUTH_DOMAIN,
|
|
262
|
+
DEFAULT_AUDIENCE,
|
|
263
|
+
DEFAULT_SCOPE,
|
|
264
|
+
DEFAULT_NEXTAUTH_BASE_PATH,
|
|
207
265
|
refreshAccessToken,
|
|
208
266
|
isTokenExpired,
|
|
209
|
-
|
|
267
|
+
createAuthConfig,
|
|
268
|
+
createImmutableAuth,
|
|
269
|
+
ImmutableAuth,
|
|
270
|
+
MarketingConsentStatus
|
|
210
271
|
};
|
|
@@ -254,7 +254,7 @@ function useAccessToken() {
|
|
|
254
254
|
|
|
255
255
|
// src/client/callback.tsx
|
|
256
256
|
var import_react3 = require("react");
|
|
257
|
-
var
|
|
257
|
+
var import_navigation = require("next/navigation");
|
|
258
258
|
var import_react4 = require("next-auth/react");
|
|
259
259
|
var import_auth3 = require("@imtbl/auth");
|
|
260
260
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -264,7 +264,8 @@ function CallbackPage({
|
|
|
264
264
|
loadingComponent = null,
|
|
265
265
|
errorComponent
|
|
266
266
|
}) {
|
|
267
|
-
const router = (0,
|
|
267
|
+
const router = (0, import_navigation.useRouter)();
|
|
268
|
+
const searchParams = (0, import_navigation.useSearchParams)();
|
|
268
269
|
const [error, setError] = (0, import_react3.useState)(null);
|
|
269
270
|
const callbackProcessedRef = (0, import_react3.useRef)(false);
|
|
270
271
|
(0, import_react3.useEffect)(() => {
|
|
@@ -316,31 +317,20 @@ function CallbackPage({
|
|
|
316
317
|
}
|
|
317
318
|
};
|
|
318
319
|
const handleOAuthError = () => {
|
|
319
|
-
const errorCode =
|
|
320
|
-
const errorDescription =
|
|
320
|
+
const errorCode = searchParams.get("error");
|
|
321
|
+
const errorDescription = searchParams.get("error_description");
|
|
321
322
|
const errorMessage = errorDescription || errorCode || "Authentication failed";
|
|
322
323
|
setError(errorMessage);
|
|
323
324
|
};
|
|
324
|
-
if (
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
if (router.query.error) {
|
|
325
|
+
if (searchParams.get("error")) {
|
|
328
326
|
handleOAuthError();
|
|
329
327
|
return;
|
|
330
328
|
}
|
|
331
|
-
if (
|
|
329
|
+
if (searchParams.get("code") && !callbackProcessedRef.current) {
|
|
332
330
|
callbackProcessedRef.current = true;
|
|
333
331
|
handleCallback();
|
|
334
332
|
}
|
|
335
|
-
}, [
|
|
336
|
-
router.isReady,
|
|
337
|
-
router.query.code,
|
|
338
|
-
router.query.error,
|
|
339
|
-
router.query.error_description,
|
|
340
|
-
router,
|
|
341
|
-
config,
|
|
342
|
-
redirectTo
|
|
343
|
-
]);
|
|
333
|
+
}, [searchParams, router, config, redirectTo]);
|
|
344
334
|
if (error) {
|
|
345
335
|
if (errorComponent) {
|
|
346
336
|
return errorComponent(error);
|
|
@@ -352,6 +342,7 @@ function CallbackPage({
|
|
|
352
342
|
"button",
|
|
353
343
|
{
|
|
354
344
|
onClick: () => router.push("/"),
|
|
345
|
+
type: "button",
|
|
355
346
|
style: {
|
|
356
347
|
padding: "0.5rem 1rem",
|
|
357
348
|
marginTop: "1rem",
|
|
@@ -240,7 +240,7 @@ function useAccessToken() {
|
|
|
240
240
|
|
|
241
241
|
// src/client/callback.tsx
|
|
242
242
|
import { useEffect as useEffect2, useState as useState2, useRef as useRef2 } from "react";
|
|
243
|
-
import { useRouter } from "next/
|
|
243
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
244
244
|
import { signIn as signIn2 } from "next-auth/react";
|
|
245
245
|
import { Auth as Auth2 } from "@imtbl/auth";
|
|
246
246
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
@@ -251,6 +251,7 @@ function CallbackPage({
|
|
|
251
251
|
errorComponent
|
|
252
252
|
}) {
|
|
253
253
|
const router = useRouter();
|
|
254
|
+
const searchParams = useSearchParams();
|
|
254
255
|
const [error, setError] = useState2(null);
|
|
255
256
|
const callbackProcessedRef = useRef2(false);
|
|
256
257
|
useEffect2(() => {
|
|
@@ -302,31 +303,20 @@ function CallbackPage({
|
|
|
302
303
|
}
|
|
303
304
|
};
|
|
304
305
|
const handleOAuthError = () => {
|
|
305
|
-
const errorCode =
|
|
306
|
-
const errorDescription =
|
|
306
|
+
const errorCode = searchParams.get("error");
|
|
307
|
+
const errorDescription = searchParams.get("error_description");
|
|
307
308
|
const errorMessage = errorDescription || errorCode || "Authentication failed";
|
|
308
309
|
setError(errorMessage);
|
|
309
310
|
};
|
|
310
|
-
if (
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
if (router.query.error) {
|
|
311
|
+
if (searchParams.get("error")) {
|
|
314
312
|
handleOAuthError();
|
|
315
313
|
return;
|
|
316
314
|
}
|
|
317
|
-
if (
|
|
315
|
+
if (searchParams.get("code") && !callbackProcessedRef.current) {
|
|
318
316
|
callbackProcessedRef.current = true;
|
|
319
317
|
handleCallback();
|
|
320
318
|
}
|
|
321
|
-
}, [
|
|
322
|
-
router.isReady,
|
|
323
|
-
router.query.code,
|
|
324
|
-
router.query.error,
|
|
325
|
-
router.query.error_description,
|
|
326
|
-
router,
|
|
327
|
-
config,
|
|
328
|
-
redirectTo
|
|
329
|
-
]);
|
|
319
|
+
}, [searchParams, router, config, redirectTo]);
|
|
330
320
|
if (error) {
|
|
331
321
|
if (errorComponent) {
|
|
332
322
|
return errorComponent(error);
|
|
@@ -338,6 +328,7 @@ function CallbackPage({
|
|
|
338
328
|
"button",
|
|
339
329
|
{
|
|
340
330
|
onClick: () => router.push("/"),
|
|
331
|
+
type: "button",
|
|
341
332
|
style: {
|
|
342
333
|
padding: "0.5rem 1rem",
|
|
343
334
|
marginTop: "1rem",
|