@solvapay/next 1.1.0 → 1.2.0-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0

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 CHANGED
@@ -69,6 +69,19 @@ export const middleware = createSupabaseAuthMiddleware({
69
69
  export const config = { matcher: ['/api/:path*'] }
70
70
  ```
71
71
 
72
+ Auth0 has the same high-level API:
73
+
74
+ ```typescript
75
+ import { createAuth0AuthMiddleware } from '@solvapay/next/middleware'
76
+ import { auth0 } from './lib/auth0'
77
+
78
+ export const proxy = createAuth0AuthMiddleware({ auth0 })
79
+
80
+ export const config = {
81
+ matcher: ['/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)'],
82
+ }
83
+ ```
84
+
72
85
  Next.js 16 renamed middleware to proxy — use `@solvapay/next/middleware` and export `proxy` instead of `middleware` when required.
73
86
 
74
87
  ## Requirements
@@ -0,0 +1,134 @@
1
+ // src/helpers/middleware.ts
2
+ import { NextResponse } from "next/server";
3
+ import { SOLVAPAY_AUTHORIZATION_HEADER, SOLVAPAY_USER_ID_HEADER } from "@solvapay/auth";
4
+ import { createAuth0AuthAdapter } from "@solvapay/auth/auth0";
5
+ function mergeSetCookies(target, source) {
6
+ for (const cookie of source.headers.getSetCookie()) {
7
+ target.headers.append("set-cookie", cookie);
8
+ }
9
+ }
10
+ async function resolveIdentity(adapter, req) {
11
+ if (adapter.getIdentityFromRequest) {
12
+ return adapter.getIdentityFromRequest(req);
13
+ }
14
+ const userId = await adapter.getUserIdFromRequest(req);
15
+ if (!userId) {
16
+ return null;
17
+ }
18
+ return { userId };
19
+ }
20
+ function buildForwardResponse(req, userIdHeader, identity) {
21
+ const requestHeaders = new Headers(req.headers);
22
+ requestHeaders.delete(userIdHeader);
23
+ requestHeaders.delete(SOLVAPAY_AUTHORIZATION_HEADER);
24
+ if (identity) {
25
+ requestHeaders.set(userIdHeader, identity.userId);
26
+ if (identity.claimsToken) {
27
+ requestHeaders.set(SOLVAPAY_AUTHORIZATION_HEADER, `Bearer ${identity.claimsToken}`);
28
+ }
29
+ }
30
+ return NextResponse.next({
31
+ request: {
32
+ headers: requestHeaders
33
+ }
34
+ });
35
+ }
36
+ function getPathname(req) {
37
+ if (req.nextUrl) {
38
+ return req.nextUrl.pathname;
39
+ }
40
+ return new URL(req.url).pathname;
41
+ }
42
+ function createAuthMiddleware(options) {
43
+ const {
44
+ adapter,
45
+ publicRoutes = [],
46
+ userIdHeader = SOLVAPAY_USER_ID_HEADER,
47
+ processAllRoutes = false,
48
+ protectedRoutePrefix = "/api"
49
+ } = options;
50
+ return async function middleware(request) {
51
+ const req = request;
52
+ const pathname = getPathname(req);
53
+ if (!processAllRoutes && !pathname.startsWith("/api")) {
54
+ return NextResponse.next();
55
+ }
56
+ const handleResult = adapter.handleRequest ? await adapter.handleRequest(req) : null;
57
+ if (handleResult?.ownsRequest && handleResult.response) {
58
+ return handleResult.response;
59
+ }
60
+ const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
61
+ const identity = await resolveIdentity(adapter, req);
62
+ const userId = identity?.userId ?? null;
63
+ const isProtectedApiRoute = pathname.startsWith(protectedRoutePrefix) && !isPublicRoute;
64
+ if (isProtectedApiRoute && !userId) {
65
+ const unauthorized = NextResponse.json(
66
+ { error: "Unauthorized", details: "Valid authentication required" },
67
+ { status: 401 }
68
+ );
69
+ if (handleResult?.sessionResponse) {
70
+ mergeSetCookies(unauthorized, handleResult.sessionResponse);
71
+ }
72
+ return unauthorized;
73
+ }
74
+ const forward = buildForwardResponse(req, userIdHeader, identity);
75
+ if (handleResult?.sessionResponse) {
76
+ mergeSetCookies(forward, handleResult.sessionResponse);
77
+ }
78
+ return forward;
79
+ };
80
+ }
81
+ function createAuth0AuthMiddleware(options) {
82
+ const {
83
+ auth0,
84
+ authRoutePrefix,
85
+ publicRoutes = [],
86
+ userIdHeader = SOLVAPAY_USER_ID_HEADER,
87
+ protectedRoutePrefix = "/api"
88
+ } = options;
89
+ return createAuthMiddleware({
90
+ adapter: createAuth0AuthAdapter({ auth0, authRoutePrefix }),
91
+ publicRoutes,
92
+ userIdHeader,
93
+ protectedRoutePrefix,
94
+ processAllRoutes: true
95
+ });
96
+ }
97
+ function createSupabaseAuthMiddleware(options = {}) {
98
+ const { jwtSecret, publicRoutes = [], userIdHeader = SOLVAPAY_USER_ID_HEADER } = options;
99
+ let authAdapter = null;
100
+ let adapterPromise = null;
101
+ const lazyAdapter = {
102
+ async getUserIdFromRequest(req) {
103
+ if (!authAdapter) {
104
+ if (!adapterPromise) {
105
+ adapterPromise = (async () => {
106
+ const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
107
+ if (!secret) {
108
+ throw new Error(
109
+ "SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
110
+ );
111
+ }
112
+ const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
113
+ authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
114
+ return authAdapter;
115
+ })();
116
+ }
117
+ authAdapter = await adapterPromise;
118
+ }
119
+ return authAdapter.getUserIdFromRequest(req);
120
+ }
121
+ };
122
+ return createAuthMiddleware({
123
+ adapter: lazyAdapter,
124
+ publicRoutes,
125
+ userIdHeader,
126
+ processAllRoutes: false
127
+ });
128
+ }
129
+
130
+ export {
131
+ createAuthMiddleware,
132
+ createAuth0AuthMiddleware,
133
+ createSupabaseAuthMiddleware
134
+ };
package/dist/index.cjs CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  checkPurchase: () => checkPurchase,
36
36
  clearAllPurchaseCache: () => clearAllPurchaseCache,
37
37
  clearPurchaseCache: () => clearPurchaseCache,
38
+ createAuth0AuthMiddleware: () => createAuth0AuthMiddleware,
38
39
  createAuthMiddleware: () => createAuthMiddleware,
39
40
  createCheckoutSession: () => createCheckoutSession,
40
41
  createCustomerSession: () => createCustomerSession,
@@ -353,44 +354,102 @@ async function trackUsage(request, body, options = {}) {
353
354
 
354
355
  // src/helpers/middleware.ts
355
356
  var import_server17 = require("next/server");
357
+ var import_auth = require("@solvapay/auth");
358
+ var import_auth0 = require("@solvapay/auth/auth0");
359
+ function mergeSetCookies(target, source) {
360
+ for (const cookie of source.headers.getSetCookie()) {
361
+ target.headers.append("set-cookie", cookie);
362
+ }
363
+ }
364
+ async function resolveIdentity(adapter, req) {
365
+ if (adapter.getIdentityFromRequest) {
366
+ return adapter.getIdentityFromRequest(req);
367
+ }
368
+ const userId = await adapter.getUserIdFromRequest(req);
369
+ if (!userId) {
370
+ return null;
371
+ }
372
+ return { userId };
373
+ }
374
+ function buildForwardResponse(req, userIdHeader, identity) {
375
+ const requestHeaders = new Headers(req.headers);
376
+ requestHeaders.delete(userIdHeader);
377
+ requestHeaders.delete(import_auth.SOLVAPAY_AUTHORIZATION_HEADER);
378
+ if (identity) {
379
+ requestHeaders.set(userIdHeader, identity.userId);
380
+ if (identity.claimsToken) {
381
+ requestHeaders.set(import_auth.SOLVAPAY_AUTHORIZATION_HEADER, `Bearer ${identity.claimsToken}`);
382
+ }
383
+ }
384
+ return import_server17.NextResponse.next({
385
+ request: {
386
+ headers: requestHeaders
387
+ }
388
+ });
389
+ }
390
+ function getPathname(req) {
391
+ if (req.nextUrl) {
392
+ return req.nextUrl.pathname;
393
+ }
394
+ return new URL(req.url).pathname;
395
+ }
356
396
  function createAuthMiddleware(options) {
357
- const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
397
+ const {
398
+ adapter,
399
+ publicRoutes = [],
400
+ userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER,
401
+ processAllRoutes = false,
402
+ protectedRoutePrefix = "/api"
403
+ } = options;
358
404
  return async function middleware(request) {
359
405
  const req = request;
360
- const { pathname } = req.nextUrl;
361
- if (!pathname.startsWith("/api")) {
406
+ const pathname = getPathname(req);
407
+ if (!processAllRoutes && !pathname.startsWith("/api")) {
362
408
  return import_server17.NextResponse.next();
363
409
  }
364
- const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
365
- const userId = await adapter.getUserIdFromRequest(req);
366
- if (isPublicRoute) {
367
- const requestHeaders2 = new Headers(req.headers);
368
- if (userId) {
369
- requestHeaders2.set(userIdHeader, userId);
370
- }
371
- return import_server17.NextResponse.next({
372
- request: {
373
- headers: requestHeaders2
374
- }
375
- });
410
+ const handleResult = adapter.handleRequest ? await adapter.handleRequest(req) : null;
411
+ if (handleResult?.ownsRequest && handleResult.response) {
412
+ return handleResult.response;
376
413
  }
377
- if (!userId) {
378
- return import_server17.NextResponse.json(
414
+ const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
415
+ const identity = await resolveIdentity(adapter, req);
416
+ const userId = identity?.userId ?? null;
417
+ const isProtectedApiRoute = pathname.startsWith(protectedRoutePrefix) && !isPublicRoute;
418
+ if (isProtectedApiRoute && !userId) {
419
+ const unauthorized = import_server17.NextResponse.json(
379
420
  { error: "Unauthorized", details: "Valid authentication required" },
380
421
  { status: 401 }
381
422
  );
382
- }
383
- const requestHeaders = new Headers(req.headers);
384
- requestHeaders.set(userIdHeader, userId);
385
- return import_server17.NextResponse.next({
386
- request: {
387
- headers: requestHeaders
423
+ if (handleResult?.sessionResponse) {
424
+ mergeSetCookies(unauthorized, handleResult.sessionResponse);
388
425
  }
389
- });
426
+ return unauthorized;
427
+ }
428
+ const forward = buildForwardResponse(req, userIdHeader, identity);
429
+ if (handleResult?.sessionResponse) {
430
+ mergeSetCookies(forward, handleResult.sessionResponse);
431
+ }
432
+ return forward;
390
433
  };
391
434
  }
435
+ function createAuth0AuthMiddleware(options) {
436
+ const {
437
+ auth0,
438
+ authRoutePrefix,
439
+ publicRoutes = [],
440
+ userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER,
441
+ protectedRoutePrefix = "/api"
442
+ } = options;
443
+ return createAuthMiddleware({
444
+ adapter: (0, import_auth0.createAuth0AuthAdapter)({ auth0, authRoutePrefix }),
445
+ publicRoutes,
446
+ userIdHeader,
447
+ protectedRoutePrefix,
448
+ processAllRoutes: true
449
+ });
450
+ }
392
451
  function createSupabaseAuthMiddleware(options = {}) {
393
- const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
452
+ const { jwtSecret, publicRoutes = [], userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER } = options;
394
453
  let authAdapter = null;
395
454
  let adapterPromise = null;
396
455
  const lazyAdapter = {
@@ -417,7 +476,8 @@ function createSupabaseAuthMiddleware(options = {}) {
417
476
  return createAuthMiddleware({
418
477
  adapter: lazyAdapter,
419
478
  publicRoutes,
420
- userIdHeader
479
+ userIdHeader,
480
+ processAllRoutes: false
421
481
  });
422
482
  }
423
483
 
@@ -460,6 +520,7 @@ async function checkPurchase(request, options = {}) {
460
520
  checkPurchase,
461
521
  clearAllPurchaseCache,
462
522
  clearPurchaseCache,
523
+ createAuth0AuthMiddleware,
463
524
  createAuthMiddleware,
464
525
  createCheckoutSession,
465
526
  createCustomerSession,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
3
- export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.cjs';
3
+ export { Auth0AuthMiddlewareOptions, AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuth0AuthMiddleware, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.cjs';
4
4
  import '@solvapay/auth';
5
+ import '@solvapay/auth/auth0';
5
6
 
6
7
  /**
7
8
  * Purchase Cache Utilities
@@ -508,6 +509,7 @@ declare function trackUsage(request: globalThis.Request, body: {
508
509
  productRef?: string;
509
510
  description?: string;
510
511
  metadata?: Record<string, unknown>;
512
+ idempotencyKey?: string;
511
513
  }, options?: {
512
514
  solvaPay?: SolvaPay;
513
515
  }): Promise<NextResponse>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { AuthenticatedUser, SolvaPay } from '@solvapay/server';
3
- export { AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.js';
3
+ export { Auth0AuthMiddlewareOptions, AuthMiddlewareOptions, SupabaseAuthMiddlewareOptions, createAuth0AuthMiddleware, createAuthMiddleware, createSupabaseAuthMiddleware } from './middleware.js';
4
4
  import '@solvapay/auth';
5
+ import '@solvapay/auth/auth0';
5
6
 
6
7
  /**
7
8
  * Purchase Cache Utilities
@@ -508,6 +509,7 @@ declare function trackUsage(request: globalThis.Request, body: {
508
509
  productRef?: string;
509
510
  description?: string;
510
511
  metadata?: Record<string, unknown>;
512
+ idempotencyKey?: string;
511
513
  }, options?: {
512
514
  solvaPay?: SolvaPay;
513
515
  }): Promise<NextResponse>;
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import {
2
+ createAuth0AuthMiddleware,
2
3
  createAuthMiddleware,
3
4
  createSupabaseAuthMiddleware
4
- } from "./chunk-F7TBIH6W.js";
5
+ } from "./chunk-WSXIXEUB.js";
5
6
 
6
7
  // src/index.ts
7
8
  import { NextResponse as NextResponse4 } from "next/server";
@@ -354,6 +355,7 @@ export {
354
355
  checkPurchase,
355
356
  clearAllPurchaseCache,
356
357
  clearPurchaseCache,
358
+ createAuth0AuthMiddleware,
357
359
  createAuthMiddleware,
358
360
  createCheckoutSession,
359
361
  createCustomerSession,
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/middleware.ts
31
31
  var middleware_exports = {};
32
32
  __export(middleware_exports, {
33
+ createAuth0AuthMiddleware: () => createAuth0AuthMiddleware,
33
34
  createAuthMiddleware: () => createAuthMiddleware,
34
35
  createSupabaseAuthMiddleware: () => createSupabaseAuthMiddleware
35
36
  });
@@ -37,44 +38,102 @@ module.exports = __toCommonJS(middleware_exports);
37
38
 
38
39
  // src/helpers/middleware.ts
39
40
  var import_server = require("next/server");
41
+ var import_auth = require("@solvapay/auth");
42
+ var import_auth0 = require("@solvapay/auth/auth0");
43
+ function mergeSetCookies(target, source) {
44
+ for (const cookie of source.headers.getSetCookie()) {
45
+ target.headers.append("set-cookie", cookie);
46
+ }
47
+ }
48
+ async function resolveIdentity(adapter, req) {
49
+ if (adapter.getIdentityFromRequest) {
50
+ return adapter.getIdentityFromRequest(req);
51
+ }
52
+ const userId = await adapter.getUserIdFromRequest(req);
53
+ if (!userId) {
54
+ return null;
55
+ }
56
+ return { userId };
57
+ }
58
+ function buildForwardResponse(req, userIdHeader, identity) {
59
+ const requestHeaders = new Headers(req.headers);
60
+ requestHeaders.delete(userIdHeader);
61
+ requestHeaders.delete(import_auth.SOLVAPAY_AUTHORIZATION_HEADER);
62
+ if (identity) {
63
+ requestHeaders.set(userIdHeader, identity.userId);
64
+ if (identity.claimsToken) {
65
+ requestHeaders.set(import_auth.SOLVAPAY_AUTHORIZATION_HEADER, `Bearer ${identity.claimsToken}`);
66
+ }
67
+ }
68
+ return import_server.NextResponse.next({
69
+ request: {
70
+ headers: requestHeaders
71
+ }
72
+ });
73
+ }
74
+ function getPathname(req) {
75
+ if (req.nextUrl) {
76
+ return req.nextUrl.pathname;
77
+ }
78
+ return new URL(req.url).pathname;
79
+ }
40
80
  function createAuthMiddleware(options) {
41
- const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
81
+ const {
82
+ adapter,
83
+ publicRoutes = [],
84
+ userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER,
85
+ processAllRoutes = false,
86
+ protectedRoutePrefix = "/api"
87
+ } = options;
42
88
  return async function middleware(request) {
43
89
  const req = request;
44
- const { pathname } = req.nextUrl;
45
- if (!pathname.startsWith("/api")) {
90
+ const pathname = getPathname(req);
91
+ if (!processAllRoutes && !pathname.startsWith("/api")) {
46
92
  return import_server.NextResponse.next();
47
93
  }
48
- const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
49
- const userId = await adapter.getUserIdFromRequest(req);
50
- if (isPublicRoute) {
51
- const requestHeaders2 = new Headers(req.headers);
52
- if (userId) {
53
- requestHeaders2.set(userIdHeader, userId);
54
- }
55
- return import_server.NextResponse.next({
56
- request: {
57
- headers: requestHeaders2
58
- }
59
- });
94
+ const handleResult = adapter.handleRequest ? await adapter.handleRequest(req) : null;
95
+ if (handleResult?.ownsRequest && handleResult.response) {
96
+ return handleResult.response;
60
97
  }
61
- if (!userId) {
62
- return import_server.NextResponse.json(
98
+ const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
99
+ const identity = await resolveIdentity(adapter, req);
100
+ const userId = identity?.userId ?? null;
101
+ const isProtectedApiRoute = pathname.startsWith(protectedRoutePrefix) && !isPublicRoute;
102
+ if (isProtectedApiRoute && !userId) {
103
+ const unauthorized = import_server.NextResponse.json(
63
104
  { error: "Unauthorized", details: "Valid authentication required" },
64
105
  { status: 401 }
65
106
  );
66
- }
67
- const requestHeaders = new Headers(req.headers);
68
- requestHeaders.set(userIdHeader, userId);
69
- return import_server.NextResponse.next({
70
- request: {
71
- headers: requestHeaders
107
+ if (handleResult?.sessionResponse) {
108
+ mergeSetCookies(unauthorized, handleResult.sessionResponse);
72
109
  }
73
- });
110
+ return unauthorized;
111
+ }
112
+ const forward = buildForwardResponse(req, userIdHeader, identity);
113
+ if (handleResult?.sessionResponse) {
114
+ mergeSetCookies(forward, handleResult.sessionResponse);
115
+ }
116
+ return forward;
74
117
  };
75
118
  }
119
+ function createAuth0AuthMiddleware(options) {
120
+ const {
121
+ auth0,
122
+ authRoutePrefix,
123
+ publicRoutes = [],
124
+ userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER,
125
+ protectedRoutePrefix = "/api"
126
+ } = options;
127
+ return createAuthMiddleware({
128
+ adapter: (0, import_auth0.createAuth0AuthAdapter)({ auth0, authRoutePrefix }),
129
+ publicRoutes,
130
+ userIdHeader,
131
+ protectedRoutePrefix,
132
+ processAllRoutes: true
133
+ });
134
+ }
76
135
  function createSupabaseAuthMiddleware(options = {}) {
77
- const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
136
+ const { jwtSecret, publicRoutes = [], userIdHeader = import_auth.SOLVAPAY_USER_ID_HEADER } = options;
78
137
  let authAdapter = null;
79
138
  let adapterPromise = null;
80
139
  const lazyAdapter = {
@@ -101,11 +160,13 @@ function createSupabaseAuthMiddleware(options = {}) {
101
160
  return createAuthMiddleware({
102
161
  adapter: lazyAdapter,
103
162
  publicRoutes,
104
- userIdHeader
163
+ userIdHeader,
164
+ processAllRoutes: false
105
165
  });
106
166
  }
107
167
  // Annotate the CommonJS export names for ESM import in node:
108
168
  0 && (module.exports = {
169
+ createAuth0AuthMiddleware,
109
170
  createAuthMiddleware,
110
171
  createSupabaseAuthMiddleware
111
172
  });
@@ -1,11 +1,12 @@
1
- import { NextRequest, NextResponse } from 'next/server';
1
+ import { NextRequest } from 'next/server';
2
2
  import { AuthAdapter } from '@solvapay/auth';
3
+ import { Auth0ClientLike } from '@solvapay/auth/auth0';
3
4
 
4
5
  /**
5
6
  * Next.js Middleware Helpers
6
7
  *
7
8
  * Helpers for creating authentication middleware in Next.js.
8
- * Works with any AuthAdapter implementation (Supabase, custom, etc.)
9
+ * Works with any AuthAdapter implementation (Supabase, Auth0, custom, etc.)
9
10
  */
10
11
 
11
12
  /**
@@ -23,156 +24,65 @@ interface AuthMiddlewareOptions {
23
24
  */
24
25
  publicRoutes?: string[];
25
26
  /**
26
- * Header name to store the user ID (default: 'x-user-id')
27
+ * Header name to store the user ID (default: `x-user-id`)
27
28
  */
28
29
  userIdHeader?: string;
30
+ /**
31
+ * When true, process all matched routes (not only `/api/*`).
32
+ * Use with session-based adapters (Auth0) that refresh cookies on every request.
33
+ * Default: false (legacy Supabase API-only behaviour).
34
+ */
35
+ processAllRoutes?: boolean;
36
+ /**
37
+ * When `processAllRoutes` is true, only enforce 401 on paths starting with this prefix.
38
+ * Default: `/api`
39
+ */
40
+ protectedRoutePrefix?: string;
29
41
  }
30
42
  /**
31
43
  * Creates a Next.js middleware function for authentication
32
- *
33
- * This helper:
34
- * 1. Uses the provided AuthAdapter to extract userId from requests
35
- * 2. Handles public vs protected routes
36
- * 3. Adds userId to request headers for downstream routes
37
- * 4. Returns appropriate error responses for auth failures
38
- *
39
- * @param options - Configuration options
40
- * @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
41
- *
42
- * @example Next.js 15
43
- * ```typescript
44
- * // middleware.ts (at project root)
45
- * import { createAuthMiddleware } from '@solvapay/next';
46
- * import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
47
- *
48
- * const adapter = new SupabaseAuthAdapter({
49
- * jwtSecret: process.env.SUPABASE_JWT_SECRET!,
50
- * });
51
- *
52
- * export const middleware = createAuthMiddleware({
53
- * adapter,
54
- * publicRoutes: ['/api/list-plans'],
55
- * });
56
- *
57
- * export const config = {
58
- * matcher: ['/api/:path*'],
59
- * };
60
- * ```
61
- *
62
- * @example Next.js 16 with src/ folder
63
- * ```typescript
64
- * // src/proxy.ts (in src/ folder, not project root)
65
- * import { createAuthMiddleware } from '@solvapay/next';
66
- * import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
67
- *
68
- * const adapter = new SupabaseAuthAdapter({
69
- * jwtSecret: process.env.SUPABASE_JWT_SECRET!,
70
- * });
71
- *
72
- * // Use 'proxy' export for Next.js 16 (no deprecation warning)
73
- * export const proxy = createAuthMiddleware({
74
- * adapter,
75
- * publicRoutes: ['/api/list-plans'],
76
- * });
77
- *
78
- * export const config = {
79
- * matcher: ['/api/:path*'],
80
- * };
81
- * ```
82
- *
83
- * @example Custom adapter
84
- * ```typescript
85
- * import { createAuthMiddleware } from '@solvapay/next';
86
- * import type { AuthAdapter } from '@solvapay/auth';
87
- *
88
- * const myAdapter: AuthAdapter = {
89
- * async getUserIdFromRequest(req) {
90
- * // Your custom auth logic
91
- * return userId;
92
- * },
93
- * };
94
- *
95
- * export const middleware = createAuthMiddleware({
96
- * adapter: myAdapter,
97
- * });
98
- * ```
99
- *
100
- * **File Location Notes:**
101
- * - **Next.js 15**: Place `middleware.ts` at project root
102
- * - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
103
- * - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
104
- *
105
- * **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
106
- * `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
107
44
  */
108
- declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
45
+ declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
109
46
  /**
110
- * Configuration options for Supabase authentication middleware
47
+ * Configuration options for Auth0 authentication middleware
111
48
  */
112
- interface SupabaseAuthMiddlewareOptions {
49
+ interface Auth0AuthMiddlewareOptions {
113
50
  /**
114
- * Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
115
- * If not provided, will use SUPABASE_JWT_SECRET environment variable
51
+ * Auth0 client instance used by the adapter.
116
52
  */
117
- jwtSecret?: string;
53
+ auth0: Auth0ClientLike;
118
54
  /**
119
- * Public routes that don't require authentication
120
- * Routes are matched using pathname.startsWith()
55
+ * Public routes that don't require authentication.
121
56
  */
122
57
  publicRoutes?: string[];
123
58
  /**
124
- * Header name to store the user ID (default: 'x-user-id')
59
+ * Route prefix owned by Auth0 (default: `/auth`).
125
60
  */
61
+ authRoutePrefix?: string;
62
+ /**
63
+ * Header name to store the user ID (default: `x-user-id`)
64
+ */
65
+ userIdHeader?: string;
66
+ /**
67
+ * Route prefix that enforces 401 when unauthenticated (default: `/api`)
68
+ */
69
+ protectedRoutePrefix?: string;
70
+ }
71
+ /**
72
+ * Creates a Next.js middleware function for Auth0 authentication.
73
+ */
74
+ declare function createAuth0AuthMiddleware(options: Auth0AuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
75
+ /**
76
+ * Configuration options for Supabase authentication middleware
77
+ */
78
+ interface SupabaseAuthMiddlewareOptions {
79
+ jwtSecret?: string;
80
+ publicRoutes?: string[];
126
81
  userIdHeader?: string;
127
82
  }
128
83
  /**
129
84
  * Creates a Next.js middleware function for Supabase authentication
130
- *
131
- * Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
132
- * Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
133
- *
134
- * Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
135
- *
136
- * @param options - Configuration options
137
- * @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
138
- *
139
- * @example Next.js 15
140
- * ```typescript
141
- * // middleware.ts (at project root)
142
- * import { createSupabaseAuthMiddleware } from '@solvapay/next';
143
- *
144
- * export const middleware = createSupabaseAuthMiddleware({
145
- * publicRoutes: ['/api/list-plans'],
146
- * });
147
- *
148
- * export const config = {
149
- * matcher: ['/api/:path*'],
150
- * };
151
- * ```
152
- *
153
- * @example Next.js 16 with src/ folder
154
- * ```typescript
155
- * // src/proxy.ts (in src/ folder, not project root)
156
- * import { createSupabaseAuthMiddleware } from '@solvapay/next';
157
- *
158
- * // Use 'proxy' export for Next.js 16 (no deprecation warning)
159
- * export const proxy = createSupabaseAuthMiddleware({
160
- * publicRoutes: ['/api/list-plans'],
161
- * });
162
- *
163
- * export const config = {
164
- * matcher: ['/api/:path*'],
165
- * };
166
- * ```
167
- *
168
- * **File Location Notes:**
169
- * - **Next.js 15**: Place `middleware.ts` at project root
170
- * - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
171
- * - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
172
- *
173
- * **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
174
- * `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
175
85
  */
176
- declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
86
+ declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
177
87
 
178
- export { type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware };
88
+ export { type Auth0AuthMiddlewareOptions, type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuth0AuthMiddleware, createAuthMiddleware, createSupabaseAuthMiddleware };
@@ -1,11 +1,12 @@
1
- import { NextRequest, NextResponse } from 'next/server';
1
+ import { NextRequest } from 'next/server';
2
2
  import { AuthAdapter } from '@solvapay/auth';
3
+ import { Auth0ClientLike } from '@solvapay/auth/auth0';
3
4
 
4
5
  /**
5
6
  * Next.js Middleware Helpers
6
7
  *
7
8
  * Helpers for creating authentication middleware in Next.js.
8
- * Works with any AuthAdapter implementation (Supabase, custom, etc.)
9
+ * Works with any AuthAdapter implementation (Supabase, Auth0, custom, etc.)
9
10
  */
10
11
 
11
12
  /**
@@ -23,156 +24,65 @@ interface AuthMiddlewareOptions {
23
24
  */
24
25
  publicRoutes?: string[];
25
26
  /**
26
- * Header name to store the user ID (default: 'x-user-id')
27
+ * Header name to store the user ID (default: `x-user-id`)
27
28
  */
28
29
  userIdHeader?: string;
30
+ /**
31
+ * When true, process all matched routes (not only `/api/*`).
32
+ * Use with session-based adapters (Auth0) that refresh cookies on every request.
33
+ * Default: false (legacy Supabase API-only behaviour).
34
+ */
35
+ processAllRoutes?: boolean;
36
+ /**
37
+ * When `processAllRoutes` is true, only enforce 401 on paths starting with this prefix.
38
+ * Default: `/api`
39
+ */
40
+ protectedRoutePrefix?: string;
29
41
  }
30
42
  /**
31
43
  * Creates a Next.js middleware function for authentication
32
- *
33
- * This helper:
34
- * 1. Uses the provided AuthAdapter to extract userId from requests
35
- * 2. Handles public vs protected routes
36
- * 3. Adds userId to request headers for downstream routes
37
- * 4. Returns appropriate error responses for auth failures
38
- *
39
- * @param options - Configuration options
40
- * @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
41
- *
42
- * @example Next.js 15
43
- * ```typescript
44
- * // middleware.ts (at project root)
45
- * import { createAuthMiddleware } from '@solvapay/next';
46
- * import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
47
- *
48
- * const adapter = new SupabaseAuthAdapter({
49
- * jwtSecret: process.env.SUPABASE_JWT_SECRET!,
50
- * });
51
- *
52
- * export const middleware = createAuthMiddleware({
53
- * adapter,
54
- * publicRoutes: ['/api/list-plans'],
55
- * });
56
- *
57
- * export const config = {
58
- * matcher: ['/api/:path*'],
59
- * };
60
- * ```
61
- *
62
- * @example Next.js 16 with src/ folder
63
- * ```typescript
64
- * // src/proxy.ts (in src/ folder, not project root)
65
- * import { createAuthMiddleware } from '@solvapay/next';
66
- * import { SupabaseAuthAdapter } from '@solvapay/auth/supabase';
67
- *
68
- * const adapter = new SupabaseAuthAdapter({
69
- * jwtSecret: process.env.SUPABASE_JWT_SECRET!,
70
- * });
71
- *
72
- * // Use 'proxy' export for Next.js 16 (no deprecation warning)
73
- * export const proxy = createAuthMiddleware({
74
- * adapter,
75
- * publicRoutes: ['/api/list-plans'],
76
- * });
77
- *
78
- * export const config = {
79
- * matcher: ['/api/:path*'],
80
- * };
81
- * ```
82
- *
83
- * @example Custom adapter
84
- * ```typescript
85
- * import { createAuthMiddleware } from '@solvapay/next';
86
- * import type { AuthAdapter } from '@solvapay/auth';
87
- *
88
- * const myAdapter: AuthAdapter = {
89
- * async getUserIdFromRequest(req) {
90
- * // Your custom auth logic
91
- * return userId;
92
- * },
93
- * };
94
- *
95
- * export const middleware = createAuthMiddleware({
96
- * adapter: myAdapter,
97
- * });
98
- * ```
99
- *
100
- * **File Location Notes:**
101
- * - **Next.js 15**: Place `middleware.ts` at project root
102
- * - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
103
- * - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
104
- *
105
- * **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
106
- * `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
107
44
  */
108
- declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
45
+ declare function createAuthMiddleware(options: AuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
109
46
  /**
110
- * Configuration options for Supabase authentication middleware
47
+ * Configuration options for Auth0 authentication middleware
111
48
  */
112
- interface SupabaseAuthMiddlewareOptions {
49
+ interface Auth0AuthMiddlewareOptions {
113
50
  /**
114
- * Supabase JWT secret (from Supabase dashboard: Settings → API → JWT Secret)
115
- * If not provided, will use SUPABASE_JWT_SECRET environment variable
51
+ * Auth0 client instance used by the adapter.
116
52
  */
117
- jwtSecret?: string;
53
+ auth0: Auth0ClientLike;
118
54
  /**
119
- * Public routes that don't require authentication
120
- * Routes are matched using pathname.startsWith()
55
+ * Public routes that don't require authentication.
121
56
  */
122
57
  publicRoutes?: string[];
123
58
  /**
124
- * Header name to store the user ID (default: 'x-user-id')
59
+ * Route prefix owned by Auth0 (default: `/auth`).
125
60
  */
61
+ authRoutePrefix?: string;
62
+ /**
63
+ * Header name to store the user ID (default: `x-user-id`)
64
+ */
65
+ userIdHeader?: string;
66
+ /**
67
+ * Route prefix that enforces 401 when unauthenticated (default: `/api`)
68
+ */
69
+ protectedRoutePrefix?: string;
70
+ }
71
+ /**
72
+ * Creates a Next.js middleware function for Auth0 authentication.
73
+ */
74
+ declare function createAuth0AuthMiddleware(options: Auth0AuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
75
+ /**
76
+ * Configuration options for Supabase authentication middleware
77
+ */
78
+ interface SupabaseAuthMiddlewareOptions {
79
+ jwtSecret?: string;
80
+ publicRoutes?: string[];
126
81
  userIdHeader?: string;
127
82
  }
128
83
  /**
129
84
  * Creates a Next.js middleware function for Supabase authentication
130
- *
131
- * Convenience function that creates a SupabaseAuthAdapter and wraps it with createAuthMiddleware.
132
- * Only use this if you're using Supabase - otherwise use createAuthMiddleware with your own adapter.
133
- *
134
- * Uses dynamic import to avoid requiring Supabase as a dependency in @solvapay/next.
135
- *
136
- * @param options - Configuration options
137
- * @returns Next.js middleware function (can be exported as `middleware` or `proxy`)
138
- *
139
- * @example Next.js 15
140
- * ```typescript
141
- * // middleware.ts (at project root)
142
- * import { createSupabaseAuthMiddleware } from '@solvapay/next';
143
- *
144
- * export const middleware = createSupabaseAuthMiddleware({
145
- * publicRoutes: ['/api/list-plans'],
146
- * });
147
- *
148
- * export const config = {
149
- * matcher: ['/api/:path*'],
150
- * };
151
- * ```
152
- *
153
- * @example Next.js 16 with src/ folder
154
- * ```typescript
155
- * // src/proxy.ts (in src/ folder, not project root)
156
- * import { createSupabaseAuthMiddleware } from '@solvapay/next';
157
- *
158
- * // Use 'proxy' export for Next.js 16 (no deprecation warning)
159
- * export const proxy = createSupabaseAuthMiddleware({
160
- * publicRoutes: ['/api/list-plans'],
161
- * });
162
- *
163
- * export const config = {
164
- * matcher: ['/api/:path*'],
165
- * };
166
- * ```
167
- *
168
- * **File Location Notes:**
169
- * - **Next.js 15**: Place `middleware.ts` at project root
170
- * - **Next.js 16 without `src/` folder**: Place `middleware.ts` or `proxy.ts` at project root
171
- * - **Next.js 16 with `src/` folder**: Place `src/proxy.ts` or `src/middleware.ts` (in `src/` folder, not root)
172
- *
173
- * **Note:** Next.js 16 renamed "middleware" to "proxy". You can export the return value as either
174
- * `middleware` or `proxy` - both work, but `proxy` is recommended to avoid deprecation warnings.
175
85
  */
176
- declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
86
+ declare function createSupabaseAuthMiddleware(options?: SupabaseAuthMiddlewareOptions): (request: NextRequest) => Promise<Response>;
177
87
 
178
- export { type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuthMiddleware, createSupabaseAuthMiddleware };
88
+ export { type Auth0AuthMiddlewareOptions, type AuthMiddlewareOptions, type SupabaseAuthMiddlewareOptions, createAuth0AuthMiddleware, createAuthMiddleware, createSupabaseAuthMiddleware };
@@ -1,8 +1,10 @@
1
1
  import {
2
+ createAuth0AuthMiddleware,
2
3
  createAuthMiddleware,
3
4
  createSupabaseAuthMiddleware
4
- } from "./chunk-F7TBIH6W.js";
5
+ } from "./chunk-WSXIXEUB.js";
5
6
  export {
7
+ createAuth0AuthMiddleware,
6
8
  createAuthMiddleware,
7
9
  createSupabaseAuthMiddleware
8
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/next",
3
- "version": "1.1.0",
3
+ "version": "1.2.0-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -34,9 +34,9 @@
34
34
  },
35
35
  "sideEffects": false,
36
36
  "dependencies": {
37
- "@solvapay/auth": "1.0.8",
37
+ "@solvapay/auth": "1.1.0-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0",
38
38
  "@solvapay/core": "1.0.9",
39
- "@solvapay/server": "1.2.0"
39
+ "@solvapay/server": "1.2.1-preview-e89fa52f99b6d0c7bf9834fcf2d1403141051fa0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "next": ">=13.0.0"
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsup src/index.ts src/middleware.ts --format esm,cjs --dts --tsconfig tsconfig.build.json --external next",
53
- "test": "vitest run || exit 0",
53
+ "test": "vitest run",
54
54
  "test:watch": "vitest",
55
55
  "lint": "eslint src",
56
56
  "lint:fix": "eslint src --fix"
@@ -1,74 +0,0 @@
1
- // src/helpers/middleware.ts
2
- import { NextResponse } from "next/server";
3
- function createAuthMiddleware(options) {
4
- const { adapter, publicRoutes = [], userIdHeader = "x-user-id" } = options;
5
- return async function middleware(request) {
6
- const req = request;
7
- const { pathname } = req.nextUrl;
8
- if (!pathname.startsWith("/api")) {
9
- return NextResponse.next();
10
- }
11
- const isPublicRoute = publicRoutes.some((route) => pathname.startsWith(route));
12
- const userId = await adapter.getUserIdFromRequest(req);
13
- if (isPublicRoute) {
14
- const requestHeaders2 = new Headers(req.headers);
15
- if (userId) {
16
- requestHeaders2.set(userIdHeader, userId);
17
- }
18
- return NextResponse.next({
19
- request: {
20
- headers: requestHeaders2
21
- }
22
- });
23
- }
24
- if (!userId) {
25
- return NextResponse.json(
26
- { error: "Unauthorized", details: "Valid authentication required" },
27
- { status: 401 }
28
- );
29
- }
30
- const requestHeaders = new Headers(req.headers);
31
- requestHeaders.set(userIdHeader, userId);
32
- return NextResponse.next({
33
- request: {
34
- headers: requestHeaders
35
- }
36
- });
37
- };
38
- }
39
- function createSupabaseAuthMiddleware(options = {}) {
40
- const { jwtSecret, publicRoutes = [], userIdHeader = "x-user-id" } = options;
41
- let authAdapter = null;
42
- let adapterPromise = null;
43
- const lazyAdapter = {
44
- async getUserIdFromRequest(req) {
45
- if (!authAdapter) {
46
- if (!adapterPromise) {
47
- adapterPromise = (async () => {
48
- const secret = jwtSecret || process.env.SUPABASE_JWT_SECRET;
49
- if (!secret) {
50
- throw new Error(
51
- "SUPABASE_JWT_SECRET environment variable is required. Please set it in your .env.local file. Get it from: Supabase Dashboard \u2192 Settings \u2192 API \u2192 JWT Secret"
52
- );
53
- }
54
- const { SupabaseAuthAdapter } = await import("@solvapay/auth/supabase");
55
- authAdapter = new SupabaseAuthAdapter({ jwtSecret: secret });
56
- return authAdapter;
57
- })();
58
- }
59
- authAdapter = await adapterPromise;
60
- }
61
- return authAdapter.getUserIdFromRequest(req);
62
- }
63
- };
64
- return createAuthMiddleware({
65
- adapter: lazyAdapter,
66
- publicRoutes,
67
- userIdHeader
68
- });
69
- }
70
-
71
- export {
72
- createAuthMiddleware,
73
- createSupabaseAuthMiddleware
74
- };