@stackwright-pro/auth-nextjs 0.2.0-alpha.7 → 0.3.0-alpha.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 +36 -4
- package/dist/chunk-MFZSH4YL.mjs +58 -0
- package/dist/chunk-MFZSH4YL.mjs.map +1 -0
- package/dist/index.d.mts +22 -33
- package/dist/index.d.ts +22 -33
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -51
- package/dist/index.mjs.map +1 -1
- package/dist/proxy-Blj2kIJp.d.mts +67 -0
- package/dist/proxy-Blj2kIJp.d.ts +67 -0
- package/dist/proxy.d.mts +4 -0
- package/dist/proxy.d.ts +4 -0
- package/dist/proxy.js +83 -0
- package/dist/proxy.js.map +1 -0
- package/dist/proxy.mjs +7 -0
- package/dist/proxy.mjs.map +1 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -10,10 +10,35 @@ pnpm add @stackwright-pro/auth-nextjs
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### Proxy (Next.js >=16 — Recommended)
|
|
14
|
+
|
|
15
|
+
Next.js 16 deprecated the `middleware.ts` convention in favor of `proxy.ts`. Use `createAuthProxy` for new projects:
|
|
14
16
|
|
|
15
17
|
```typescript
|
|
16
|
-
//
|
|
18
|
+
// proxy.ts (project root)
|
|
19
|
+
import { createAuthProxy } from '@stackwright-pro/auth-nextjs';
|
|
20
|
+
import { sessionManager, rbacEngine, authConfig } from './lib/auth';
|
|
21
|
+
|
|
22
|
+
export default createAuthProxy({
|
|
23
|
+
authConfig,
|
|
24
|
+
sessionManager,
|
|
25
|
+
rbacEngine,
|
|
26
|
+
cookieName: 'my_session',
|
|
27
|
+
loginUrl: '/login',
|
|
28
|
+
unauthorizedUrl: '/403',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const config = {
|
|
32
|
+
matcher: ['/((?!_next|api/auth|login).*)'],
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Middleware (Next.js 14–15 — Legacy)
|
|
37
|
+
|
|
38
|
+
> **Deprecated**: For Next.js >=16, use `createAuthProxy` above instead.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// middleware.ts (project root)
|
|
17
42
|
import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';
|
|
18
43
|
import { sessionManager, rbacEngine, authConfig } from './lib/auth';
|
|
19
44
|
|
|
@@ -59,11 +84,18 @@ import { setSessionCookie } from '@stackwright-pro/auth-nextjs';
|
|
|
59
84
|
export default async function handler(req, res) {
|
|
60
85
|
const session = await authenticateUser(req.body);
|
|
61
86
|
const jwt = await sessionManager.serialize(session);
|
|
62
|
-
|
|
87
|
+
|
|
63
88
|
setSessionCookie(res, jwt, {
|
|
64
89
|
maxAge: 900, // 15 minutes
|
|
65
90
|
});
|
|
66
|
-
|
|
91
|
+
|
|
67
92
|
res.json({ success: true });
|
|
68
93
|
}
|
|
69
94
|
```
|
|
95
|
+
|
|
96
|
+
## Subpath Exports
|
|
97
|
+
|
|
98
|
+
| Import path | Convention | Next.js version |
|
|
99
|
+
| ------------------------------------ | --------------------------- | --------------- |
|
|
100
|
+
| `@stackwright-pro/auth-nextjs` | Both exports available | All |
|
|
101
|
+
| `@stackwright-pro/auth-nextjs/proxy` | Proxy only (tree-shakeable) | >=16 |
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// src/auth-handler.ts
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
function createAuthHandler(config) {
|
|
4
|
+
const {
|
|
5
|
+
sessionManager,
|
|
6
|
+
rbacEngine,
|
|
7
|
+
cookieName = "stackwright_session",
|
|
8
|
+
loginUrl = "/login",
|
|
9
|
+
unauthorizedUrl = "/unauthorized"
|
|
10
|
+
} = config;
|
|
11
|
+
return async function authHandler(request) {
|
|
12
|
+
const { pathname } = request.nextUrl;
|
|
13
|
+
if (rbacEngine.isPublicRoute(pathname)) {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const sessionCookie = request.cookies.get(cookieName);
|
|
17
|
+
let session = null;
|
|
18
|
+
if (sessionCookie) {
|
|
19
|
+
session = await sessionManager.deserialize(sessionCookie.value);
|
|
20
|
+
}
|
|
21
|
+
if (!session || sessionManager.isExpired(session)) {
|
|
22
|
+
const url = request.nextUrl.clone();
|
|
23
|
+
url.pathname = loginUrl;
|
|
24
|
+
url.searchParams.set("redirect", pathname);
|
|
25
|
+
return NextResponse.redirect(url);
|
|
26
|
+
}
|
|
27
|
+
if (!rbacEngine.canAccessRoute(session.user, pathname)) {
|
|
28
|
+
const url = request.nextUrl.clone();
|
|
29
|
+
url.pathname = unauthorizedUrl;
|
|
30
|
+
return NextResponse.redirect(url);
|
|
31
|
+
}
|
|
32
|
+
if (sessionManager.shouldRefresh(session)) {
|
|
33
|
+
const refreshed = await sessionManager.refreshSession(session);
|
|
34
|
+
const newJwt = await sessionManager.serialize(refreshed);
|
|
35
|
+
const response = NextResponse.next();
|
|
36
|
+
response.cookies.set(cookieName, newJwt, {
|
|
37
|
+
httpOnly: true,
|
|
38
|
+
secure: true,
|
|
39
|
+
sameSite: "lax",
|
|
40
|
+
maxAge: 900
|
|
41
|
+
// 15 minutes
|
|
42
|
+
});
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/proxy.ts
|
|
50
|
+
function createAuthProxy(config) {
|
|
51
|
+
return createAuthHandler(config);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
createAuthHandler,
|
|
56
|
+
createAuthProxy
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=chunk-MFZSH4YL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth-handler.ts","../src/proxy.ts"],"sourcesContent":["import { type NextRequest, NextResponse } from 'next/server';\nimport {\n SessionManager,\n RBACEngine,\n type AuthConfig,\n type AuthSession,\n} from '@stackwright-pro/auth';\n\nexport interface AuthHandlerConfig {\n /**\n * Auth configuration\n */\n authConfig: AuthConfig;\n\n /**\n * Session manager instance\n */\n sessionManager: SessionManager;\n\n /**\n * RBAC engine instance\n */\n rbacEngine: RBACEngine;\n\n /**\n * Cookie name for session (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * URL to redirect to when authentication fails (default: '/login')\n */\n loginUrl?: string;\n\n /**\n * URL to redirect to when authorization fails (default: '/unauthorized')\n */\n unauthorizedUrl?: string;\n}\n\n/**\n * Core auth handler shared by both the middleware (Next.js <16) and\n * proxy (Next.js >=16) conventions.\n *\n * @internal — consumers should use `createAuthMiddleware` or `createAuthProxy`.\n */\nexport function createAuthHandler(config: AuthHandlerConfig) {\n const {\n sessionManager,\n rbacEngine,\n cookieName = 'stackwright_session',\n loginUrl = '/login',\n unauthorizedUrl = '/unauthorized',\n } = config;\n\n return async function authHandler(request: NextRequest): Promise<NextResponse | undefined> {\n const { pathname } = request.nextUrl;\n\n // Check if route is public\n if (rbacEngine.isPublicRoute(pathname)) {\n return undefined; // Continue to next handler\n }\n\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n let session: AuthSession | null = null;\n\n if (sessionCookie) {\n session = await sessionManager.deserialize(sessionCookie.value);\n }\n\n // Check if session is valid\n if (!session || sessionManager.isExpired(session)) {\n // Redirect to login\n const url = request.nextUrl.clone();\n url.pathname = loginUrl;\n url.searchParams.set('redirect', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if user can access route\n if (!rbacEngine.canAccessRoute(session.user, pathname)) {\n // Redirect to unauthorized\n const url = request.nextUrl.clone();\n url.pathname = unauthorizedUrl;\n return NextResponse.redirect(url);\n }\n\n // Refresh session if needed\n if (sessionManager.shouldRefresh(session)) {\n const refreshed = await sessionManager.refreshSession(session);\n const newJwt = await sessionManager.serialize(refreshed);\n\n const response = NextResponse.next();\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge: 900, // 15 minutes\n });\n\n return response;\n }\n\n // Allow request to continue\n return undefined;\n };\n}\n","import { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\n\n/**\n * Configuration for Next.js proxy-based auth (Next.js >=16).\n */\nexport type ProxyConfig = AuthHandlerConfig;\n\n/**\n * Create a Next.js proxy handler for authentication and authorization.\n *\n * For Next.js >=16 projects that use the `proxy.ts` file convention,\n * replacing the deprecated `middleware.ts` convention.\n *\n * @example\n * ```typescript\n * // proxy.ts (Next.js >=16)\n * import { createAuthProxy } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthProxy({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthProxy(config: ProxyConfig) {\n return createAuthHandler(config);\n}\n"],"mappings":";AAAA,SAA2B,oBAAoB;AA8CxC,SAAS,kBAAkB,QAA2B;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX,kBAAkB;AAAA,EACpB,IAAI;AAEJ,SAAO,eAAe,YAAY,SAAyD;AACzF,UAAM,EAAE,SAAS,IAAI,QAAQ;AAG7B,QAAI,WAAW,cAAc,QAAQ,GAAG;AACtC,aAAO;AAAA,IACT;AAGA,UAAM,gBAAgB,QAAQ,QAAQ,IAAI,UAAU;AACpD,QAAI,UAA8B;AAElC,QAAI,eAAe;AACjB,gBAAU,MAAM,eAAe,YAAY,cAAc,KAAK;AAAA,IAChE;AAGA,QAAI,CAAC,WAAW,eAAe,UAAU,OAAO,GAAG;AAEjD,YAAM,MAAM,QAAQ,QAAQ,MAAM;AAClC,UAAI,WAAW;AACf,UAAI,aAAa,IAAI,YAAY,QAAQ;AACzC,aAAO,aAAa,SAAS,GAAG;AAAA,IAClC;AAGA,QAAI,CAAC,WAAW,eAAe,QAAQ,MAAM,QAAQ,GAAG;AAEtD,YAAM,MAAM,QAAQ,QAAQ,MAAM;AAClC,UAAI,WAAW;AACf,aAAO,aAAa,SAAS,GAAG;AAAA,IAClC;AAGA,QAAI,eAAe,cAAc,OAAO,GAAG;AACzC,YAAM,YAAY,MAAM,eAAe,eAAe,OAAO;AAC7D,YAAM,SAAS,MAAM,eAAe,UAAU,SAAS;AAEvD,YAAM,WAAW,aAAa,KAAK;AACnC,eAAS,QAAQ,IAAI,YAAY,QAAQ;AAAA,QACvC,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,QAAQ;AAAA;AAAA,MACV,CAAC;AAED,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;;;AC9EO,SAAS,gBAAgB,QAAqB;AACnD,SAAO,kBAAkB,MAAM;AACjC;","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,40 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
1
|
+
import * as next_server_js from 'next/server.js';
|
|
2
|
+
import { A as AuthHandlerConfig } from './proxy-Blj2kIJp.mjs';
|
|
3
|
+
export { P as ProxyConfig, c as createAuthHandler, a as createAuthProxy } from './proxy-Blj2kIJp.mjs';
|
|
4
4
|
import { NextApiRequest, NextApiResponse } from 'next';
|
|
5
|
+
import { AuthSession, SessionManager, RBACEngine, CookieOptions } from '@stackwright-pro/auth';
|
|
6
|
+
export { AuthConfig, AuthContext, AuthContextValue, AuthProvider, AuthProviderProps, AuthSession, AuthUser, RBACEngine, useAuth, useRequireAuth } from '@stackwright-pro/auth';
|
|
7
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
5
8
|
|
|
6
|
-
interface MiddlewareConfig {
|
|
7
|
-
/**
|
|
8
|
-
* Auth configuration
|
|
9
|
-
*/
|
|
10
|
-
authConfig: AuthConfig;
|
|
11
|
-
/**
|
|
12
|
-
* Session manager instance
|
|
13
|
-
*/
|
|
14
|
-
sessionManager: SessionManager;
|
|
15
|
-
/**
|
|
16
|
-
* RBAC engine instance
|
|
17
|
-
*/
|
|
18
|
-
rbacEngine: RBACEngine;
|
|
19
|
-
/**
|
|
20
|
-
* Cookie name for session (default: 'stackwright_session')
|
|
21
|
-
*/
|
|
22
|
-
cookieName?: string;
|
|
23
|
-
/**
|
|
24
|
-
* URL to redirect to when authentication fails (default: '/login')
|
|
25
|
-
*/
|
|
26
|
-
loginUrl?: string;
|
|
27
|
-
/**
|
|
28
|
-
* URL to redirect to when authorization fails (default: '/unauthorized')
|
|
29
|
-
*/
|
|
30
|
-
unauthorizedUrl?: string;
|
|
31
|
-
}
|
|
32
9
|
/**
|
|
33
|
-
*
|
|
10
|
+
* Configuration for Next.js middleware-based auth (Next.js <16).
|
|
11
|
+
*
|
|
12
|
+
* @deprecated For Next.js >=16, use {@link ProxyConfig} with {@link createAuthProxy} instead.
|
|
13
|
+
* The `middleware.ts` file convention is deprecated in Next.js 16.
|
|
14
|
+
*/
|
|
15
|
+
type MiddlewareConfig = AuthHandlerConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Create Next.js middleware for authentication and authorization.
|
|
18
|
+
*
|
|
19
|
+
* For Next.js 14–15 projects that use the `middleware.ts` file convention.
|
|
20
|
+
*
|
|
21
|
+
* @deprecated For Next.js >=16, use {@link createAuthProxy} instead.
|
|
22
|
+
* The `middleware.ts` file convention is deprecated in Next.js 16 in favor of `proxy.ts`.
|
|
34
23
|
*
|
|
35
24
|
* @example
|
|
36
25
|
* ```typescript
|
|
37
|
-
* // middleware.ts
|
|
26
|
+
* // middleware.ts (Next.js 14–15)
|
|
38
27
|
* import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';
|
|
39
28
|
*
|
|
40
29
|
* export default createAuthMiddleware({
|
|
@@ -48,7 +37,7 @@ interface MiddlewareConfig {
|
|
|
48
37
|
* };
|
|
49
38
|
* ```
|
|
50
39
|
*/
|
|
51
|
-
declare function createAuthMiddleware(config: MiddlewareConfig): (request: NextRequest) => Promise<NextResponse | undefined>;
|
|
40
|
+
declare function createAuthMiddleware(config: MiddlewareConfig): (request: next_server_js.NextRequest) => Promise<next_server_js.NextResponse | undefined>;
|
|
52
41
|
|
|
53
42
|
interface ProtectedRouteConfig {
|
|
54
43
|
/**
|
|
@@ -204,4 +193,4 @@ declare function clearSessionCookieOnResponse(response: NextResponse, options?:
|
|
|
204
193
|
cookieName?: string;
|
|
205
194
|
}): NextResponse;
|
|
206
195
|
|
|
207
|
-
export { type AuthenticatedHandler, type AuthenticatedRouteHandler, type MiddlewareConfig, type ProtectedRouteConfig, type RouteHandlerConfig, clearSessionCookie, clearSessionCookieOnResponse, createAuthMiddleware, protectedRoute, protectedRouteHandler, setSessionCookie, setSessionCookieOnResponse };
|
|
196
|
+
export { AuthHandlerConfig, type AuthenticatedHandler, type AuthenticatedRouteHandler, type MiddlewareConfig, type ProtectedRouteConfig, type RouteHandlerConfig, clearSessionCookie, clearSessionCookieOnResponse, createAuthMiddleware, protectedRoute, protectedRouteHandler, setSessionCookie, setSessionCookieOnResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,40 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
1
|
+
import * as next_server_js from 'next/server.js';
|
|
2
|
+
import { A as AuthHandlerConfig } from './proxy-Blj2kIJp.js';
|
|
3
|
+
export { P as ProxyConfig, c as createAuthHandler, a as createAuthProxy } from './proxy-Blj2kIJp.js';
|
|
4
4
|
import { NextApiRequest, NextApiResponse } from 'next';
|
|
5
|
+
import { AuthSession, SessionManager, RBACEngine, CookieOptions } from '@stackwright-pro/auth';
|
|
6
|
+
export { AuthConfig, AuthContext, AuthContextValue, AuthProvider, AuthProviderProps, AuthSession, AuthUser, RBACEngine, useAuth, useRequireAuth } from '@stackwright-pro/auth';
|
|
7
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
5
8
|
|
|
6
|
-
interface MiddlewareConfig {
|
|
7
|
-
/**
|
|
8
|
-
* Auth configuration
|
|
9
|
-
*/
|
|
10
|
-
authConfig: AuthConfig;
|
|
11
|
-
/**
|
|
12
|
-
* Session manager instance
|
|
13
|
-
*/
|
|
14
|
-
sessionManager: SessionManager;
|
|
15
|
-
/**
|
|
16
|
-
* RBAC engine instance
|
|
17
|
-
*/
|
|
18
|
-
rbacEngine: RBACEngine;
|
|
19
|
-
/**
|
|
20
|
-
* Cookie name for session (default: 'stackwright_session')
|
|
21
|
-
*/
|
|
22
|
-
cookieName?: string;
|
|
23
|
-
/**
|
|
24
|
-
* URL to redirect to when authentication fails (default: '/login')
|
|
25
|
-
*/
|
|
26
|
-
loginUrl?: string;
|
|
27
|
-
/**
|
|
28
|
-
* URL to redirect to when authorization fails (default: '/unauthorized')
|
|
29
|
-
*/
|
|
30
|
-
unauthorizedUrl?: string;
|
|
31
|
-
}
|
|
32
9
|
/**
|
|
33
|
-
*
|
|
10
|
+
* Configuration for Next.js middleware-based auth (Next.js <16).
|
|
11
|
+
*
|
|
12
|
+
* @deprecated For Next.js >=16, use {@link ProxyConfig} with {@link createAuthProxy} instead.
|
|
13
|
+
* The `middleware.ts` file convention is deprecated in Next.js 16.
|
|
14
|
+
*/
|
|
15
|
+
type MiddlewareConfig = AuthHandlerConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Create Next.js middleware for authentication and authorization.
|
|
18
|
+
*
|
|
19
|
+
* For Next.js 14–15 projects that use the `middleware.ts` file convention.
|
|
20
|
+
*
|
|
21
|
+
* @deprecated For Next.js >=16, use {@link createAuthProxy} instead.
|
|
22
|
+
* The `middleware.ts` file convention is deprecated in Next.js 16 in favor of `proxy.ts`.
|
|
34
23
|
*
|
|
35
24
|
* @example
|
|
36
25
|
* ```typescript
|
|
37
|
-
* // middleware.ts
|
|
26
|
+
* // middleware.ts (Next.js 14–15)
|
|
38
27
|
* import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';
|
|
39
28
|
*
|
|
40
29
|
* export default createAuthMiddleware({
|
|
@@ -48,7 +37,7 @@ interface MiddlewareConfig {
|
|
|
48
37
|
* };
|
|
49
38
|
* ```
|
|
50
39
|
*/
|
|
51
|
-
declare function createAuthMiddleware(config: MiddlewareConfig): (request: NextRequest) => Promise<NextResponse | undefined>;
|
|
40
|
+
declare function createAuthMiddleware(config: MiddlewareConfig): (request: next_server_js.NextRequest) => Promise<next_server_js.NextResponse | undefined>;
|
|
52
41
|
|
|
53
42
|
interface ProtectedRouteConfig {
|
|
54
43
|
/**
|
|
@@ -204,4 +193,4 @@ declare function clearSessionCookieOnResponse(response: NextResponse, options?:
|
|
|
204
193
|
cookieName?: string;
|
|
205
194
|
}): NextResponse;
|
|
206
195
|
|
|
207
|
-
export { type AuthenticatedHandler, type AuthenticatedRouteHandler, type MiddlewareConfig, type ProtectedRouteConfig, type RouteHandlerConfig, clearSessionCookie, clearSessionCookieOnResponse, createAuthMiddleware, protectedRoute, protectedRouteHandler, setSessionCookie, setSessionCookieOnResponse };
|
|
196
|
+
export { AuthHandlerConfig, type AuthenticatedHandler, type AuthenticatedRouteHandler, type MiddlewareConfig, type ProtectedRouteConfig, type RouteHandlerConfig, clearSessionCookie, clearSessionCookieOnResponse, createAuthMiddleware, protectedRoute, protectedRouteHandler, setSessionCookie, setSessionCookieOnResponse };
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,9 @@ __export(index_exports, {
|
|
|
25
25
|
RBACEngine: () => import_auth2.RBACEngine,
|
|
26
26
|
clearSessionCookie: () => clearSessionCookie,
|
|
27
27
|
clearSessionCookieOnResponse: () => clearSessionCookieOnResponse,
|
|
28
|
+
createAuthHandler: () => createAuthHandler,
|
|
28
29
|
createAuthMiddleware: () => createAuthMiddleware,
|
|
30
|
+
createAuthProxy: () => createAuthProxy,
|
|
29
31
|
protectedRoute: () => protectedRoute,
|
|
30
32
|
protectedRouteHandler: () => protectedRouteHandler,
|
|
31
33
|
setSessionCookie: () => setSessionCookie,
|
|
@@ -35,9 +37,9 @@ __export(index_exports, {
|
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(index_exports);
|
|
37
39
|
|
|
38
|
-
// src/
|
|
40
|
+
// src/auth-handler.ts
|
|
39
41
|
var import_server = require("next/server");
|
|
40
|
-
function
|
|
42
|
+
function createAuthHandler(config) {
|
|
41
43
|
const {
|
|
42
44
|
sessionManager,
|
|
43
45
|
rbacEngine,
|
|
@@ -45,7 +47,7 @@ function createAuthMiddleware(config) {
|
|
|
45
47
|
loginUrl = "/login",
|
|
46
48
|
unauthorizedUrl = "/unauthorized"
|
|
47
49
|
} = config;
|
|
48
|
-
return async function
|
|
50
|
+
return async function authHandler(request) {
|
|
49
51
|
const { pathname } = request.nextUrl;
|
|
50
52
|
if (rbacEngine.isPublicRoute(pathname)) {
|
|
51
53
|
return void 0;
|
|
@@ -83,6 +85,16 @@ function createAuthMiddleware(config) {
|
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// src/middleware.ts
|
|
89
|
+
function createAuthMiddleware(config) {
|
|
90
|
+
return createAuthHandler(config);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/proxy.ts
|
|
94
|
+
function createAuthProxy(config) {
|
|
95
|
+
return createAuthHandler(config);
|
|
96
|
+
}
|
|
97
|
+
|
|
86
98
|
// src/api-helpers.ts
|
|
87
99
|
function protectedRoute(handler, config) {
|
|
88
100
|
const { sessionManager, roles, permissions, cookieName = "stackwright_session" } = config;
|
|
@@ -224,7 +236,9 @@ function clearSessionCookieOnResponse(response, options = {}) {
|
|
|
224
236
|
RBACEngine,
|
|
225
237
|
clearSessionCookie,
|
|
226
238
|
clearSessionCookieOnResponse,
|
|
239
|
+
createAuthHandler,
|
|
227
240
|
createAuthMiddleware,
|
|
241
|
+
createAuthProxy,
|
|
228
242
|
protectedRoute,
|
|
229
243
|
protectedRouteHandler,
|
|
230
244
|
setSessionCookie,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/api-helpers.ts","../src/cookie-utils.ts","../src/route-handlers.ts"],"sourcesContent":["export { createAuthMiddleware, type MiddlewareConfig } from './middleware.js';\nexport {\n protectedRoute,\n type ProtectedRouteConfig,\n type AuthenticatedHandler,\n} from './api-helpers.js';\nexport { setSessionCookie, clearSessionCookie } from './cookie-utils.js';\n\n// Re-export commonly used types/classes from core\nexport type { AuthUser, AuthSession, AuthConfig } from '@stackwright-pro/auth';\n\n// Re-export RBAC engine\nexport { RBACEngine } from '@stackwright-pro/auth';\n\n// Re-export React context components for Next.js apps\nexport { AuthProvider, AuthContext, useAuth, useRequireAuth } from '@stackwright-pro/auth';\nexport type { AuthProviderProps, AuthContextValue } from '@stackwright-pro/auth';\n\n// App Router Route Handler helpers (replaces api-helpers for App Router users)\nexport {\n protectedRouteHandler,\n setSessionCookieOnResponse,\n clearSessionCookieOnResponse,\n type RouteHandlerConfig,\n type AuthenticatedRouteHandler,\n} from './route-handlers.js';\n","import { type NextRequest, NextResponse } from 'next/server';\nimport {\n SessionManager,\n RBACEngine,\n type AuthConfig,\n type AuthSession,\n} from '@stackwright-pro/auth';\n\nexport interface MiddlewareConfig {\n /**\n * Auth configuration\n */\n authConfig: AuthConfig;\n\n /**\n * Session manager instance\n */\n sessionManager: SessionManager;\n\n /**\n * RBAC engine instance\n */\n rbacEngine: RBACEngine;\n\n /**\n * Cookie name for session (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * URL to redirect to when authentication fails (default: '/login')\n */\n loginUrl?: string;\n\n /**\n * URL to redirect to when authorization fails (default: '/unauthorized')\n */\n unauthorizedUrl?: string;\n}\n\n/**\n * Create Next.js middleware for authentication and authorization\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthMiddleware({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthMiddleware(config: MiddlewareConfig) {\n const {\n sessionManager,\n rbacEngine,\n cookieName = 'stackwright_session',\n loginUrl = '/login',\n unauthorizedUrl = '/unauthorized',\n } = config;\n\n return async function authMiddleware(request: NextRequest): Promise<NextResponse | undefined> {\n const { pathname } = request.nextUrl;\n\n // Check if route is public\n if (rbacEngine.isPublicRoute(pathname)) {\n return undefined; // Continue to next middleware\n }\n\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n let session: AuthSession | null = null;\n\n if (sessionCookie) {\n session = await sessionManager.deserialize(sessionCookie.value);\n }\n\n // Check if session is valid\n if (!session || sessionManager.isExpired(session)) {\n // Redirect to login\n const url = request.nextUrl.clone();\n url.pathname = loginUrl;\n url.searchParams.set('redirect', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if user can access route\n if (!rbacEngine.canAccessRoute(session.user, pathname)) {\n // Redirect to unauthorized\n const url = request.nextUrl.clone();\n url.pathname = unauthorizedUrl;\n return NextResponse.redirect(url);\n }\n\n // Refresh session if needed\n if (sessionManager.shouldRefresh(session)) {\n const refreshed = await sessionManager.refreshSession(session);\n const newJwt = await sessionManager.serialize(refreshed);\n\n const response = NextResponse.next();\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge: 900, // 15 minutes\n });\n\n return response;\n }\n\n // Allow request to continue\n return undefined;\n };\n}\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { SessionManager, RBACEngine, type AuthSession, type AuthUser } from '@stackwright-pro/auth';\n\nexport interface ProtectedRouteConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session\n */\nexport type AuthenticatedHandler<T = any> = (\n req: NextApiRequest,\n res: NextApiResponse<T>,\n session: AuthSession\n) => void | Promise<void>;\n\n/**\n * Wrap API route with authentication/authorization\n *\n * @example\n * ```typescript\n * // pages/api/equipment/[id].ts\n * export default protectedRoute(\n * async (req, res, session) => {\n * const equipment = await getEquipment(req.query.id);\n * res.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRoute<T = any>(\n handler: AuthenticatedHandler<T>,\n config: ProtectedRouteConfig\n): (req: NextApiRequest, res: NextApiResponse) => Promise<void> {\n const { sessionManager, roles, permissions, cookieName = 'stackwright_session' } = config;\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // Extract session from cookie\n const sessionCookie = req.cookies[cookieName];\n\n if (!sessionCookie) {\n res.status(401).json({ error: 'Not authenticated' } as any);\n return;\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie);\n\n if (!session || sessionManager.isExpired(session)) {\n res.status(401).json({ error: 'Session expired' } as any);\n return;\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for consistent wildcard-aware checking\n if (!config.rbacEngine.hasAnyRole(session.user, roles)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for wildcard-aware permission checking\n if (!config.rbacEngine.hasAllPermissions(session.user, permissions)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasAllPermissions = permissions.every((permission) =>\n session.user.permissions?.includes(permission)\n );\n if (!hasAllPermissions) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Call handler with session\n await handler(req, res, session);\n };\n}\n","import type { NextApiResponse } from 'next';\nimport { serializeCookie, clearCookie, type CookieOptions } from '@stackwright-pro/auth';\n\n/**\n * Set session cookie in Next.js API response\n */\nexport function setSessionCookie(\n res: NextApiResponse,\n sessionJwt: string,\n options: CookieOptions = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n const maxAge = options.maxAge || 900; // 15 minutes default\n\n const cookie = serializeCookie(cookieName, sessionJwt, {\n ...options,\n maxAge,\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n });\n\n res.setHeader('Set-Cookie', cookie);\n}\n\n/**\n * Clear session cookie in Next.js API response\n */\nexport function clearSessionCookie(\n res: NextApiResponse,\n options: Pick<CookieOptions, 'name' | 'domain' | 'path'> = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n\n const cookie = clearCookie(cookieName, options);\n\n res.setHeader('Set-Cookie', cookie);\n}\n","import { type NextRequest, NextResponse } from 'next/server';\nimport { SessionManager, RBACEngine, type AuthSession } from '@stackwright-pro/auth';\n\nexport interface RouteHandlerConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session — App Router Route Handler signature.\n */\nexport type AuthenticatedRouteHandler = (\n request: NextRequest,\n context: { params: Record<string, string> },\n session: AuthSession\n) => Promise<Response> | Response;\n\n/**\n * Wrap an App Router Route Handler with authentication/authorization.\n *\n * This is the App Router equivalent of `protectedRoute()` from `api-helpers.ts`.\n *\n * @example\n * ```typescript\n * // app/api/equipment/[id]/route.ts\n * import { protectedRouteHandler } from '@stackwright-pro/auth-nextjs';\n *\n * export const GET = protectedRouteHandler(\n * async (request, { params }, session) => {\n * const equipment = await getEquipment(params.id);\n * return NextResponse.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRouteHandler(\n handler: AuthenticatedRouteHandler,\n config: RouteHandlerConfig\n): (request: NextRequest, context: { params: Record<string, string> }) => Promise<Response> {\n const {\n sessionManager,\n roles,\n permissions,\n cookieName = 'stackwright_session',\n rbacEngine,\n } = config;\n\n return async (\n request: NextRequest,\n context: { params: Record<string, string> }\n ): Promise<Response> => {\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n\n if (!sessionCookie) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie.value);\n\n if (!session || sessionManager.isExpired(session)) {\n return NextResponse.json({ error: 'Session expired' }, { status: 401 });\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAnyRole(session.user, roles)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAllPermissions(session.user, permissions)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasAllPermissions = permissions.every((p) => session.user.permissions?.includes(p));\n if (!hasAllPermissions) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n return handler(request, context, session);\n };\n}\n\n/**\n * Set the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `setSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/login/route.ts\n * import { setSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST(request: NextRequest) {\n * const session = await createSession(request);\n * const jwt = await sessionManager.serialize(session);\n * const response = NextResponse.json({ ok: true });\n * return setSessionCookieOnResponse(response, jwt);\n * }\n * ```\n */\nexport function setSessionCookieOnResponse(\n response: NextResponse,\n sessionJwt: string,\n options: {\n cookieName?: string;\n maxAge?: number;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n const maxAge = options.maxAge ?? 900; // 15 minutes\n\n response.cookies.set(cookieName, sessionJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge,\n });\n\n return response;\n}\n\n/**\n * Clear the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `clearSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/logout/route.ts\n * import { clearSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST() {\n * const response = NextResponse.json({ ok: true });\n * return clearSessionCookieOnResponse(response);\n * }\n * ```\n */\nexport function clearSessionCookieOnResponse(\n response: NextResponse,\n options: {\n cookieName?: string;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n response.cookies.delete(cookieName);\n return response;\n}\n"],"mappings":"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","names":["import_auth","import_server"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth-handler.ts","../src/middleware.ts","../src/proxy.ts","../src/api-helpers.ts","../src/cookie-utils.ts","../src/route-handlers.ts"],"sourcesContent":["export { createAuthMiddleware, type MiddlewareConfig } from './middleware.js';\nexport { createAuthProxy, type ProxyConfig } from './proxy.js';\nexport { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\nexport {\n protectedRoute,\n type ProtectedRouteConfig,\n type AuthenticatedHandler,\n} from './api-helpers.js';\nexport { setSessionCookie, clearSessionCookie } from './cookie-utils.js';\n\n// Re-export commonly used types/classes from core\nexport type { AuthUser, AuthSession, AuthConfig } from '@stackwright-pro/auth';\n\n// Re-export RBAC engine\nexport { RBACEngine } from '@stackwright-pro/auth';\n\n// Re-export React context components for Next.js apps\nexport { AuthProvider, AuthContext, useAuth, useRequireAuth } from '@stackwright-pro/auth';\nexport type { AuthProviderProps, AuthContextValue } from '@stackwright-pro/auth';\n\n// App Router Route Handler helpers (replaces api-helpers for App Router users)\nexport {\n protectedRouteHandler,\n setSessionCookieOnResponse,\n clearSessionCookieOnResponse,\n type RouteHandlerConfig,\n type AuthenticatedRouteHandler,\n} from './route-handlers.js';\n","import { type NextRequest, NextResponse } from 'next/server';\nimport {\n SessionManager,\n RBACEngine,\n type AuthConfig,\n type AuthSession,\n} from '@stackwright-pro/auth';\n\nexport interface AuthHandlerConfig {\n /**\n * Auth configuration\n */\n authConfig: AuthConfig;\n\n /**\n * Session manager instance\n */\n sessionManager: SessionManager;\n\n /**\n * RBAC engine instance\n */\n rbacEngine: RBACEngine;\n\n /**\n * Cookie name for session (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * URL to redirect to when authentication fails (default: '/login')\n */\n loginUrl?: string;\n\n /**\n * URL to redirect to when authorization fails (default: '/unauthorized')\n */\n unauthorizedUrl?: string;\n}\n\n/**\n * Core auth handler shared by both the middleware (Next.js <16) and\n * proxy (Next.js >=16) conventions.\n *\n * @internal — consumers should use `createAuthMiddleware` or `createAuthProxy`.\n */\nexport function createAuthHandler(config: AuthHandlerConfig) {\n const {\n sessionManager,\n rbacEngine,\n cookieName = 'stackwright_session',\n loginUrl = '/login',\n unauthorizedUrl = '/unauthorized',\n } = config;\n\n return async function authHandler(request: NextRequest): Promise<NextResponse | undefined> {\n const { pathname } = request.nextUrl;\n\n // Check if route is public\n if (rbacEngine.isPublicRoute(pathname)) {\n return undefined; // Continue to next handler\n }\n\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n let session: AuthSession | null = null;\n\n if (sessionCookie) {\n session = await sessionManager.deserialize(sessionCookie.value);\n }\n\n // Check if session is valid\n if (!session || sessionManager.isExpired(session)) {\n // Redirect to login\n const url = request.nextUrl.clone();\n url.pathname = loginUrl;\n url.searchParams.set('redirect', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if user can access route\n if (!rbacEngine.canAccessRoute(session.user, pathname)) {\n // Redirect to unauthorized\n const url = request.nextUrl.clone();\n url.pathname = unauthorizedUrl;\n return NextResponse.redirect(url);\n }\n\n // Refresh session if needed\n if (sessionManager.shouldRefresh(session)) {\n const refreshed = await sessionManager.refreshSession(session);\n const newJwt = await sessionManager.serialize(refreshed);\n\n const response = NextResponse.next();\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge: 900, // 15 minutes\n });\n\n return response;\n }\n\n // Allow request to continue\n return undefined;\n };\n}\n","import { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\n\n/**\n * Configuration for Next.js middleware-based auth (Next.js <16).\n *\n * @deprecated For Next.js >=16, use {@link ProxyConfig} with {@link createAuthProxy} instead.\n * The `middleware.ts` file convention is deprecated in Next.js 16.\n */\nexport type MiddlewareConfig = AuthHandlerConfig;\n\n/**\n * Create Next.js middleware for authentication and authorization.\n *\n * For Next.js 14–15 projects that use the `middleware.ts` file convention.\n *\n * @deprecated For Next.js >=16, use {@link createAuthProxy} instead.\n * The `middleware.ts` file convention is deprecated in Next.js 16 in favor of `proxy.ts`.\n *\n * @example\n * ```typescript\n * // middleware.ts (Next.js 14–15)\n * import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthMiddleware({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthMiddleware(config: MiddlewareConfig) {\n return createAuthHandler(config);\n}\n","import { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\n\n/**\n * Configuration for Next.js proxy-based auth (Next.js >=16).\n */\nexport type ProxyConfig = AuthHandlerConfig;\n\n/**\n * Create a Next.js proxy handler for authentication and authorization.\n *\n * For Next.js >=16 projects that use the `proxy.ts` file convention,\n * replacing the deprecated `middleware.ts` convention.\n *\n * @example\n * ```typescript\n * // proxy.ts (Next.js >=16)\n * import { createAuthProxy } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthProxy({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthProxy(config: ProxyConfig) {\n return createAuthHandler(config);\n}\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { SessionManager, RBACEngine, type AuthSession, type AuthUser } from '@stackwright-pro/auth';\n\nexport interface ProtectedRouteConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session\n */\nexport type AuthenticatedHandler<T = any> = (\n req: NextApiRequest,\n res: NextApiResponse<T>,\n session: AuthSession\n) => void | Promise<void>;\n\n/**\n * Wrap API route with authentication/authorization\n *\n * @example\n * ```typescript\n * // pages/api/equipment/[id].ts\n * export default protectedRoute(\n * async (req, res, session) => {\n * const equipment = await getEquipment(req.query.id);\n * res.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRoute<T = any>(\n handler: AuthenticatedHandler<T>,\n config: ProtectedRouteConfig\n): (req: NextApiRequest, res: NextApiResponse) => Promise<void> {\n const { sessionManager, roles, permissions, cookieName = 'stackwright_session' } = config;\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // Extract session from cookie\n const sessionCookie = req.cookies[cookieName];\n\n if (!sessionCookie) {\n res.status(401).json({ error: 'Not authenticated' } as any);\n return;\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie);\n\n if (!session || sessionManager.isExpired(session)) {\n res.status(401).json({ error: 'Session expired' } as any);\n return;\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for consistent wildcard-aware checking\n if (!config.rbacEngine.hasAnyRole(session.user, roles)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for wildcard-aware permission checking\n if (!config.rbacEngine.hasAllPermissions(session.user, permissions)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasAllPermissions = permissions.every((permission) =>\n session.user.permissions?.includes(permission)\n );\n if (!hasAllPermissions) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Call handler with session\n await handler(req, res, session);\n };\n}\n","import type { NextApiResponse } from 'next';\nimport { serializeCookie, clearCookie, type CookieOptions } from '@stackwright-pro/auth';\n\n/**\n * Set session cookie in Next.js API response\n */\nexport function setSessionCookie(\n res: NextApiResponse,\n sessionJwt: string,\n options: CookieOptions = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n const maxAge = options.maxAge || 900; // 15 minutes default\n\n const cookie = serializeCookie(cookieName, sessionJwt, {\n ...options,\n maxAge,\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n });\n\n res.setHeader('Set-Cookie', cookie);\n}\n\n/**\n * Clear session cookie in Next.js API response\n */\nexport function clearSessionCookie(\n res: NextApiResponse,\n options: Pick<CookieOptions, 'name' | 'domain' | 'path'> = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n\n const cookie = clearCookie(cookieName, options);\n\n res.setHeader('Set-Cookie', cookie);\n}\n","import { type NextRequest, NextResponse } from 'next/server';\nimport { SessionManager, RBACEngine, type AuthSession } from '@stackwright-pro/auth';\n\nexport interface RouteHandlerConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session — App Router Route Handler signature.\n */\nexport type AuthenticatedRouteHandler = (\n request: NextRequest,\n context: { params: Record<string, string> },\n session: AuthSession\n) => Promise<Response> | Response;\n\n/**\n * Wrap an App Router Route Handler with authentication/authorization.\n *\n * This is the App Router equivalent of `protectedRoute()` from `api-helpers.ts`.\n *\n * @example\n * ```typescript\n * // app/api/equipment/[id]/route.ts\n * import { protectedRouteHandler } from '@stackwright-pro/auth-nextjs';\n *\n * export const GET = protectedRouteHandler(\n * async (request, { params }, session) => {\n * const equipment = await getEquipment(params.id);\n * return NextResponse.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRouteHandler(\n handler: AuthenticatedRouteHandler,\n config: RouteHandlerConfig\n): (request: NextRequest, context: { params: Record<string, string> }) => Promise<Response> {\n const {\n sessionManager,\n roles,\n permissions,\n cookieName = 'stackwright_session',\n rbacEngine,\n } = config;\n\n return async (\n request: NextRequest,\n context: { params: Record<string, string> }\n ): Promise<Response> => {\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n\n if (!sessionCookie) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie.value);\n\n if (!session || sessionManager.isExpired(session)) {\n return NextResponse.json({ error: 'Session expired' }, { status: 401 });\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAnyRole(session.user, roles)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAllPermissions(session.user, permissions)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasAllPermissions = permissions.every((p) => session.user.permissions?.includes(p));\n if (!hasAllPermissions) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n return handler(request, context, session);\n };\n}\n\n/**\n * Set the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `setSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/login/route.ts\n * import { setSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST(request: NextRequest) {\n * const session = await createSession(request);\n * const jwt = await sessionManager.serialize(session);\n * const response = NextResponse.json({ ok: true });\n * return setSessionCookieOnResponse(response, jwt);\n * }\n * ```\n */\nexport function setSessionCookieOnResponse(\n response: NextResponse,\n sessionJwt: string,\n options: {\n cookieName?: string;\n maxAge?: number;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n const maxAge = options.maxAge ?? 900; // 15 minutes\n\n response.cookies.set(cookieName, sessionJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge,\n });\n\n return response;\n}\n\n/**\n * Clear the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `clearSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/logout/route.ts\n * import { clearSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST() {\n * const response = NextResponse.json({ ok: true });\n * return clearSessionCookieOnResponse(response);\n * }\n * ```\n */\nexport function clearSessionCookieOnResponse(\n response: NextResponse,\n options: {\n cookieName?: string;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n response.cookies.delete(cookieName);\n return response;\n}\n"],"mappings":"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","names":["import_auth","import_server"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,49 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAuthHandler,
|
|
3
|
+
createAuthProxy
|
|
4
|
+
} from "./chunk-MFZSH4YL.mjs";
|
|
5
|
+
|
|
1
6
|
// src/middleware.ts
|
|
2
|
-
import { NextResponse } from "next/server";
|
|
3
7
|
function createAuthMiddleware(config) {
|
|
4
|
-
|
|
5
|
-
sessionManager,
|
|
6
|
-
rbacEngine,
|
|
7
|
-
cookieName = "stackwright_session",
|
|
8
|
-
loginUrl = "/login",
|
|
9
|
-
unauthorizedUrl = "/unauthorized"
|
|
10
|
-
} = config;
|
|
11
|
-
return async function authMiddleware(request) {
|
|
12
|
-
const { pathname } = request.nextUrl;
|
|
13
|
-
if (rbacEngine.isPublicRoute(pathname)) {
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
const sessionCookie = request.cookies.get(cookieName);
|
|
17
|
-
let session = null;
|
|
18
|
-
if (sessionCookie) {
|
|
19
|
-
session = await sessionManager.deserialize(sessionCookie.value);
|
|
20
|
-
}
|
|
21
|
-
if (!session || sessionManager.isExpired(session)) {
|
|
22
|
-
const url = request.nextUrl.clone();
|
|
23
|
-
url.pathname = loginUrl;
|
|
24
|
-
url.searchParams.set("redirect", pathname);
|
|
25
|
-
return NextResponse.redirect(url);
|
|
26
|
-
}
|
|
27
|
-
if (!rbacEngine.canAccessRoute(session.user, pathname)) {
|
|
28
|
-
const url = request.nextUrl.clone();
|
|
29
|
-
url.pathname = unauthorizedUrl;
|
|
30
|
-
return NextResponse.redirect(url);
|
|
31
|
-
}
|
|
32
|
-
if (sessionManager.shouldRefresh(session)) {
|
|
33
|
-
const refreshed = await sessionManager.refreshSession(session);
|
|
34
|
-
const newJwt = await sessionManager.serialize(refreshed);
|
|
35
|
-
const response = NextResponse.next();
|
|
36
|
-
response.cookies.set(cookieName, newJwt, {
|
|
37
|
-
httpOnly: true,
|
|
38
|
-
secure: true,
|
|
39
|
-
sameSite: "lax",
|
|
40
|
-
maxAge: 900
|
|
41
|
-
// 15 minutes
|
|
42
|
-
});
|
|
43
|
-
return response;
|
|
44
|
-
}
|
|
45
|
-
return void 0;
|
|
46
|
-
};
|
|
8
|
+
return createAuthHandler(config);
|
|
47
9
|
}
|
|
48
10
|
|
|
49
11
|
// src/api-helpers.ts
|
|
@@ -119,7 +81,7 @@ import { RBACEngine } from "@stackwright-pro/auth";
|
|
|
119
81
|
import { AuthProvider, AuthContext, useAuth, useRequireAuth } from "@stackwright-pro/auth";
|
|
120
82
|
|
|
121
83
|
// src/route-handlers.ts
|
|
122
|
-
import { NextResponse
|
|
84
|
+
import { NextResponse } from "next/server";
|
|
123
85
|
function protectedRouteHandler(handler, config) {
|
|
124
86
|
const {
|
|
125
87
|
sessionManager,
|
|
@@ -131,33 +93,33 @@ function protectedRouteHandler(handler, config) {
|
|
|
131
93
|
return async (request, context) => {
|
|
132
94
|
const sessionCookie = request.cookies.get(cookieName);
|
|
133
95
|
if (!sessionCookie) {
|
|
134
|
-
return
|
|
96
|
+
return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
|
|
135
97
|
}
|
|
136
98
|
const session = await sessionManager.deserialize(sessionCookie.value);
|
|
137
99
|
if (!session || sessionManager.isExpired(session)) {
|
|
138
|
-
return
|
|
100
|
+
return NextResponse.json({ error: "Session expired" }, { status: 401 });
|
|
139
101
|
}
|
|
140
102
|
if (roles && roles.length > 0) {
|
|
141
103
|
if (rbacEngine) {
|
|
142
104
|
if (!rbacEngine.hasAnyRole(session.user, roles)) {
|
|
143
|
-
return
|
|
105
|
+
return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 });
|
|
144
106
|
}
|
|
145
107
|
} else {
|
|
146
108
|
const hasRole = roles.some((role) => session.user.roles.includes(role));
|
|
147
109
|
if (!hasRole) {
|
|
148
|
-
return
|
|
110
|
+
return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 });
|
|
149
111
|
}
|
|
150
112
|
}
|
|
151
113
|
}
|
|
152
114
|
if (permissions && permissions.length > 0) {
|
|
153
115
|
if (rbacEngine) {
|
|
154
116
|
if (!rbacEngine.hasAllPermissions(session.user, permissions)) {
|
|
155
|
-
return
|
|
117
|
+
return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 });
|
|
156
118
|
}
|
|
157
119
|
} else {
|
|
158
120
|
const hasAllPermissions = permissions.every((p) => session.user.permissions?.includes(p));
|
|
159
121
|
if (!hasAllPermissions) {
|
|
160
|
-
return
|
|
122
|
+
return NextResponse.json({ error: "Insufficient permissions" }, { status: 403 });
|
|
161
123
|
}
|
|
162
124
|
}
|
|
163
125
|
}
|
|
@@ -186,7 +148,9 @@ export {
|
|
|
186
148
|
RBACEngine,
|
|
187
149
|
clearSessionCookie,
|
|
188
150
|
clearSessionCookieOnResponse,
|
|
151
|
+
createAuthHandler,
|
|
189
152
|
createAuthMiddleware,
|
|
153
|
+
createAuthProxy,
|
|
190
154
|
protectedRoute,
|
|
191
155
|
protectedRouteHandler,
|
|
192
156
|
setSessionCookie,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts","../src/api-helpers.ts","../src/cookie-utils.ts","../src/index.ts","../src/route-handlers.ts"],"sourcesContent":["import { type NextRequest, NextResponse } from 'next/server';\nimport {\n SessionManager,\n RBACEngine,\n type AuthConfig,\n type AuthSession,\n} from '@stackwright-pro/auth';\n\nexport interface MiddlewareConfig {\n /**\n * Auth configuration\n */\n authConfig: AuthConfig;\n\n /**\n * Session manager instance\n */\n sessionManager: SessionManager;\n\n /**\n * RBAC engine instance\n */\n rbacEngine: RBACEngine;\n\n /**\n * Cookie name for session (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * URL to redirect to when authentication fails (default: '/login')\n */\n loginUrl?: string;\n\n /**\n * URL to redirect to when authorization fails (default: '/unauthorized')\n */\n unauthorizedUrl?: string;\n}\n\n/**\n * Create Next.js middleware for authentication and authorization\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthMiddleware({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthMiddleware(config: MiddlewareConfig) {\n const {\n sessionManager,\n rbacEngine,\n cookieName = 'stackwright_session',\n loginUrl = '/login',\n unauthorizedUrl = '/unauthorized',\n } = config;\n\n return async function authMiddleware(request: NextRequest): Promise<NextResponse | undefined> {\n const { pathname } = request.nextUrl;\n\n // Check if route is public\n if (rbacEngine.isPublicRoute(pathname)) {\n return undefined; // Continue to next middleware\n }\n\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n let session: AuthSession | null = null;\n\n if (sessionCookie) {\n session = await sessionManager.deserialize(sessionCookie.value);\n }\n\n // Check if session is valid\n if (!session || sessionManager.isExpired(session)) {\n // Redirect to login\n const url = request.nextUrl.clone();\n url.pathname = loginUrl;\n url.searchParams.set('redirect', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if user can access route\n if (!rbacEngine.canAccessRoute(session.user, pathname)) {\n // Redirect to unauthorized\n const url = request.nextUrl.clone();\n url.pathname = unauthorizedUrl;\n return NextResponse.redirect(url);\n }\n\n // Refresh session if needed\n if (sessionManager.shouldRefresh(session)) {\n const refreshed = await sessionManager.refreshSession(session);\n const newJwt = await sessionManager.serialize(refreshed);\n\n const response = NextResponse.next();\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge: 900, // 15 minutes\n });\n\n return response;\n }\n\n // Allow request to continue\n return undefined;\n };\n}\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { SessionManager, RBACEngine, type AuthSession, type AuthUser } from '@stackwright-pro/auth';\n\nexport interface ProtectedRouteConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session\n */\nexport type AuthenticatedHandler<T = any> = (\n req: NextApiRequest,\n res: NextApiResponse<T>,\n session: AuthSession\n) => void | Promise<void>;\n\n/**\n * Wrap API route with authentication/authorization\n *\n * @example\n * ```typescript\n * // pages/api/equipment/[id].ts\n * export default protectedRoute(\n * async (req, res, session) => {\n * const equipment = await getEquipment(req.query.id);\n * res.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRoute<T = any>(\n handler: AuthenticatedHandler<T>,\n config: ProtectedRouteConfig\n): (req: NextApiRequest, res: NextApiResponse) => Promise<void> {\n const { sessionManager, roles, permissions, cookieName = 'stackwright_session' } = config;\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // Extract session from cookie\n const sessionCookie = req.cookies[cookieName];\n\n if (!sessionCookie) {\n res.status(401).json({ error: 'Not authenticated' } as any);\n return;\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie);\n\n if (!session || sessionManager.isExpired(session)) {\n res.status(401).json({ error: 'Session expired' } as any);\n return;\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for consistent wildcard-aware checking\n if (!config.rbacEngine.hasAnyRole(session.user, roles)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for wildcard-aware permission checking\n if (!config.rbacEngine.hasAllPermissions(session.user, permissions)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasAllPermissions = permissions.every((permission) =>\n session.user.permissions?.includes(permission)\n );\n if (!hasAllPermissions) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Call handler with session\n await handler(req, res, session);\n };\n}\n","import type { NextApiResponse } from 'next';\nimport { serializeCookie, clearCookie, type CookieOptions } from '@stackwright-pro/auth';\n\n/**\n * Set session cookie in Next.js API response\n */\nexport function setSessionCookie(\n res: NextApiResponse,\n sessionJwt: string,\n options: CookieOptions = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n const maxAge = options.maxAge || 900; // 15 minutes default\n\n const cookie = serializeCookie(cookieName, sessionJwt, {\n ...options,\n maxAge,\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n });\n\n res.setHeader('Set-Cookie', cookie);\n}\n\n/**\n * Clear session cookie in Next.js API response\n */\nexport function clearSessionCookie(\n res: NextApiResponse,\n options: Pick<CookieOptions, 'name' | 'domain' | 'path'> = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n\n const cookie = clearCookie(cookieName, options);\n\n res.setHeader('Set-Cookie', cookie);\n}\n","export { createAuthMiddleware, type MiddlewareConfig } from './middleware.js';\nexport {\n protectedRoute,\n type ProtectedRouteConfig,\n type AuthenticatedHandler,\n} from './api-helpers.js';\nexport { setSessionCookie, clearSessionCookie } from './cookie-utils.js';\n\n// Re-export commonly used types/classes from core\nexport type { AuthUser, AuthSession, AuthConfig } from '@stackwright-pro/auth';\n\n// Re-export RBAC engine\nexport { RBACEngine } from '@stackwright-pro/auth';\n\n// Re-export React context components for Next.js apps\nexport { AuthProvider, AuthContext, useAuth, useRequireAuth } from '@stackwright-pro/auth';\nexport type { AuthProviderProps, AuthContextValue } from '@stackwright-pro/auth';\n\n// App Router Route Handler helpers (replaces api-helpers for App Router users)\nexport {\n protectedRouteHandler,\n setSessionCookieOnResponse,\n clearSessionCookieOnResponse,\n type RouteHandlerConfig,\n type AuthenticatedRouteHandler,\n} from './route-handlers.js';\n","import { type NextRequest, NextResponse } from 'next/server';\nimport { SessionManager, RBACEngine, type AuthSession } from '@stackwright-pro/auth';\n\nexport interface RouteHandlerConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session — App Router Route Handler signature.\n */\nexport type AuthenticatedRouteHandler = (\n request: NextRequest,\n context: { params: Record<string, string> },\n session: AuthSession\n) => Promise<Response> | Response;\n\n/**\n * Wrap an App Router Route Handler with authentication/authorization.\n *\n * This is the App Router equivalent of `protectedRoute()` from `api-helpers.ts`.\n *\n * @example\n * ```typescript\n * // app/api/equipment/[id]/route.ts\n * import { protectedRouteHandler } from '@stackwright-pro/auth-nextjs';\n *\n * export const GET = protectedRouteHandler(\n * async (request, { params }, session) => {\n * const equipment = await getEquipment(params.id);\n * return NextResponse.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRouteHandler(\n handler: AuthenticatedRouteHandler,\n config: RouteHandlerConfig\n): (request: NextRequest, context: { params: Record<string, string> }) => Promise<Response> {\n const {\n sessionManager,\n roles,\n permissions,\n cookieName = 'stackwright_session',\n rbacEngine,\n } = config;\n\n return async (\n request: NextRequest,\n context: { params: Record<string, string> }\n ): Promise<Response> => {\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n\n if (!sessionCookie) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie.value);\n\n if (!session || sessionManager.isExpired(session)) {\n return NextResponse.json({ error: 'Session expired' }, { status: 401 });\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAnyRole(session.user, roles)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAllPermissions(session.user, permissions)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasAllPermissions = permissions.every((p) => session.user.permissions?.includes(p));\n if (!hasAllPermissions) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n return handler(request, context, session);\n };\n}\n\n/**\n * Set the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `setSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/login/route.ts\n * import { setSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST(request: NextRequest) {\n * const session = await createSession(request);\n * const jwt = await sessionManager.serialize(session);\n * const response = NextResponse.json({ ok: true });\n * return setSessionCookieOnResponse(response, jwt);\n * }\n * ```\n */\nexport function setSessionCookieOnResponse(\n response: NextResponse,\n sessionJwt: string,\n options: {\n cookieName?: string;\n maxAge?: number;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n const maxAge = options.maxAge ?? 900; // 15 minutes\n\n response.cookies.set(cookieName, sessionJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge,\n });\n\n return response;\n}\n\n/**\n * Clear the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `clearSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/logout/route.ts\n * import { clearSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST() {\n * const response = NextResponse.json({ ok: true });\n * return clearSessionCookieOnResponse(response);\n * }\n * ```\n */\nexport function clearSessionCookieOnResponse(\n response: NextResponse,\n options: {\n cookieName?: string;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n response.cookies.delete(cookieName);\n return response;\n}\n"],"mappings":"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","names":["NextResponse"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/api-helpers.ts","../src/cookie-utils.ts","../src/index.ts","../src/route-handlers.ts"],"sourcesContent":["import { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\n\n/**\n * Configuration for Next.js middleware-based auth (Next.js <16).\n *\n * @deprecated For Next.js >=16, use {@link ProxyConfig} with {@link createAuthProxy} instead.\n * The `middleware.ts` file convention is deprecated in Next.js 16.\n */\nexport type MiddlewareConfig = AuthHandlerConfig;\n\n/**\n * Create Next.js middleware for authentication and authorization.\n *\n * For Next.js 14–15 projects that use the `middleware.ts` file convention.\n *\n * @deprecated For Next.js >=16, use {@link createAuthProxy} instead.\n * The `middleware.ts` file convention is deprecated in Next.js 16 in favor of `proxy.ts`.\n *\n * @example\n * ```typescript\n * // middleware.ts (Next.js 14–15)\n * import { createAuthMiddleware } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthMiddleware({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthMiddleware(config: MiddlewareConfig) {\n return createAuthHandler(config);\n}\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { SessionManager, RBACEngine, type AuthSession, type AuthUser } from '@stackwright-pro/auth';\n\nexport interface ProtectedRouteConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session\n */\nexport type AuthenticatedHandler<T = any> = (\n req: NextApiRequest,\n res: NextApiResponse<T>,\n session: AuthSession\n) => void | Promise<void>;\n\n/**\n * Wrap API route with authentication/authorization\n *\n * @example\n * ```typescript\n * // pages/api/equipment/[id].ts\n * export default protectedRoute(\n * async (req, res, session) => {\n * const equipment = await getEquipment(req.query.id);\n * res.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRoute<T = any>(\n handler: AuthenticatedHandler<T>,\n config: ProtectedRouteConfig\n): (req: NextApiRequest, res: NextApiResponse) => Promise<void> {\n const { sessionManager, roles, permissions, cookieName = 'stackwright_session' } = config;\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // Extract session from cookie\n const sessionCookie = req.cookies[cookieName];\n\n if (!sessionCookie) {\n res.status(401).json({ error: 'Not authenticated' } as any);\n return;\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie);\n\n if (!session || sessionManager.isExpired(session)) {\n res.status(401).json({ error: 'Session expired' } as any);\n return;\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for consistent wildcard-aware checking\n if (!config.rbacEngine.hasAnyRole(session.user, roles)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (config.rbacEngine) {\n // Use RBAC engine for wildcard-aware permission checking\n if (!config.rbacEngine.hasAllPermissions(session.user, permissions)) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n } else {\n // Fallback: direct check (no wildcard support)\n const hasAllPermissions = permissions.every((permission) =>\n session.user.permissions?.includes(permission)\n );\n if (!hasAllPermissions) {\n res.status(403).json({ error: 'Insufficient permissions' } as any);\n return;\n }\n }\n }\n\n // Call handler with session\n await handler(req, res, session);\n };\n}\n","import type { NextApiResponse } from 'next';\nimport { serializeCookie, clearCookie, type CookieOptions } from '@stackwright-pro/auth';\n\n/**\n * Set session cookie in Next.js API response\n */\nexport function setSessionCookie(\n res: NextApiResponse,\n sessionJwt: string,\n options: CookieOptions = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n const maxAge = options.maxAge || 900; // 15 minutes default\n\n const cookie = serializeCookie(cookieName, sessionJwt, {\n ...options,\n maxAge,\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n });\n\n res.setHeader('Set-Cookie', cookie);\n}\n\n/**\n * Clear session cookie in Next.js API response\n */\nexport function clearSessionCookie(\n res: NextApiResponse,\n options: Pick<CookieOptions, 'name' | 'domain' | 'path'> = {}\n): void {\n const cookieName = options.name || 'stackwright_session';\n\n const cookie = clearCookie(cookieName, options);\n\n res.setHeader('Set-Cookie', cookie);\n}\n","export { createAuthMiddleware, type MiddlewareConfig } from './middleware.js';\nexport { createAuthProxy, type ProxyConfig } from './proxy.js';\nexport { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\nexport {\n protectedRoute,\n type ProtectedRouteConfig,\n type AuthenticatedHandler,\n} from './api-helpers.js';\nexport { setSessionCookie, clearSessionCookie } from './cookie-utils.js';\n\n// Re-export commonly used types/classes from core\nexport type { AuthUser, AuthSession, AuthConfig } from '@stackwright-pro/auth';\n\n// Re-export RBAC engine\nexport { RBACEngine } from '@stackwright-pro/auth';\n\n// Re-export React context components for Next.js apps\nexport { AuthProvider, AuthContext, useAuth, useRequireAuth } from '@stackwright-pro/auth';\nexport type { AuthProviderProps, AuthContextValue } from '@stackwright-pro/auth';\n\n// App Router Route Handler helpers (replaces api-helpers for App Router users)\nexport {\n protectedRouteHandler,\n setSessionCookieOnResponse,\n clearSessionCookieOnResponse,\n type RouteHandlerConfig,\n type AuthenticatedRouteHandler,\n} from './route-handlers.js';\n","import { type NextRequest, NextResponse } from 'next/server';\nimport { SessionManager, RBACEngine, type AuthSession } from '@stackwright-pro/auth';\n\nexport interface RouteHandlerConfig {\n /**\n * Session manager for validating sessions\n */\n sessionManager: SessionManager;\n\n /**\n * Required roles (user must have ANY of these)\n */\n roles?: string[];\n\n /**\n * Required permissions (user must have ALL of these)\n */\n permissions?: string[];\n\n /**\n * Cookie name (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * Optional RBAC engine for wildcard-aware role/permission checking.\n * When provided, authorization decisions use RBACEngine (consistent\n * with middleware). Without it, falls back to direct array checks.\n */\n rbacEngine?: RBACEngine;\n}\n\n/**\n * Handler function with authenticated session — App Router Route Handler signature.\n */\nexport type AuthenticatedRouteHandler = (\n request: NextRequest,\n context: { params: Record<string, string> },\n session: AuthSession\n) => Promise<Response> | Response;\n\n/**\n * Wrap an App Router Route Handler with authentication/authorization.\n *\n * This is the App Router equivalent of `protectedRoute()` from `api-helpers.ts`.\n *\n * @example\n * ```typescript\n * // app/api/equipment/[id]/route.ts\n * import { protectedRouteHandler } from '@stackwright-pro/auth-nextjs';\n *\n * export const GET = protectedRouteHandler(\n * async (request, { params }, session) => {\n * const equipment = await getEquipment(params.id);\n * return NextResponse.json(equipment);\n * },\n * {\n * sessionManager,\n * roles: ['ANALYST', 'ADMIN'],\n * }\n * );\n * ```\n */\nexport function protectedRouteHandler(\n handler: AuthenticatedRouteHandler,\n config: RouteHandlerConfig\n): (request: NextRequest, context: { params: Record<string, string> }) => Promise<Response> {\n const {\n sessionManager,\n roles,\n permissions,\n cookieName = 'stackwright_session',\n rbacEngine,\n } = config;\n\n return async (\n request: NextRequest,\n context: { params: Record<string, string> }\n ): Promise<Response> => {\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n\n if (!sessionCookie) {\n return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });\n }\n\n // Verify session\n const session = await sessionManager.deserialize(sessionCookie.value);\n\n if (!session || sessionManager.isExpired(session)) {\n return NextResponse.json({ error: 'Session expired' }, { status: 401 });\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAnyRole(session.user, roles)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasRole = roles.some((role) => session.user.roles.includes(role));\n if (!hasRole) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n if (rbacEngine) {\n if (!rbacEngine.hasAllPermissions(session.user, permissions)) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n } else {\n const hasAllPermissions = permissions.every((p) => session.user.permissions?.includes(p));\n if (!hasAllPermissions) {\n return NextResponse.json({ error: 'Insufficient permissions' }, { status: 403 });\n }\n }\n }\n\n return handler(request, context, session);\n };\n}\n\n/**\n * Set the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `setSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/login/route.ts\n * import { setSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST(request: NextRequest) {\n * const session = await createSession(request);\n * const jwt = await sessionManager.serialize(session);\n * const response = NextResponse.json({ ok: true });\n * return setSessionCookieOnResponse(response, jwt);\n * }\n * ```\n */\nexport function setSessionCookieOnResponse(\n response: NextResponse,\n sessionJwt: string,\n options: {\n cookieName?: string;\n maxAge?: number;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n const maxAge = options.maxAge ?? 900; // 15 minutes\n\n response.cookies.set(cookieName, sessionJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge,\n });\n\n return response;\n}\n\n/**\n * Clear the session cookie on a `NextResponse` (App Router).\n *\n * This is the App Router equivalent of `clearSessionCookie()` from `cookie-utils.ts`.\n *\n * @example\n * ```typescript\n * // app/api/auth/logout/route.ts\n * import { clearSessionCookieOnResponse } from '@stackwright-pro/auth-nextjs';\n *\n * export async function POST() {\n * const response = NextResponse.json({ ok: true });\n * return clearSessionCookieOnResponse(response);\n * }\n * ```\n */\nexport function clearSessionCookieOnResponse(\n response: NextResponse,\n options: {\n cookieName?: string;\n } = {}\n): NextResponse {\n const cookieName = options.cookieName ?? 'stackwright_session';\n response.cookies.delete(cookieName);\n return response;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as next_server_js from 'next/server.js';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { AuthConfig, SessionManager, RBACEngine } from '@stackwright-pro/auth';
|
|
4
|
+
|
|
5
|
+
interface AuthHandlerConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Auth configuration
|
|
8
|
+
*/
|
|
9
|
+
authConfig: AuthConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Session manager instance
|
|
12
|
+
*/
|
|
13
|
+
sessionManager: SessionManager;
|
|
14
|
+
/**
|
|
15
|
+
* RBAC engine instance
|
|
16
|
+
*/
|
|
17
|
+
rbacEngine: RBACEngine;
|
|
18
|
+
/**
|
|
19
|
+
* Cookie name for session (default: 'stackwright_session')
|
|
20
|
+
*/
|
|
21
|
+
cookieName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* URL to redirect to when authentication fails (default: '/login')
|
|
24
|
+
*/
|
|
25
|
+
loginUrl?: string;
|
|
26
|
+
/**
|
|
27
|
+
* URL to redirect to when authorization fails (default: '/unauthorized')
|
|
28
|
+
*/
|
|
29
|
+
unauthorizedUrl?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Core auth handler shared by both the middleware (Next.js <16) and
|
|
33
|
+
* proxy (Next.js >=16) conventions.
|
|
34
|
+
*
|
|
35
|
+
* @internal — consumers should use `createAuthMiddleware` or `createAuthProxy`.
|
|
36
|
+
*/
|
|
37
|
+
declare function createAuthHandler(config: AuthHandlerConfig): (request: NextRequest) => Promise<NextResponse | undefined>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Configuration for Next.js proxy-based auth (Next.js >=16).
|
|
41
|
+
*/
|
|
42
|
+
type ProxyConfig = AuthHandlerConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Create a Next.js proxy handler for authentication and authorization.
|
|
45
|
+
*
|
|
46
|
+
* For Next.js >=16 projects that use the `proxy.ts` file convention,
|
|
47
|
+
* replacing the deprecated `middleware.ts` convention.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // proxy.ts (Next.js >=16)
|
|
52
|
+
* import { createAuthProxy } from '@stackwright-pro/auth-nextjs';
|
|
53
|
+
*
|
|
54
|
+
* export default createAuthProxy({
|
|
55
|
+
* authConfig,
|
|
56
|
+
* sessionManager,
|
|
57
|
+
* rbacEngine,
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* export const config = {
|
|
61
|
+
* matcher: ['/((?!_next|api/auth).*)'],
|
|
62
|
+
* };
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function createAuthProxy(config: ProxyConfig): (request: next_server_js.NextRequest) => Promise<next_server_js.NextResponse | undefined>;
|
|
66
|
+
|
|
67
|
+
export { type AuthHandlerConfig as A, type ProxyConfig as P, createAuthProxy as a, createAuthHandler as c };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as next_server_js from 'next/server.js';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { AuthConfig, SessionManager, RBACEngine } from '@stackwright-pro/auth';
|
|
4
|
+
|
|
5
|
+
interface AuthHandlerConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Auth configuration
|
|
8
|
+
*/
|
|
9
|
+
authConfig: AuthConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Session manager instance
|
|
12
|
+
*/
|
|
13
|
+
sessionManager: SessionManager;
|
|
14
|
+
/**
|
|
15
|
+
* RBAC engine instance
|
|
16
|
+
*/
|
|
17
|
+
rbacEngine: RBACEngine;
|
|
18
|
+
/**
|
|
19
|
+
* Cookie name for session (default: 'stackwright_session')
|
|
20
|
+
*/
|
|
21
|
+
cookieName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* URL to redirect to when authentication fails (default: '/login')
|
|
24
|
+
*/
|
|
25
|
+
loginUrl?: string;
|
|
26
|
+
/**
|
|
27
|
+
* URL to redirect to when authorization fails (default: '/unauthorized')
|
|
28
|
+
*/
|
|
29
|
+
unauthorizedUrl?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Core auth handler shared by both the middleware (Next.js <16) and
|
|
33
|
+
* proxy (Next.js >=16) conventions.
|
|
34
|
+
*
|
|
35
|
+
* @internal — consumers should use `createAuthMiddleware` or `createAuthProxy`.
|
|
36
|
+
*/
|
|
37
|
+
declare function createAuthHandler(config: AuthHandlerConfig): (request: NextRequest) => Promise<NextResponse | undefined>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Configuration for Next.js proxy-based auth (Next.js >=16).
|
|
41
|
+
*/
|
|
42
|
+
type ProxyConfig = AuthHandlerConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Create a Next.js proxy handler for authentication and authorization.
|
|
45
|
+
*
|
|
46
|
+
* For Next.js >=16 projects that use the `proxy.ts` file convention,
|
|
47
|
+
* replacing the deprecated `middleware.ts` convention.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // proxy.ts (Next.js >=16)
|
|
52
|
+
* import { createAuthProxy } from '@stackwright-pro/auth-nextjs';
|
|
53
|
+
*
|
|
54
|
+
* export default createAuthProxy({
|
|
55
|
+
* authConfig,
|
|
56
|
+
* sessionManager,
|
|
57
|
+
* rbacEngine,
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* export const config = {
|
|
61
|
+
* matcher: ['/((?!_next|api/auth).*)'],
|
|
62
|
+
* };
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function createAuthProxy(config: ProxyConfig): (request: next_server_js.NextRequest) => Promise<next_server_js.NextResponse | undefined>;
|
|
66
|
+
|
|
67
|
+
export { type AuthHandlerConfig as A, type ProxyConfig as P, createAuthProxy as a, createAuthHandler as c };
|
package/dist/proxy.d.mts
ADDED
package/dist/proxy.d.ts
ADDED
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/proxy.ts
|
|
21
|
+
var proxy_exports = {};
|
|
22
|
+
__export(proxy_exports, {
|
|
23
|
+
createAuthProxy: () => createAuthProxy
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(proxy_exports);
|
|
26
|
+
|
|
27
|
+
// src/auth-handler.ts
|
|
28
|
+
var import_server = require("next/server");
|
|
29
|
+
function createAuthHandler(config) {
|
|
30
|
+
const {
|
|
31
|
+
sessionManager,
|
|
32
|
+
rbacEngine,
|
|
33
|
+
cookieName = "stackwright_session",
|
|
34
|
+
loginUrl = "/login",
|
|
35
|
+
unauthorizedUrl = "/unauthorized"
|
|
36
|
+
} = config;
|
|
37
|
+
return async function authHandler(request) {
|
|
38
|
+
const { pathname } = request.nextUrl;
|
|
39
|
+
if (rbacEngine.isPublicRoute(pathname)) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
const sessionCookie = request.cookies.get(cookieName);
|
|
43
|
+
let session = null;
|
|
44
|
+
if (sessionCookie) {
|
|
45
|
+
session = await sessionManager.deserialize(sessionCookie.value);
|
|
46
|
+
}
|
|
47
|
+
if (!session || sessionManager.isExpired(session)) {
|
|
48
|
+
const url = request.nextUrl.clone();
|
|
49
|
+
url.pathname = loginUrl;
|
|
50
|
+
url.searchParams.set("redirect", pathname);
|
|
51
|
+
return import_server.NextResponse.redirect(url);
|
|
52
|
+
}
|
|
53
|
+
if (!rbacEngine.canAccessRoute(session.user, pathname)) {
|
|
54
|
+
const url = request.nextUrl.clone();
|
|
55
|
+
url.pathname = unauthorizedUrl;
|
|
56
|
+
return import_server.NextResponse.redirect(url);
|
|
57
|
+
}
|
|
58
|
+
if (sessionManager.shouldRefresh(session)) {
|
|
59
|
+
const refreshed = await sessionManager.refreshSession(session);
|
|
60
|
+
const newJwt = await sessionManager.serialize(refreshed);
|
|
61
|
+
const response = import_server.NextResponse.next();
|
|
62
|
+
response.cookies.set(cookieName, newJwt, {
|
|
63
|
+
httpOnly: true,
|
|
64
|
+
secure: true,
|
|
65
|
+
sameSite: "lax",
|
|
66
|
+
maxAge: 900
|
|
67
|
+
// 15 minutes
|
|
68
|
+
});
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
return void 0;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/proxy.ts
|
|
76
|
+
function createAuthProxy(config) {
|
|
77
|
+
return createAuthHandler(config);
|
|
78
|
+
}
|
|
79
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
80
|
+
0 && (module.exports = {
|
|
81
|
+
createAuthProxy
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/proxy.ts","../src/auth-handler.ts"],"sourcesContent":["import { createAuthHandler, type AuthHandlerConfig } from './auth-handler.js';\n\n/**\n * Configuration for Next.js proxy-based auth (Next.js >=16).\n */\nexport type ProxyConfig = AuthHandlerConfig;\n\n/**\n * Create a Next.js proxy handler for authentication and authorization.\n *\n * For Next.js >=16 projects that use the `proxy.ts` file convention,\n * replacing the deprecated `middleware.ts` convention.\n *\n * @example\n * ```typescript\n * // proxy.ts (Next.js >=16)\n * import { createAuthProxy } from '@stackwright-pro/auth-nextjs';\n *\n * export default createAuthProxy({\n * authConfig,\n * sessionManager,\n * rbacEngine,\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next|api/auth).*)'],\n * };\n * ```\n */\nexport function createAuthProxy(config: ProxyConfig) {\n return createAuthHandler(config);\n}\n","import { type NextRequest, NextResponse } from 'next/server';\nimport {\n SessionManager,\n RBACEngine,\n type AuthConfig,\n type AuthSession,\n} from '@stackwright-pro/auth';\n\nexport interface AuthHandlerConfig {\n /**\n * Auth configuration\n */\n authConfig: AuthConfig;\n\n /**\n * Session manager instance\n */\n sessionManager: SessionManager;\n\n /**\n * RBAC engine instance\n */\n rbacEngine: RBACEngine;\n\n /**\n * Cookie name for session (default: 'stackwright_session')\n */\n cookieName?: string;\n\n /**\n * URL to redirect to when authentication fails (default: '/login')\n */\n loginUrl?: string;\n\n /**\n * URL to redirect to when authorization fails (default: '/unauthorized')\n */\n unauthorizedUrl?: string;\n}\n\n/**\n * Core auth handler shared by both the middleware (Next.js <16) and\n * proxy (Next.js >=16) conventions.\n *\n * @internal — consumers should use `createAuthMiddleware` or `createAuthProxy`.\n */\nexport function createAuthHandler(config: AuthHandlerConfig) {\n const {\n sessionManager,\n rbacEngine,\n cookieName = 'stackwright_session',\n loginUrl = '/login',\n unauthorizedUrl = '/unauthorized',\n } = config;\n\n return async function authHandler(request: NextRequest): Promise<NextResponse | undefined> {\n const { pathname } = request.nextUrl;\n\n // Check if route is public\n if (rbacEngine.isPublicRoute(pathname)) {\n return undefined; // Continue to next handler\n }\n\n // Extract session from cookie\n const sessionCookie = request.cookies.get(cookieName);\n let session: AuthSession | null = null;\n\n if (sessionCookie) {\n session = await sessionManager.deserialize(sessionCookie.value);\n }\n\n // Check if session is valid\n if (!session || sessionManager.isExpired(session)) {\n // Redirect to login\n const url = request.nextUrl.clone();\n url.pathname = loginUrl;\n url.searchParams.set('redirect', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if user can access route\n if (!rbacEngine.canAccessRoute(session.user, pathname)) {\n // Redirect to unauthorized\n const url = request.nextUrl.clone();\n url.pathname = unauthorizedUrl;\n return NextResponse.redirect(url);\n }\n\n // Refresh session if needed\n if (sessionManager.shouldRefresh(session)) {\n const refreshed = await sessionManager.refreshSession(session);\n const newJwt = await sessionManager.serialize(refreshed);\n\n const response = NextResponse.next();\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n maxAge: 900, // 15 minutes\n });\n\n return response;\n }\n\n // Allow request to continue\n return undefined;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA+C;AA8CxC,SAAS,kBAAkB,QAA2B;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX,kBAAkB;AAAA,EACpB,IAAI;AAEJ,SAAO,eAAe,YAAY,SAAyD;AACzF,UAAM,EAAE,SAAS,IAAI,QAAQ;AAG7B,QAAI,WAAW,cAAc,QAAQ,GAAG;AACtC,aAAO;AAAA,IACT;AAGA,UAAM,gBAAgB,QAAQ,QAAQ,IAAI,UAAU;AACpD,QAAI,UAA8B;AAElC,QAAI,eAAe;AACjB,gBAAU,MAAM,eAAe,YAAY,cAAc,KAAK;AAAA,IAChE;AAGA,QAAI,CAAC,WAAW,eAAe,UAAU,OAAO,GAAG;AAEjD,YAAM,MAAM,QAAQ,QAAQ,MAAM;AAClC,UAAI,WAAW;AACf,UAAI,aAAa,IAAI,YAAY,QAAQ;AACzC,aAAO,2BAAa,SAAS,GAAG;AAAA,IAClC;AAGA,QAAI,CAAC,WAAW,eAAe,QAAQ,MAAM,QAAQ,GAAG;AAEtD,YAAM,MAAM,QAAQ,QAAQ,MAAM;AAClC,UAAI,WAAW;AACf,aAAO,2BAAa,SAAS,GAAG;AAAA,IAClC;AAGA,QAAI,eAAe,cAAc,OAAO,GAAG;AACzC,YAAM,YAAY,MAAM,eAAe,eAAe,OAAO;AAC7D,YAAM,SAAS,MAAM,eAAe,UAAU,SAAS;AAEvD,YAAM,WAAW,2BAAa,KAAK;AACnC,eAAS,QAAQ,IAAI,YAAY,QAAQ;AAAA,QACvC,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,QAAQ;AAAA;AAAA,MACV,CAAC;AAED,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;;;AD9EO,SAAS,gBAAgB,QAAqB;AACnD,SAAO,kBAAkB,MAAM;AACjC;","names":[]}
|
package/dist/proxy.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackwright-pro/auth-nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-alpha.0",
|
|
4
4
|
"description": "Next.js adapter for Stackwright Pro authentication",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,19 +11,25 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"import": "./dist/index.mjs",
|
|
13
13
|
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./proxy": {
|
|
16
|
+
"types": "./dist/proxy.d.ts",
|
|
17
|
+
"import": "./dist/proxy.mjs",
|
|
18
|
+
"require": "./dist/proxy.js"
|
|
14
19
|
}
|
|
15
20
|
},
|
|
16
21
|
"files": [
|
|
17
22
|
"dist"
|
|
18
23
|
],
|
|
19
24
|
"dependencies": {
|
|
20
|
-
"@stackwright-pro/auth": "0.2.0-alpha.
|
|
25
|
+
"@stackwright-pro/auth": "0.2.0-alpha.11"
|
|
21
26
|
},
|
|
22
27
|
"devDependencies": {
|
|
23
|
-
"@types/node": "^25.
|
|
28
|
+
"@types/node": "^25.9.2",
|
|
29
|
+
"reflect-metadata": "^0.2.2",
|
|
24
30
|
"tsup": "^8.5.1",
|
|
25
31
|
"typescript": "^6.0.3",
|
|
26
|
-
"vitest": "^4.
|
|
32
|
+
"vitest": "^4.1.8"
|
|
27
33
|
},
|
|
28
34
|
"peerDependencies": {
|
|
29
35
|
"next": ">=14.0.0 <16.0.0-beta.0 || >=16.2.3",
|