next-token-auth 1.0.0
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 +520 -0
- package/dist/index.d.mts +283 -0
- package/dist/index.d.ts +283 -0
- package/dist/index.js +619 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +606 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# next-auth-kit
|
|
2
|
+
|
|
3
|
+
A production-grade authentication library for Next.js. Handles access tokens, refresh tokens, session management, and route protection — so you don't have to wire it all up yourself.
|
|
4
|
+
|
|
5
|
+
Works with both the App Router and Pages Router. Fully typed with TypeScript.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
Authentication in Next.js involves a lot of moving parts:
|
|
12
|
+
|
|
13
|
+
- Storing tokens securely
|
|
14
|
+
- Refreshing access tokens before they expire
|
|
15
|
+
- Keeping client and server sessions in sync
|
|
16
|
+
- Protecting routes on both the client and server
|
|
17
|
+
- Wiring up login, logout, and user fetching from scratch
|
|
18
|
+
|
|
19
|
+
Most projects end up with hundreds of lines of boilerplate before a single feature is built.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## The Solution
|
|
24
|
+
|
|
25
|
+
`next-auth-kit` gives you a single `AuthProvider` and a set of hooks that handle the entire auth lifecycle. You configure your API endpoints once, and the library takes care of the rest:
|
|
26
|
+
|
|
27
|
+
- Tokens are stored in cookies or memory
|
|
28
|
+
- Access tokens are automatically refreshed before they expire
|
|
29
|
+
- Sessions are restored on page load from stored tokens
|
|
30
|
+
- Routes can be protected client-side with a hook or server-side with middleware
|
|
31
|
+
- Every API request made through the built-in fetch wrapper gets a `Bearer` token injected automatically
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- `AuthProvider` — React context provider that initializes and manages auth state
|
|
38
|
+
- `useAuth` — login, logout, refresh, and session in one hook
|
|
39
|
+
- `useSession` — read-only access to the current session
|
|
40
|
+
- `useRequireAuth` — redirects unauthenticated users, works in App Router and Pages Router
|
|
41
|
+
- Token storage in cookies or in-memory
|
|
42
|
+
- AES-GCM encrypted session cookies (server-side)
|
|
43
|
+
- Automatic access token refresh on a 30-second interval (when `autoRefresh` is enabled)
|
|
44
|
+
- 401 → refresh → retry built into the HTTP client
|
|
45
|
+
- `getServerSession` — read and validate the session in server components and API routes
|
|
46
|
+
- `withAuth` — higher-order function to protect App Router route handlers
|
|
47
|
+
- `authMiddleware` — Next.js middleware factory for edge-level route protection
|
|
48
|
+
- Flexible expiry parsing: `"15m"`, `"2h"`, `"2d"`, `"7d"`, `"1w"`, or plain seconds
|
|
49
|
+
- Three expiry strategies: `backend`, `config`, `hybrid`
|
|
50
|
+
- Fully typed with TypeScript generics for custom user shapes
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install next-auth-kit
|
|
58
|
+
# or
|
|
59
|
+
yarn add next-auth-kit
|
|
60
|
+
# or
|
|
61
|
+
pnpm add next-auth-kit
|
|
62
|
+
# or
|
|
63
|
+
bun add next-auth-kit
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Peer dependencies** (already installed in any Next.js project):
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
next >= 13
|
|
70
|
+
react >= 18
|
|
71
|
+
react-dom >= 18
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
### 1. Create your config
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// lib/auth.ts
|
|
82
|
+
import type { AuthConfig } from "next-auth-kit";
|
|
83
|
+
|
|
84
|
+
interface User {
|
|
85
|
+
id: string;
|
|
86
|
+
email: string;
|
|
87
|
+
name: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const authConfig: AuthConfig<User> = {
|
|
91
|
+
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
|
|
92
|
+
|
|
93
|
+
endpoints: {
|
|
94
|
+
login: "/auth/login",
|
|
95
|
+
refresh: "/auth/refresh",
|
|
96
|
+
logout: "/auth/logout",
|
|
97
|
+
me: "/auth/me",
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
token: {
|
|
101
|
+
storage: "cookie",
|
|
102
|
+
cookieName: "myapp.session",
|
|
103
|
+
secure: true,
|
|
104
|
+
sameSite: "lax",
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
secret: process.env.AUTH_SECRET!,
|
|
108
|
+
|
|
109
|
+
autoRefresh: true,
|
|
110
|
+
|
|
111
|
+
expiry: {
|
|
112
|
+
accessTokenExpiresIn: "2d",
|
|
113
|
+
refreshTokenExpiresIn: "7d",
|
|
114
|
+
strategy: "hybrid",
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 2. Wrap your app with `AuthProvider`
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// app/layout.tsx
|
|
123
|
+
import { AuthProvider } from "next-auth-kit/react";
|
|
124
|
+
import { authConfig } from "@/lib/auth";
|
|
125
|
+
|
|
126
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
127
|
+
return (
|
|
128
|
+
<html lang="en">
|
|
129
|
+
<body>
|
|
130
|
+
<AuthProvider config={authConfig}>{children}</AuthProvider>
|
|
131
|
+
</body>
|
|
132
|
+
</html>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 3. Use the hooks
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
"use client";
|
|
141
|
+
|
|
142
|
+
import { useAuth } from "next-auth-kit/react";
|
|
143
|
+
|
|
144
|
+
export default function LoginPage() {
|
|
145
|
+
const { login, isLoading } = useAuth();
|
|
146
|
+
|
|
147
|
+
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
const form = new FormData(e.currentTarget);
|
|
150
|
+
await login({ email: form.get("email"), password: form.get("password") });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<form onSubmit={handleSubmit}>
|
|
155
|
+
<input name="email" type="email" required />
|
|
156
|
+
<input name="password" type="password" required />
|
|
157
|
+
<button type="submit" disabled={isLoading}>
|
|
158
|
+
{isLoading ? "Signing in…" : "Sign in"}
|
|
159
|
+
</button>
|
|
160
|
+
</form>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Usage
|
|
168
|
+
|
|
169
|
+
### `AuthProvider`
|
|
170
|
+
|
|
171
|
+
Wrap your application once at the root. It initializes the `AuthClient`, restores any existing session from stored tokens on mount, and subscribes all child hooks to session changes.
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
<AuthProvider config={authConfig}>
|
|
175
|
+
{children}
|
|
176
|
+
</AuthProvider>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
When `autoRefresh: true` is set, the provider checks every 30 seconds whether the access token is near expiry and refreshes it silently in the background.
|
|
180
|
+
|
|
181
|
+
#### Full config reference
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
interface AuthConfig<User = unknown> {
|
|
185
|
+
// Base URL of your backend API
|
|
186
|
+
baseUrl: string;
|
|
187
|
+
|
|
188
|
+
endpoints: {
|
|
189
|
+
login: string; // required
|
|
190
|
+
refresh: string; // required
|
|
191
|
+
register?: string;
|
|
192
|
+
logout?: string;
|
|
193
|
+
me?: string; // fetched after login/session restore to populate user
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
routes?: {
|
|
197
|
+
public: string[]; // always accessible, e.g. ["/", "/login"]
|
|
198
|
+
protected: string[]; // require auth, supports wildcard: "/dashboard/*"
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
token: {
|
|
202
|
+
storage: "cookie" | "memory";
|
|
203
|
+
cookieName?: string; // default: "next-auth-kit.session"
|
|
204
|
+
secure?: boolean; // default: true
|
|
205
|
+
sameSite?: "strict" | "lax" | "none"; // default: "lax"
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Used to AES-GCM encrypt session cookies server-side
|
|
209
|
+
secret: string;
|
|
210
|
+
|
|
211
|
+
// Automatically refresh the access token before it expires
|
|
212
|
+
autoRefresh?: boolean;
|
|
213
|
+
|
|
214
|
+
// Seconds before expiry to trigger a proactive refresh (default: 60)
|
|
215
|
+
refreshThreshold?: number;
|
|
216
|
+
|
|
217
|
+
expiry?: {
|
|
218
|
+
accessTokenExpiresIn?: number | string; // e.g. "2d", 3600
|
|
219
|
+
refreshTokenExpiresIn?: number | string; // e.g. "7d"
|
|
220
|
+
strategy?: "backend" | "config" | "hybrid"; // default: "hybrid"
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Provide a custom fetch implementation (e.g. for testing)
|
|
224
|
+
fetchFn?: typeof fetch;
|
|
225
|
+
|
|
226
|
+
// Lifecycle callbacks
|
|
227
|
+
onLogin?: (session: AuthSession<User>) => void;
|
|
228
|
+
onLogout?: () => void;
|
|
229
|
+
onRefreshError?: (error: unknown) => void;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### `useAuth`
|
|
236
|
+
|
|
237
|
+
The primary hook. Gives you everything you need to build auth flows.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const { session, login, logout, refresh, isLoading } = useAuth<User>();
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Property | Type | Description |
|
|
244
|
+
|-------------|-----------------------------------------|--------------------------------------------------|
|
|
245
|
+
| `session` | `AuthSession<User>` | Current auth session |
|
|
246
|
+
| `login` | `(input: LoginInput) => Promise<void>` | POST to your login endpoint, stores tokens |
|
|
247
|
+
| `logout` | `() => Promise<void>` | Clears tokens, calls logout endpoint if set |
|
|
248
|
+
| `refresh` | `() => Promise<void>` | Manually trigger a token refresh |
|
|
249
|
+
| `isLoading` | `boolean` | `true` while initializing or during login |
|
|
250
|
+
|
|
251
|
+
`LoginInput` is an open object (`{ [key: string]: unknown }`), so you can pass any fields your backend expects.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### `useSession`
|
|
256
|
+
|
|
257
|
+
Read-only access to the current session. Use this in components that only need to display user data.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
const { user, tokens, isAuthenticated } = useSession<User>();
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### `useRequireAuth`
|
|
266
|
+
|
|
267
|
+
Redirects unauthenticated users. Call it at the top of any protected client component.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
useRequireAuth({ redirectTo: "/login" });
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
You can also pass a custom handler instead of a redirect path:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
useRequireAuth({
|
|
277
|
+
onUnauthenticated: () => router.push("/login?from=/dashboard"),
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The hook waits for `isLoading` to be `false` before acting, so it won't flash a redirect during the initial session restore.
|
|
282
|
+
|
|
283
|
+
| Option | Type | Default |
|
|
284
|
+
|---------------------|--------------|------------|
|
|
285
|
+
| `redirectTo` | `string` | `"/login"` |
|
|
286
|
+
| `onUnauthenticated` | `() => void` | — |
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
### Protecting API Routes with `withAuth`
|
|
291
|
+
|
|
292
|
+
Wrap App Router route handlers to require authentication:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
// app/api/profile/route.ts
|
|
296
|
+
import { withAuth } from "next-auth-kit/server";
|
|
297
|
+
import { authConfig } from "@/lib/auth";
|
|
298
|
+
|
|
299
|
+
export const GET = withAuth(authConfig, async (req, session) => {
|
|
300
|
+
return Response.json({ user: session.user });
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Unauthenticated requests are redirected to `/login` by default. Pass `{ redirectTo: "/your-path" }` as the third argument to override.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### Middleware (Edge Route Protection)
|
|
309
|
+
|
|
310
|
+
Protect entire route groups at the edge using Next.js middleware:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
// middleware.ts (project root)
|
|
314
|
+
import { authMiddleware } from "next-auth-kit/server";
|
|
315
|
+
import { authConfig } from "@/lib/auth";
|
|
316
|
+
|
|
317
|
+
export const middleware = authMiddleware(authConfig);
|
|
318
|
+
|
|
319
|
+
export const config = {
|
|
320
|
+
matcher: ["/dashboard/:path*", "/settings/:path*"],
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
The middleware reads the encrypted session cookie, checks whether the refresh token is still valid, and redirects to `/login` if not. Routes listed in `config.routes.public` are always allowed through.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Session and Token Handling
|
|
329
|
+
|
|
330
|
+
### How tokens are stored
|
|
331
|
+
|
|
332
|
+
| Storage mode | Where |
|
|
333
|
+
|--------------|-----------------------------------------------------------------------|
|
|
334
|
+
| `"cookie"` | Serialized as JSON in a browser cookie with `Secure` + `SameSite` |
|
|
335
|
+
| `"memory"` | Held in a JavaScript variable — cleared on page refresh |
|
|
336
|
+
|
|
337
|
+
Server-side (in `getServerSession` and `authMiddleware`), the cookie value is expected to be AES-GCM encrypted using your `secret`. The `TokenManager` provides `encryptTokens` / `decryptTokens` helpers for this.
|
|
338
|
+
|
|
339
|
+
### Session restore on page load
|
|
340
|
+
|
|
341
|
+
When `AuthProvider` mounts, it calls `client.initialize()`, which:
|
|
342
|
+
|
|
343
|
+
1. Reads tokens from the configured storage
|
|
344
|
+
2. Checks whether the access token is expired (accounting for `refreshThreshold`)
|
|
345
|
+
3. If the access token is near expiry but the refresh token is still valid, it silently refreshes
|
|
346
|
+
4. If a `me` endpoint is configured, it fetches the user profile to populate `session.user`
|
|
347
|
+
5. Updates React state — `isLoading` flips to `false` once complete
|
|
348
|
+
|
|
349
|
+
### Automatic refresh
|
|
350
|
+
|
|
351
|
+
When `autoRefresh: true`, the provider runs a check every 30 seconds. If the access token is within `refreshThreshold` seconds of expiry (default: 60s) and the refresh token is still valid, it calls the refresh endpoint automatically.
|
|
352
|
+
|
|
353
|
+
The HTTP client also handles 401 responses: it attempts a token refresh and retries the original request once. Multiple concurrent 401s share a single refresh request (deduplicated via a shared promise).
|
|
354
|
+
|
|
355
|
+
### Refresh flow
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
Request → 401 → refresh endpoint → new tokens stored → original request retried
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
If the refresh token is expired, the user is logged out and the session is cleared.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Server-Side Session (`getServerSession`)
|
|
366
|
+
|
|
367
|
+
Use this in App Router server components and API routes to read the session without going through the client:
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
// app/dashboard/page.tsx
|
|
371
|
+
import { redirect } from "next/navigation";
|
|
372
|
+
import { cookies } from "next/headers";
|
|
373
|
+
import { getServerSession } from "next-auth-kit/server";
|
|
374
|
+
import { authConfig } from "@/lib/auth";
|
|
375
|
+
|
|
376
|
+
export default async function DashboardPage() {
|
|
377
|
+
const cookieStore = await cookies();
|
|
378
|
+
|
|
379
|
+
const session = await getServerSession(
|
|
380
|
+
{ cookies: { get: (name) => cookieStore.get(name) } },
|
|
381
|
+
authConfig
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
if (!session.isAuthenticated) {
|
|
385
|
+
redirect("/login");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return <h1>Welcome, {session.user.name}</h1>;
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
`getServerSession` decrypts the session cookie, validates expiry, and attempts a server-side token refresh if the access token is near expiry but the refresh token is still valid.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Backend Requirements
|
|
397
|
+
|
|
398
|
+
Your API needs to implement the following contract:
|
|
399
|
+
|
|
400
|
+
### `POST /auth/login`
|
|
401
|
+
|
|
402
|
+
Request body: whatever fields you pass to `login()` (e.g. `{ email, password }`)
|
|
403
|
+
|
|
404
|
+
Response:
|
|
405
|
+
|
|
406
|
+
```json
|
|
407
|
+
{
|
|
408
|
+
"accessToken": "eyJ...",
|
|
409
|
+
"refreshToken": "eyJ...",
|
|
410
|
+
"user": { "id": "1", "email": "user@example.com", "name": "Jane" },
|
|
411
|
+
|
|
412
|
+
// Optional — used by "backend" and "hybrid" expiry strategies
|
|
413
|
+
"accessTokenExpiresIn": "2d",
|
|
414
|
+
"refreshTokenExpiresIn": "7d",
|
|
415
|
+
|
|
416
|
+
// Legacy field, also accepted
|
|
417
|
+
"expiresIn": 172800
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### `POST /auth/refresh`
|
|
422
|
+
|
|
423
|
+
Request body:
|
|
424
|
+
|
|
425
|
+
```json
|
|
426
|
+
{ "refreshToken": "eyJ..." }
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Response: same shape as the login response (new `accessToken` + `refreshToken`).
|
|
430
|
+
|
|
431
|
+
### `GET /auth/me` _(optional)_
|
|
432
|
+
|
|
433
|
+
Returns the current user object. Called after login and on session restore if the `me` endpoint is configured.
|
|
434
|
+
|
|
435
|
+
### `POST /auth/logout` _(optional)_
|
|
436
|
+
|
|
437
|
+
Called on logout. Failure is silently ignored — tokens are always cleared locally regardless.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Expiry Formats
|
|
442
|
+
|
|
443
|
+
The `parseExpiry` utility accepts:
|
|
444
|
+
|
|
445
|
+
| Input | Seconds |
|
|
446
|
+
|---------|-----------|
|
|
447
|
+
| `900` | 900 |
|
|
448
|
+
| `"15m"` | 900 |
|
|
449
|
+
| `"2h"` | 7 200 |
|
|
450
|
+
| `"2d"` | 172 800 |
|
|
451
|
+
| `"7d"` | 604 800 |
|
|
452
|
+
| `"1w"` | 604 800 |
|
|
453
|
+
|
|
454
|
+
### Expiry strategies
|
|
455
|
+
|
|
456
|
+
| Strategy | Behaviour |
|
|
457
|
+
|-----------|------------------------------------------------------------------|
|
|
458
|
+
| `backend` | Use only the expiry values returned by the API |
|
|
459
|
+
| `config` | Use only the values set in `expiry` config |
|
|
460
|
+
| `hybrid` | API response first; fall back to config if not present (default) |
|
|
461
|
+
|
|
462
|
+
`hybrid` is the safest choice — it works whether or not your backend returns expiry fields.
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## TypeScript Types
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
interface AuthSession<User = unknown> {
|
|
470
|
+
user: User | null;
|
|
471
|
+
tokens: AuthTokens | null;
|
|
472
|
+
isAuthenticated: boolean;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
interface AuthTokens {
|
|
476
|
+
accessToken: string;
|
|
477
|
+
refreshToken: string;
|
|
478
|
+
accessTokenExpiresAt: number; // Unix timestamp in ms
|
|
479
|
+
refreshTokenExpiresAt?: number; // Unix timestamp in ms
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
interface LoginResponse<User = unknown> {
|
|
483
|
+
user: User;
|
|
484
|
+
accessToken: string;
|
|
485
|
+
refreshToken: string;
|
|
486
|
+
expiresIn?: number;
|
|
487
|
+
accessTokenExpiresIn?: number | string;
|
|
488
|
+
refreshTokenExpiresIn?: number | string;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
type ExpiryInput = number | string;
|
|
492
|
+
type ExpiryStrategy = "backend" | "config" | "hybrid";
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
All types are exported from the root `next-auth-kit` import.
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Who This Is For
|
|
500
|
+
|
|
501
|
+
- Developers building Next.js apps who want auth that just works
|
|
502
|
+
- Teams that need a consistent auth pattern across multiple projects
|
|
503
|
+
- Anyone tired of writing the same token refresh logic over and over
|
|
504
|
+
- SaaS and MVP builders who want to ship features, not auth plumbing
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## Security Notes
|
|
509
|
+
|
|
510
|
+
- Session cookies use `Secure` and `SameSite` flags by default
|
|
511
|
+
- Server-side cookies are AES-GCM encrypted using your `secret`
|
|
512
|
+
- Use a random 32-character string for `secret` in production — never commit it
|
|
513
|
+
- The `"memory"` storage mode keeps tokens out of cookies entirely, at the cost of losing the session on page refresh
|
|
514
|
+
- Refresh tokens are never exposed to JavaScript when using server-side encrypted cookies
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## License
|
|
519
|
+
|
|
520
|
+
MIT
|