@imtbl/auth-next-server 2.12.7-alpha.1 → 2.12.7-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/README.md +128 -64
- package/dist/node/index.cjs +141 -75
- package/dist/node/index.js +131 -75
- package/dist/types/config.d.ts +20 -7
- package/dist/types/constants.d.ts +17 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +3 -3
- package/src/config.ts +163 -99
- package/src/constants.ts +21 -0
- package/src/index.ts +12 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ Server-side utilities for Immutable authentication with Auth.js v5 (NextAuth) in
|
|
|
7
7
|
This package provides server-side authentication utilities for Next.js applications using the App Router. It integrates with Auth.js v5 to handle OAuth authentication with Immutable's identity provider.
|
|
8
8
|
|
|
9
9
|
**Key features:**
|
|
10
|
+
|
|
10
11
|
- Auth.js v5 configuration for Immutable authentication
|
|
11
12
|
- Route protection via middleware
|
|
12
13
|
- Server utilities for authenticated data fetching
|
|
@@ -29,6 +30,16 @@ yarn add @imtbl/auth-next-server next-auth@5
|
|
|
29
30
|
- `next` >= 14.0.0
|
|
30
31
|
- `next-auth` >= 5.0.0-beta.25
|
|
31
32
|
|
|
33
|
+
### Next.js 14 Compatibility
|
|
34
|
+
|
|
35
|
+
This package is compatible with both Next.js 14 and 15. It uses only standard APIs available in both versions:
|
|
36
|
+
|
|
37
|
+
- `next/server`: `NextRequest`, `NextResponse` (middleware)
|
|
38
|
+
- `next/navigation`: `redirect` (Server Components)
|
|
39
|
+
- NextAuth v5 with App Router
|
|
40
|
+
|
|
41
|
+
No Next.js 15-only APIs are used (e.g. async `headers()`/`cookies()`, `unstable_after`).
|
|
42
|
+
|
|
32
43
|
## Quick Start
|
|
33
44
|
|
|
34
45
|
### 1. Create Auth Configuration
|
|
@@ -40,10 +51,12 @@ Create a file to configure Immutable authentication:
|
|
|
40
51
|
import NextAuth from "next-auth";
|
|
41
52
|
import { createAuthConfig } from "@imtbl/auth-next-server";
|
|
42
53
|
|
|
43
|
-
export const { handlers, auth, signIn, signOut } = NextAuth(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
54
|
+
export const { handlers, auth, signIn, signOut } = NextAuth(
|
|
55
|
+
createAuthConfig({
|
|
56
|
+
clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
|
|
57
|
+
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
47
60
|
```
|
|
48
61
|
|
|
49
62
|
### 2. Set Up API Route
|
|
@@ -66,37 +79,75 @@ NEXT_PUBLIC_BASE_URL=http://localhost:3000
|
|
|
66
79
|
AUTH_SECRET=your-secret-key-min-32-characters
|
|
67
80
|
```
|
|
68
81
|
|
|
82
|
+
## Default Auth (Zero Config)
|
|
83
|
+
|
|
84
|
+
Policy: **provide nothing → full sandbox; provide config → provide everything.**
|
|
85
|
+
|
|
86
|
+
With no configuration, `createAuthConfig()` uses sandbox defaults:
|
|
87
|
+
- `clientId`: sandbox (public Immutable client ID)
|
|
88
|
+
- `redirectUri`: from `window.location.origin + '/callback'` (path only on server)
|
|
89
|
+
|
|
90
|
+
When providing config, pass `clientId` and `redirectUri` (and optionally `audience`, `scope`, `authenticationDomain`) to avoid conflicts.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// lib/auth.ts
|
|
94
|
+
import NextAuth from "next-auth";
|
|
95
|
+
import { createAuthConfig } from "@imtbl/auth-next-server";
|
|
96
|
+
|
|
97
|
+
// Zero config - only AUTH_SECRET required in .env
|
|
98
|
+
export const { handlers, auth, signIn, signOut } = NextAuth(createAuthConfig());
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
With partial overrides:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// With config - provide clientId and redirectUri
|
|
105
|
+
export const { handlers, auth, signIn, signOut } = NextAuth(
|
|
106
|
+
createAuthConfig({
|
|
107
|
+
clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
|
|
108
|
+
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
> **Note:** Default auth uses public Immutable client IDs. For production apps, use your own client ID from Immutable Hub.
|
|
114
|
+
|
|
69
115
|
## Configuration
|
|
70
116
|
|
|
71
|
-
### `createAuthConfig(config)`
|
|
117
|
+
### `createAuthConfig(config?)`
|
|
72
118
|
|
|
73
|
-
Creates an Auth.js v5 configuration object for Immutable authentication.
|
|
119
|
+
Creates an Auth.js v5 configuration object for Immutable authentication. Config is optional—when omitted, sensible defaults are used. Pass this to `NextAuth()` to create your auth instance.
|
|
74
120
|
|
|
75
121
|
```typescript
|
|
76
122
|
import NextAuth from "next-auth";
|
|
77
123
|
import { createAuthConfig } from "@imtbl/auth-next-server";
|
|
78
124
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
125
|
+
// Zero config
|
|
126
|
+
const { handlers, auth, signIn, signOut } = NextAuth(createAuthConfig());
|
|
127
|
+
|
|
128
|
+
// Or with custom config
|
|
129
|
+
const { handlers, auth, signIn, signOut } = NextAuth(
|
|
130
|
+
createAuthConfig({
|
|
131
|
+
clientId: "your-client-id",
|
|
132
|
+
redirectUri: "https://your-app.com/callback",
|
|
133
|
+
|
|
134
|
+
// Optional
|
|
135
|
+
audience: "platform_api", // Default: "platform_api"
|
|
136
|
+
scope: "openid profile email offline_access transact", // Default scope
|
|
137
|
+
authenticationDomain: "https://auth.immutable.com", // Default domain
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
89
140
|
```
|
|
90
141
|
|
|
91
142
|
#### Configuration Options
|
|
92
143
|
|
|
93
|
-
| Option
|
|
94
|
-
|
|
95
|
-
| `clientId`
|
|
96
|
-
| `redirectUri`
|
|
97
|
-
| `audience`
|
|
98
|
-
| `scope`
|
|
99
|
-
| `authenticationDomain` | `string` | No
|
|
144
|
+
| Option | Type | Required | Description |
|
|
145
|
+
| ---------------------- | -------- | -------- | ------------------------------------------------------------------------ |
|
|
146
|
+
| `clientId` | `string` | Yes* | Your Immutable application client ID (*required when config is provided) |
|
|
147
|
+
| `redirectUri` | `string` | Yes* | OAuth redirect URI (*required when config is provided) |
|
|
148
|
+
| `audience` | `string` | No | OAuth audience (default: `"platform_api"`) |
|
|
149
|
+
| `scope` | `string` | No | OAuth scopes (default: `"openid profile email offline_access transact"`) |
|
|
150
|
+
| `authenticationDomain` | `string` | No | Auth domain (default: `"https://auth.immutable.com"`) |
|
|
100
151
|
|
|
101
152
|
#### Extending the Configuration
|
|
102
153
|
|
|
@@ -117,19 +168,20 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
|
|
|
117
168
|
secret: process.env.AUTH_SECRET,
|
|
118
169
|
trustHost: true,
|
|
119
170
|
basePath: "/api/auth/custom",
|
|
120
|
-
|
|
171
|
+
|
|
121
172
|
// Extend callbacks (be sure to call the base callbacks first)
|
|
122
173
|
callbacks: {
|
|
123
174
|
...baseConfig.callbacks,
|
|
124
175
|
async jwt(params) {
|
|
125
176
|
// Call base jwt callback first
|
|
126
|
-
const token = await baseConfig.callbacks?.jwt?.(params) ?? params.token;
|
|
177
|
+
const token = (await baseConfig.callbacks?.jwt?.(params)) ?? params.token;
|
|
127
178
|
// Add your custom logic
|
|
128
179
|
return token;
|
|
129
180
|
},
|
|
130
181
|
async session(params) {
|
|
131
182
|
// Call base session callback first
|
|
132
|
-
const session =
|
|
183
|
+
const session =
|
|
184
|
+
(await baseConfig.callbacks?.session?.(params)) ?? params.session;
|
|
133
185
|
// Add your custom logic
|
|
134
186
|
return session;
|
|
135
187
|
},
|
|
@@ -141,18 +193,19 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
|
|
|
141
193
|
|
|
142
194
|
This package provides several utilities for handling authentication in Server Components. Choose the right one based on your needs:
|
|
143
195
|
|
|
144
|
-
| Utility
|
|
145
|
-
|
|
146
|
-
| `getAuthProps`
|
|
147
|
-
| `getAuthenticatedData`
|
|
148
|
-
| `createProtectedFetchers` | Multiple pages with same error handling
|
|
149
|
-
| `getValidSession`
|
|
196
|
+
| Utility | Use Case | Data Fetching | Error Handling |
|
|
197
|
+
| ------------------------- | ------------------------------------------------- | ------------- | ----------------- |
|
|
198
|
+
| `getAuthProps` | Pass auth state to client, fetch data client-side | No | Manual |
|
|
199
|
+
| `getAuthenticatedData` | SSR data fetching with client fallback | Yes | Manual |
|
|
200
|
+
| `createProtectedFetchers` | Multiple pages with same error handling | Optional | Centralized |
|
|
201
|
+
| `getValidSession` | Custom logic for each auth state | No | Manual (detailed) |
|
|
150
202
|
|
|
151
203
|
### `getAuthProps(auth)`
|
|
152
204
|
|
|
153
205
|
**Use case:** You want to pass authentication state to a Client Component but handle data fetching entirely on the client side. This is the simplest approach when your page doesn't need SSR data fetching.
|
|
154
206
|
|
|
155
207
|
**When to use:**
|
|
208
|
+
|
|
156
209
|
- Pages where data is fetched client-side (e.g., infinite scroll, real-time updates)
|
|
157
210
|
- Pages that show a loading skeleton while fetching
|
|
158
211
|
- When you want full control over loading states in the client
|
|
@@ -167,11 +220,11 @@ import { DashboardClient } from "./DashboardClient";
|
|
|
167
220
|
|
|
168
221
|
export default async function DashboardPage() {
|
|
169
222
|
const authProps = await getAuthProps(auth);
|
|
170
|
-
|
|
223
|
+
|
|
171
224
|
if (authProps.authError) {
|
|
172
225
|
redirect("/login");
|
|
173
226
|
}
|
|
174
|
-
|
|
227
|
+
|
|
175
228
|
// DashboardClient will fetch its own data using useImmutableSession().getUser()
|
|
176
229
|
return <DashboardClient {...authProps} />;
|
|
177
230
|
}
|
|
@@ -182,11 +235,13 @@ export default async function DashboardPage() {
|
|
|
182
235
|
**Use case:** You want to fetch data server-side for faster initial page loads (SSR), but gracefully fall back to client-side fetching when the token is expired.
|
|
183
236
|
|
|
184
237
|
**When to use:**
|
|
238
|
+
|
|
185
239
|
- Pages that benefit from SSR (SEO, faster first paint)
|
|
186
240
|
- Profile pages, settings pages, or any page showing user-specific data
|
|
187
241
|
- When you want the best of both worlds: SSR when possible, CSR as fallback
|
|
188
242
|
|
|
189
243
|
**How it works:**
|
|
244
|
+
|
|
190
245
|
1. If token is valid → fetches data server-side, returns `ssr: true`
|
|
191
246
|
2. If token is expired → skips fetch, returns `ssr: false`, client refreshes and fetches
|
|
192
247
|
3. Pair with `useHydratedData` hook on the client for seamless handling
|
|
@@ -208,11 +263,11 @@ async function fetchUserProfile(accessToken: string) {
|
|
|
208
263
|
|
|
209
264
|
export default async function ProfilePage() {
|
|
210
265
|
const result = await getAuthenticatedData(auth, fetchUserProfile);
|
|
211
|
-
|
|
266
|
+
|
|
212
267
|
if (result.authError) {
|
|
213
268
|
redirect("/login");
|
|
214
269
|
}
|
|
215
|
-
|
|
270
|
+
|
|
216
271
|
// ProfileClient uses useHydratedData() to handle both SSR data and client fallback
|
|
217
272
|
return <ProfileClient {...result} />;
|
|
218
273
|
}
|
|
@@ -223,11 +278,13 @@ export default async function ProfilePage() {
|
|
|
223
278
|
**Use case:** You have multiple protected pages and want to define auth error handling once, rather than repeating `if (authError) redirect(...)` on every page.
|
|
224
279
|
|
|
225
280
|
**When to use:**
|
|
281
|
+
|
|
226
282
|
- Apps with many protected pages sharing the same error handling logic
|
|
227
283
|
- When you want DRY (Don't Repeat Yourself) error handling
|
|
228
284
|
- Teams that want consistent auth error behavior across the app
|
|
229
285
|
|
|
230
286
|
**How it works:**
|
|
287
|
+
|
|
231
288
|
- Define error handling once in a shared file
|
|
232
289
|
- Use the returned `getAuthProps` and `getData` functions in your pages
|
|
233
290
|
- Auth errors automatically trigger your handler (no manual checking needed)
|
|
@@ -245,7 +302,7 @@ export const { getAuthProps, getData } = createProtectedFetchers(
|
|
|
245
302
|
(error) => {
|
|
246
303
|
// This runs automatically when there's an auth error (e.g., RefreshTokenError)
|
|
247
304
|
redirect(`/login?error=${error}`);
|
|
248
|
-
}
|
|
305
|
+
},
|
|
249
306
|
);
|
|
250
307
|
```
|
|
251
308
|
|
|
@@ -259,7 +316,7 @@ export default async function DashboardPage() {
|
|
|
259
316
|
const result = await getData(async (token) => {
|
|
260
317
|
return fetchDashboardData(token);
|
|
261
318
|
});
|
|
262
|
-
|
|
319
|
+
|
|
263
320
|
return <DashboardClient {...result} />;
|
|
264
321
|
}
|
|
265
322
|
```
|
|
@@ -281,6 +338,7 @@ export default async function SettingsPage() {
|
|
|
281
338
|
**Use case:** You need fine-grained control over different authentication states and want to handle each case with custom logic.
|
|
282
339
|
|
|
283
340
|
**When to use:**
|
|
341
|
+
|
|
284
342
|
- Complex pages that render completely different UI based on auth state
|
|
285
343
|
- When you need to distinguish between "token expired" vs "not authenticated"
|
|
286
344
|
- Analytics or logging that needs to track specific auth states
|
|
@@ -294,22 +352,22 @@ import { getValidSession } from "@imtbl/auth-next-server";
|
|
|
294
352
|
|
|
295
353
|
export default async function AccountPage() {
|
|
296
354
|
const result = await getValidSession(auth);
|
|
297
|
-
|
|
355
|
+
|
|
298
356
|
switch (result.status) {
|
|
299
357
|
case "authenticated":
|
|
300
358
|
// Full access - render the complete account page with SSR data
|
|
301
359
|
const userData = await fetchUserData(result.session.accessToken);
|
|
302
360
|
return <FullAccountPage user={userData} />;
|
|
303
|
-
|
|
361
|
+
|
|
304
362
|
case "token_expired":
|
|
305
363
|
// Token expired but user has session - show skeleton, let client refresh
|
|
306
364
|
// This avoids a flash of "please login" for users who are actually logged in
|
|
307
365
|
return <AccountPageSkeleton session={result.session} />;
|
|
308
|
-
|
|
366
|
+
|
|
309
367
|
case "unauthenticated":
|
|
310
368
|
// No session at all - show login prompt or redirect
|
|
311
369
|
return <LoginPrompt message="Sign in to view your account" />;
|
|
312
|
-
|
|
370
|
+
|
|
313
371
|
case "error":
|
|
314
372
|
// Auth system error (e.g., refresh token revoked) - needs re-login
|
|
315
373
|
return <AuthErrorPage error={result.error} />;
|
|
@@ -324,11 +382,13 @@ export default async function AccountPage() {
|
|
|
324
382
|
**Use case:** Protect entire sections of your app at the routing level, before pages even render. This is the most efficient way to block unauthenticated access.
|
|
325
383
|
|
|
326
384
|
**When to use:**
|
|
385
|
+
|
|
327
386
|
- You have groups of pages that all require authentication (e.g., `/dashboard/*`, `/settings/*`)
|
|
328
387
|
- You want to redirect unauthenticated users before any page code runs
|
|
329
388
|
- You need consistent protection across many routes without adding checks to each page
|
|
330
389
|
|
|
331
390
|
**When NOT to use:**
|
|
391
|
+
|
|
332
392
|
- Pages that show different content for authenticated vs unauthenticated users (use page-level checks instead)
|
|
333
393
|
- Public pages with optional authenticated features
|
|
334
394
|
|
|
@@ -352,17 +412,18 @@ export const config = {
|
|
|
352
412
|
|
|
353
413
|
#### Middleware Options
|
|
354
414
|
|
|
355
|
-
| Option
|
|
356
|
-
|
|
357
|
-
| `loginUrl`
|
|
358
|
-
| `protectedPaths` | `(string \| RegExp)[]` | Paths that require authentication
|
|
359
|
-
| `publicPaths`
|
|
415
|
+
| Option | Type | Description |
|
|
416
|
+
| ---------------- | ---------------------- | ----------------------------------------------------------- |
|
|
417
|
+
| `loginUrl` | `string` | URL to redirect unauthenticated users (default: `"/login"`) |
|
|
418
|
+
| `protectedPaths` | `(string \| RegExp)[]` | Paths that require authentication |
|
|
419
|
+
| `publicPaths` | `(string \| RegExp)[]` | Paths that skip authentication (takes precedence) |
|
|
360
420
|
|
|
361
421
|
### `withAuth(auth, handler)`
|
|
362
422
|
|
|
363
423
|
**Use case:** Protect individual API Route Handlers or Server Actions. Ensures the handler only runs for authenticated users.
|
|
364
424
|
|
|
365
425
|
**When to use:**
|
|
426
|
+
|
|
366
427
|
- API routes that should only be accessible to authenticated users
|
|
367
428
|
- Server Actions (form submissions, mutations) that require authentication
|
|
368
429
|
- When you need the session/user info inside the handler
|
|
@@ -394,11 +455,11 @@ import { auth } from "@/lib/auth";
|
|
|
394
455
|
import { withAuth } from "@imtbl/auth-next-server";
|
|
395
456
|
|
|
396
457
|
export const transferAsset = withAuth(
|
|
397
|
-
auth,
|
|
458
|
+
auth,
|
|
398
459
|
async (session, formData: FormData) => {
|
|
399
460
|
const assetId = formData.get("assetId") as string;
|
|
400
461
|
const toAddress = formData.get("toAddress") as string;
|
|
401
|
-
|
|
462
|
+
|
|
402
463
|
// Use session.user.sub to identify the sender
|
|
403
464
|
// Use session.accessToken to call Immutable APIs
|
|
404
465
|
const result = await executeTransfer({
|
|
@@ -407,9 +468,9 @@ export const transferAsset = withAuth(
|
|
|
407
468
|
assetId,
|
|
408
469
|
accessToken: session.accessToken,
|
|
409
470
|
});
|
|
410
|
-
|
|
471
|
+
|
|
411
472
|
return result;
|
|
412
|
-
}
|
|
473
|
+
},
|
|
413
474
|
);
|
|
414
475
|
```
|
|
415
476
|
|
|
@@ -420,22 +481,24 @@ The package augments the Auth.js `Session` type with Immutable-specific fields:
|
|
|
420
481
|
```typescript
|
|
421
482
|
interface Session {
|
|
422
483
|
user: {
|
|
423
|
-
sub: string;
|
|
484
|
+
sub: string; // Immutable user ID
|
|
424
485
|
email?: string;
|
|
425
486
|
nickname?: string;
|
|
426
487
|
};
|
|
427
488
|
accessToken: string;
|
|
428
489
|
refreshToken?: string;
|
|
429
|
-
idToken?: string;
|
|
490
|
+
idToken?: string; // Only present transiently after sign-in or token refresh (not stored in cookie)
|
|
430
491
|
accessTokenExpires: number;
|
|
431
492
|
zkEvm?: {
|
|
432
493
|
ethAddress: string;
|
|
433
494
|
userAdminAddress: string;
|
|
434
495
|
};
|
|
435
|
-
error?: string;
|
|
496
|
+
error?: string; // "TokenExpired" or "RefreshTokenError"
|
|
436
497
|
}
|
|
437
498
|
```
|
|
438
499
|
|
|
500
|
+
> **Note:** The `idToken` is **not** stored in the session cookie. It is stripped by a custom `jwt.encode` to keep cookie size under CDN header limits. The `idToken` is only present in the session response transiently after sign-in or token refresh. On the client, `@imtbl/auth-next-client` automatically persists it in `localStorage` so that wallet operations (via `getUser()`) can always access it. All data extracted from the idToken (`email`, `nickname`, `zkEvm`) remains in the cookie as separate fields.
|
|
501
|
+
|
|
439
502
|
## Token Refresh
|
|
440
503
|
|
|
441
504
|
### Automatic Refresh on Token Expiry
|
|
@@ -453,10 +516,10 @@ import { useImmutableSession } from "@imtbl/auth-next-client";
|
|
|
453
516
|
|
|
454
517
|
function MyComponent() {
|
|
455
518
|
const { getUser } = useImmutableSession();
|
|
456
|
-
|
|
519
|
+
|
|
457
520
|
const handleRegistration = async () => {
|
|
458
521
|
// After zkEVM registration completes...
|
|
459
|
-
|
|
522
|
+
|
|
460
523
|
// Force refresh to get updated zkEvm claims from IDP
|
|
461
524
|
const freshUser = await getUser(true);
|
|
462
525
|
console.log("Updated zkEvm:", freshUser?.zkEvm);
|
|
@@ -465,6 +528,7 @@ function MyComponent() {
|
|
|
465
528
|
```
|
|
466
529
|
|
|
467
530
|
When `forceRefresh` is triggered:
|
|
531
|
+
|
|
468
532
|
1. Client calls `update({ forceRefresh: true })` via NextAuth
|
|
469
533
|
2. The `jwt` callback detects `trigger === 'update'` with `forceRefresh: true`
|
|
470
534
|
3. Server performs a token refresh using the refresh token
|
|
@@ -476,10 +540,10 @@ When `forceRefresh` is triggered:
|
|
|
476
540
|
The package also exports utilities for manual token handling:
|
|
477
541
|
|
|
478
542
|
```typescript
|
|
479
|
-
import {
|
|
480
|
-
isTokenExpired,
|
|
481
|
-
refreshAccessToken,
|
|
482
|
-
extractZkEvmFromIdToken // Extract zkEvm claims from ID token
|
|
543
|
+
import {
|
|
544
|
+
isTokenExpired, // Check if access token is expired
|
|
545
|
+
refreshAccessToken, // Manually refresh tokens
|
|
546
|
+
extractZkEvmFromIdToken, // Extract zkEvm claims from ID token
|
|
483
547
|
} from "@imtbl/auth-next-server";
|
|
484
548
|
```
|
|
485
549
|
|
|
@@ -487,10 +551,10 @@ import {
|
|
|
487
551
|
|
|
488
552
|
The session may contain an `error` field indicating authentication issues:
|
|
489
553
|
|
|
490
|
-
| Error
|
|
491
|
-
|
|
492
|
-
| `"TokenExpired"`
|
|
493
|
-
| `"RefreshTokenError"` | Refresh token invalid/expired
|
|
554
|
+
| Error | Description | Recommended Action |
|
|
555
|
+
| --------------------- | ------------------------------------------------ | ------------------------------------------------ |
|
|
556
|
+
| `"TokenExpired"` | Access token expired, refresh token may be valid | Let client refresh via `@imtbl/auth-next-client` |
|
|
557
|
+
| `"RefreshTokenError"` | Refresh token invalid/expired | Redirect to login |
|
|
494
558
|
|
|
495
559
|
## TypeScript
|
|
496
560
|
|