najm-auth 1.1.36 → 1.1.38
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/dist/client/edge.d.ts +47 -0
- package/dist/client/edge.js +88 -0
- package/dist/client/server/index.d.ts +3 -46
- package/package.json +15 -10
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as next_server from 'next/server';
|
|
2
|
+
|
|
3
|
+
interface AuthMiddlewareConfig {
|
|
4
|
+
/** Routes that require authentication (glob patterns) */
|
|
5
|
+
protectedRoutes?: string[];
|
|
6
|
+
/** Always-public routes (glob patterns) */
|
|
7
|
+
publicRoutes?: string[];
|
|
8
|
+
/** Route to redirect unauthenticated users to */
|
|
9
|
+
loginRoute?: string;
|
|
10
|
+
/** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
|
|
11
|
+
roleRoutes?: Record<string, string[]>;
|
|
12
|
+
/** Refresh token cookie name (default: 'refreshToken') */
|
|
13
|
+
cookieName?: string;
|
|
14
|
+
/** Session cookie name to clear on redirect (default: 'najm.session') */
|
|
15
|
+
sessionCookieName?: string;
|
|
16
|
+
/** URL of the verify endpoint (default: derived from request) */
|
|
17
|
+
verifyURL?: string;
|
|
18
|
+
/**
|
|
19
|
+
* When true, call the verify endpoint on EVERY protected route (not just
|
|
20
|
+
* roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
|
|
21
|
+
* fetch per navigation — trade latency for stronger guarantees.
|
|
22
|
+
*/
|
|
23
|
+
verifyAlways?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a Next.js middleware function that protects routes based on auth state.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // middleware.ts
|
|
31
|
+
* import { withAuthMiddleware } from 'najm-auth/client/server';
|
|
32
|
+
*
|
|
33
|
+
* export default withAuthMiddleware({
|
|
34
|
+
* protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
|
|
35
|
+
* publicRoutes: ['/', '/about', '/login', '/register'],
|
|
36
|
+
* loginRoute: '/login',
|
|
37
|
+
* roleRoutes: { '/admin/:path*': ['admin'] },
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* export const config = {
|
|
41
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
42
|
+
* };
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
|
|
46
|
+
|
|
47
|
+
export { type AuthMiddlewareConfig, withAuthMiddleware };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/client/server/withAuthMiddleware.ts
|
|
5
|
+
function withAuthMiddleware(config) {
|
|
6
|
+
const {
|
|
7
|
+
protectedRoutes = [],
|
|
8
|
+
publicRoutes = [],
|
|
9
|
+
loginRoute = "/login",
|
|
10
|
+
roleRoutes = {},
|
|
11
|
+
cookieName = "refreshToken",
|
|
12
|
+
sessionCookieName = "najm.session",
|
|
13
|
+
verifyAlways = false
|
|
14
|
+
} = config;
|
|
15
|
+
return /* @__PURE__ */ __name(async function middleware(request) {
|
|
16
|
+
const { NextResponse } = await import("next/server");
|
|
17
|
+
const redirectToLogin = /* @__PURE__ */ __name((pathname2, clearCookies) => {
|
|
18
|
+
const loginUrl = new URL(loginRoute, request.url);
|
|
19
|
+
loginUrl.searchParams.set("from", pathname2);
|
|
20
|
+
const res = NextResponse.redirect(loginUrl);
|
|
21
|
+
if (clearCookies) {
|
|
22
|
+
res.cookies.delete(cookieName);
|
|
23
|
+
res.cookies.delete(sessionCookieName);
|
|
24
|
+
}
|
|
25
|
+
return res;
|
|
26
|
+
}, "redirectToLogin");
|
|
27
|
+
const url = new URL(request.url);
|
|
28
|
+
const pathname = url.pathname;
|
|
29
|
+
if (matchesAny(pathname, publicRoutes)) {
|
|
30
|
+
return NextResponse.next();
|
|
31
|
+
}
|
|
32
|
+
const isProtected = protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);
|
|
33
|
+
if (!isProtected) return NextResponse.next();
|
|
34
|
+
const cookie = request.headers.get("cookie") ?? "";
|
|
35
|
+
const hasToken = cookieRegex(cookieName).test(cookie);
|
|
36
|
+
if (!hasToken) {
|
|
37
|
+
return redirectToLogin(pathname, true);
|
|
38
|
+
}
|
|
39
|
+
const requiredRoles = findMatchingRoles(pathname, roleRoutes);
|
|
40
|
+
const needsVerify = verifyAlways || !!requiredRoles;
|
|
41
|
+
if (needsVerify) {
|
|
42
|
+
const verifyURL = config.verifyURL ?? `${url.origin}/api/auth/me`;
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch(verifyURL, {
|
|
45
|
+
headers: { "Cookie": cookie, "Accept": "application/json" }
|
|
46
|
+
});
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
return redirectToLogin(pathname, true);
|
|
49
|
+
}
|
|
50
|
+
if (requiredRoles) {
|
|
51
|
+
const body = await res.json();
|
|
52
|
+
const userRole = body?.data?.role;
|
|
53
|
+
if (!userRole || !requiredRoles.includes(userRole)) {
|
|
54
|
+
return new NextResponse(null, { status: 403 });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
return redirectToLogin(pathname, true);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return NextResponse.next();
|
|
62
|
+
}, "middleware");
|
|
63
|
+
}
|
|
64
|
+
__name(withAuthMiddleware, "withAuthMiddleware");
|
|
65
|
+
function matchesAny(pathname, patterns) {
|
|
66
|
+
return patterns.some((p) => matchPattern(pathname, p));
|
|
67
|
+
}
|
|
68
|
+
__name(matchesAny, "matchesAny");
|
|
69
|
+
function matchPattern(pathname, pattern) {
|
|
70
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
71
|
+
const regex = escaped.replace(/\/:[^/]+\*/g, "(?:/.*)?").replace(/\/\\\*$/g, "(?:/.*)?").replace(/\\\*/g, "(?:/.*)?").replace(/\//g, "\\/");
|
|
72
|
+
return new RegExp(`^${regex}$`).test(pathname);
|
|
73
|
+
}
|
|
74
|
+
__name(matchPattern, "matchPattern");
|
|
75
|
+
function cookieRegex(name) {
|
|
76
|
+
return new RegExp(`(?:^|;\\s*)${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=[^;]`);
|
|
77
|
+
}
|
|
78
|
+
__name(cookieRegex, "cookieRegex");
|
|
79
|
+
function findMatchingRoles(pathname, roleRoutes) {
|
|
80
|
+
for (const [pattern, roles] of Object.entries(roleRoutes)) {
|
|
81
|
+
if (matchPattern(pathname, pattern)) return roles;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
__name(findMatchingRoles, "findMatchingRoles");
|
|
86
|
+
export {
|
|
87
|
+
withAuthMiddleware
|
|
88
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { e as AuthUser, F as FetchClient, R as RetryConfig, N as NajmAuthClient } from '../../NajmAuthClient-D08--i69.js';
|
|
2
|
-
|
|
2
|
+
export { withAuthMiddleware } from '../edge.js';
|
|
3
|
+
import 'next/server';
|
|
3
4
|
|
|
4
5
|
interface GetServerSessionOptions {
|
|
5
6
|
/** The URL of the /auth/me endpoint */
|
|
@@ -63,50 +64,6 @@ interface ServerClientConfig {
|
|
|
63
64
|
*/
|
|
64
65
|
declare function createServerClient(config: ServerClientConfig): FetchClient;
|
|
65
66
|
|
|
66
|
-
interface AuthMiddlewareConfig {
|
|
67
|
-
/** Routes that require authentication (glob patterns) */
|
|
68
|
-
protectedRoutes?: string[];
|
|
69
|
-
/** Always-public routes (glob patterns) */
|
|
70
|
-
publicRoutes?: string[];
|
|
71
|
-
/** Route to redirect unauthenticated users to */
|
|
72
|
-
loginRoute?: string;
|
|
73
|
-
/** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
|
|
74
|
-
roleRoutes?: Record<string, string[]>;
|
|
75
|
-
/** Refresh token cookie name (default: 'refreshToken') */
|
|
76
|
-
cookieName?: string;
|
|
77
|
-
/** Session cookie name to clear on redirect (default: 'najm.session') */
|
|
78
|
-
sessionCookieName?: string;
|
|
79
|
-
/** URL of the verify endpoint (default: derived from request) */
|
|
80
|
-
verifyURL?: string;
|
|
81
|
-
/**
|
|
82
|
-
* When true, call the verify endpoint on EVERY protected route (not just
|
|
83
|
-
* roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
|
|
84
|
-
* fetch per navigation — trade latency for stronger guarantees.
|
|
85
|
-
*/
|
|
86
|
-
verifyAlways?: boolean;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Create a Next.js middleware function that protects routes based on auth state.
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* ```ts
|
|
93
|
-
* // middleware.ts
|
|
94
|
-
* import { withAuthMiddleware } from 'najm-auth/client/server';
|
|
95
|
-
*
|
|
96
|
-
* export default withAuthMiddleware({
|
|
97
|
-
* protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
|
|
98
|
-
* publicRoutes: ['/', '/about', '/login', '/register'],
|
|
99
|
-
* loginRoute: '/login',
|
|
100
|
-
* roleRoutes: { '/admin/:path*': ['admin'] },
|
|
101
|
-
* });
|
|
102
|
-
*
|
|
103
|
-
* export const config = {
|
|
104
|
-
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
105
|
-
* };
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
|
|
109
|
-
|
|
110
67
|
interface ServerSession {
|
|
111
68
|
user: AuthUser;
|
|
112
69
|
roles?: string[];
|
|
@@ -279,4 +236,4 @@ interface AuthKit {
|
|
|
279
236
|
}
|
|
280
237
|
declare function defineAuth(authConfig?: DefineAuthConfig): AuthKit;
|
|
281
238
|
|
|
282
|
-
export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth
|
|
239
|
+
export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "najm-auth",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.38",
|
|
4
4
|
"description": "Authentication and authorization library for najm framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"import": "./dist/client/index.js",
|
|
20
20
|
"default": "./dist/client/index.js"
|
|
21
21
|
},
|
|
22
|
+
"./client/edge": {
|
|
23
|
+
"types": "./dist/client/edge.d.ts",
|
|
24
|
+
"import": "./dist/client/edge.js",
|
|
25
|
+
"default": "./dist/client/edge.js"
|
|
26
|
+
},
|
|
22
27
|
"./client/react": {
|
|
23
28
|
"types": "./dist/client/react/index.d.ts",
|
|
24
29
|
"import": "./dist/client/react/index.js",
|
|
@@ -73,15 +78,15 @@
|
|
|
73
78
|
},
|
|
74
79
|
"dependencies": {
|
|
75
80
|
"bcryptjs": "^3.0.2",
|
|
76
|
-
"najm-cookies": "^1.1.
|
|
77
|
-
"najm-core": "^1.2.
|
|
78
|
-
"najm-database": "^1.1.
|
|
79
|
-
"najm-guard": "^1.1.
|
|
80
|
-
"najm-i18n": "^1.1.
|
|
81
|
-
"najm-cache": "^1.2.
|
|
82
|
-
"najm-email": "^1.1.
|
|
83
|
-
"najm-rate": "^1.1.
|
|
84
|
-
"najm-validation": "^1.1.
|
|
81
|
+
"najm-cookies": "^1.1.12",
|
|
82
|
+
"najm-core": "^1.2.10",
|
|
83
|
+
"najm-database": "^1.1.14",
|
|
84
|
+
"najm-guard": "^1.1.12",
|
|
85
|
+
"najm-i18n": "^1.1.12",
|
|
86
|
+
"najm-cache": "^1.2.9",
|
|
87
|
+
"najm-email": "^1.1.12",
|
|
88
|
+
"najm-rate": "^1.1.12",
|
|
89
|
+
"najm-validation": "^1.1.13",
|
|
85
90
|
"hono": "^4.0.0",
|
|
86
91
|
"jsonwebtoken": "^9.0.3",
|
|
87
92
|
"lodash.isempty": "^4.4.0",
|