@inai-dev/nextjs 1.2.0 → 1.4.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 +7 -0
- package/dist/middleware.cjs +42 -10
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +2 -0
- package/dist/middleware.d.ts +2 -0
- package/dist/middleware.js +44 -11
- package/dist/middleware.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -26,11 +26,14 @@ import { inaiAuthMiddleware } from "@inai-dev/nextjs/middleware";
|
|
|
26
26
|
export default inaiAuthMiddleware({
|
|
27
27
|
publicRoutes: ["/", "/about", "/login"],
|
|
28
28
|
signInUrl: "/login",
|
|
29
|
+
// jwksUrl: "https://apiauth.inai.dev/.well-known/jwks.json", // optional override
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
export const config = { matcher: ["/((?!_next|static|favicon.ico).*)"] };
|
|
32
33
|
```
|
|
33
34
|
|
|
35
|
+
> All tokens are cryptographically verified using ES256 (ECDSA P-256). Public keys are fetched from the JWKS endpoint and cached for 5 minutes.
|
|
36
|
+
|
|
34
37
|
### 2. Provider
|
|
35
38
|
|
|
36
39
|
```tsx
|
|
@@ -391,6 +394,10 @@ import type {
|
|
|
391
394
|
} from "@inai-dev/nextjs/middleware";
|
|
392
395
|
```
|
|
393
396
|
|
|
397
|
+
## Questions & Support
|
|
398
|
+
|
|
399
|
+
Visit [https://inai.dev](https://inai.dev) for documentation, guides, and support.
|
|
400
|
+
|
|
394
401
|
## License
|
|
395
402
|
|
|
396
403
|
[MIT](../../LICENSE)
|
package/dist/middleware.cjs
CHANGED
|
@@ -27,6 +27,17 @@ __export(middleware_exports, {
|
|
|
27
27
|
module.exports = __toCommonJS(middleware_exports);
|
|
28
28
|
var import_server = require("next/server");
|
|
29
29
|
var import_shared = require("@inai-dev/shared");
|
|
30
|
+
var import_shared2 = require("@inai-dev/shared");
|
|
31
|
+
var sharedJwksClient = null;
|
|
32
|
+
var sharedJwksUrl = null;
|
|
33
|
+
function getJwksClient(config) {
|
|
34
|
+
const jwksUrl = config.jwksUrl ?? `${config.apiUrl ?? import_shared.DEFAULT_API_URL}/.well-known/jwks.json`;
|
|
35
|
+
if (!sharedJwksClient || sharedJwksUrl !== jwksUrl) {
|
|
36
|
+
sharedJwksClient = new import_shared.JWKSClient(jwksUrl);
|
|
37
|
+
sharedJwksUrl = jwksUrl;
|
|
38
|
+
}
|
|
39
|
+
return sharedJwksClient;
|
|
40
|
+
}
|
|
30
41
|
function createRouteMatcher(patterns) {
|
|
31
42
|
const matchers = patterns.map((pattern) => {
|
|
32
43
|
if (pattern instanceof RegExp) return pattern;
|
|
@@ -55,7 +66,26 @@ function isPublicRoute(req, publicRoutes, builtinPublic) {
|
|
|
55
66
|
if (typeof publicRoutes === "function") return publicRoutes(req);
|
|
56
67
|
return matchesRoute(pathname, publicRoutes);
|
|
57
68
|
}
|
|
58
|
-
function buildAuthObject(token,
|
|
69
|
+
async function buildAuthObject(token, jwksClient) {
|
|
70
|
+
const header = (0, import_shared.decodeJWTHeader)(token);
|
|
71
|
+
if (!header?.kid) return null;
|
|
72
|
+
let publicKey;
|
|
73
|
+
try {
|
|
74
|
+
publicKey = await jwksClient.getKey(header.kid);
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
let claims = await (0, import_shared.verifyES256)(token, publicKey);
|
|
79
|
+
if (!claims) {
|
|
80
|
+
jwksClient.invalidate();
|
|
81
|
+
try {
|
|
82
|
+
publicKey = await jwksClient.getKey(header.kid);
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
claims = await (0, import_shared.verifyES256)(token, publicKey);
|
|
87
|
+
if (!claims) return null;
|
|
88
|
+
}
|
|
59
89
|
const roles = claims.roles ?? [];
|
|
60
90
|
const permissions = claims.permissions ?? [];
|
|
61
91
|
return {
|
|
@@ -75,10 +105,10 @@ function buildAuthObject(token, claims) {
|
|
|
75
105
|
}
|
|
76
106
|
};
|
|
77
107
|
}
|
|
78
|
-
async function runAuthCheck(req, signInUrl, apiUrl) {
|
|
108
|
+
async function runAuthCheck(req, signInUrl, jwksClient, apiUrl) {
|
|
79
109
|
const { pathname } = req.nextUrl;
|
|
80
110
|
const token = req.cookies.get(import_shared.COOKIE_AUTH_TOKEN)?.value;
|
|
81
|
-
if (!token || (0,
|
|
111
|
+
if (!token || (0, import_shared2.isTokenExpired)(token)) {
|
|
82
112
|
const refreshToken = req.cookies.get(import_shared.COOKIE_REFRESH_TOKEN)?.value;
|
|
83
113
|
if (refreshToken) {
|
|
84
114
|
try {
|
|
@@ -160,14 +190,14 @@ async function runAuthCheck(req, signInUrl, apiUrl) {
|
|
|
160
190
|
response.cookies.set(import_shared.COOKIE_AUTH_SESSION, "", { path: "/", maxAge: 0 });
|
|
161
191
|
return { authObj: null, response };
|
|
162
192
|
}
|
|
163
|
-
const
|
|
164
|
-
if (!
|
|
193
|
+
const authObj = await buildAuthObject(token, jwksClient);
|
|
194
|
+
if (!authObj) {
|
|
165
195
|
return {
|
|
166
196
|
authObj: null,
|
|
167
197
|
response: import_server.NextResponse.redirect(new URL(signInUrl, req.url))
|
|
168
198
|
};
|
|
169
199
|
}
|
|
170
|
-
return { authObj
|
|
200
|
+
return { authObj };
|
|
171
201
|
}
|
|
172
202
|
function inaiAuthMiddleware(config = {}) {
|
|
173
203
|
const {
|
|
@@ -178,6 +208,7 @@ function inaiAuthMiddleware(config = {}) {
|
|
|
178
208
|
afterAuth
|
|
179
209
|
} = config;
|
|
180
210
|
const builtinPublic = ["/_next/*", "/favicon.ico", "/api/*", signInUrl];
|
|
211
|
+
const jwksClient = getJwksClient(config);
|
|
181
212
|
return async function middleware(req) {
|
|
182
213
|
if (beforeAuth) {
|
|
183
214
|
const result = beforeAuth(req);
|
|
@@ -186,8 +217,8 @@ function inaiAuthMiddleware(config = {}) {
|
|
|
186
217
|
if (isPublicRoute(req, publicRoutes, builtinPublic)) {
|
|
187
218
|
return import_server.NextResponse.next();
|
|
188
219
|
}
|
|
189
|
-
const apiUrl = authMode === "platform" ? import_shared.DEFAULT_API_URL : void 0;
|
|
190
|
-
const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);
|
|
220
|
+
const apiUrl = authMode === "platform" ? config.apiUrl ?? import_shared.DEFAULT_API_URL : void 0;
|
|
221
|
+
const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);
|
|
191
222
|
if (response) return response;
|
|
192
223
|
if (!authObj)
|
|
193
224
|
return import_server.NextResponse.redirect(new URL(signInUrl, req.url));
|
|
@@ -207,6 +238,7 @@ function withInAIAuth(wrappedMiddleware, config = {}) {
|
|
|
207
238
|
afterAuth
|
|
208
239
|
} = config;
|
|
209
240
|
const builtinPublic = ["/_next/*", "/favicon.ico", "/api/*", signInUrl];
|
|
241
|
+
const jwksClient = getJwksClient(config);
|
|
210
242
|
return async function middleware(req) {
|
|
211
243
|
if (beforeAuth) {
|
|
212
244
|
const result = beforeAuth(req);
|
|
@@ -214,8 +246,8 @@ function withInAIAuth(wrappedMiddleware, config = {}) {
|
|
|
214
246
|
}
|
|
215
247
|
const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);
|
|
216
248
|
if (!isPublic) {
|
|
217
|
-
const apiUrl = authMode === "platform" ? import_shared.DEFAULT_API_URL : void 0;
|
|
218
|
-
const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);
|
|
249
|
+
const apiUrl = authMode === "platform" ? config.apiUrl ?? import_shared.DEFAULT_API_URL : void 0;
|
|
250
|
+
const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);
|
|
219
251
|
if (response) return response;
|
|
220
252
|
if (!authObj)
|
|
221
253
|
return import_server.NextResponse.redirect(new URL(signInUrl, req.url));
|
package/dist/middleware.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport type { NextRequest } from \"next/server\";\nimport type { AuthObject } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_AUTH_SESSION,\n COOKIE_REFRESH_TOKEN,\n DEFAULT_API_URL,\n getClaimsFromToken,\n isTokenExpired,\n} from \"@inai-dev/shared\";\n\nexport interface InAIMiddlewareConfig {\n authMode?: \"app\" | \"platform\";\n publicRoutes?: string[] | ((req: NextRequest) => boolean);\n signInUrl?: string;\n beforeAuth?: (req: NextRequest) => NextResponse | void;\n afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;\n}\n\nexport function createRouteMatcher(\n patterns: (string | RegExp)[],\n): (req: NextRequest) => boolean {\n const matchers = patterns.map((pattern) => {\n if (pattern instanceof RegExp) return pattern;\n let regexStr = pattern;\n if (regexStr.endsWith(\"*\") && !regexStr.includes(\"(\")) {\n regexStr = regexStr.slice(0, -1) + \".*\";\n }\n return new RegExp(`^${regexStr}$`);\n });\n\n return (req: NextRequest) => {\n const pathname = req.nextUrl.pathname;\n return matchers.some((m) => m.test(pathname));\n };\n}\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n req: NextRequest,\n publicRoutes: string[] | ((req: NextRequest) => boolean),\n builtinPublic: string[],\n): boolean {\n const pathname = req.nextUrl.pathname;\n if (matchesRoute(pathname, builtinPublic)) return true;\n if (typeof publicRoutes === \"function\") return publicRoutes(req);\n return matchesRoute(pathname, publicRoutes);\n}\n\nfunction buildAuthObject(\n token: string,\n claims: NonNullable<ReturnType<typeof getClaimsFromToken>>,\n): AuthObject {\n const roles = claims.roles ?? [];\n const permissions = claims.permissions ?? [];\n return {\n userId: claims.sub,\n tenantId: claims.tenant_id,\n appId: claims.app_id ?? null,\n envId: claims.env_id ?? null,\n orgId: claims.org_id ?? null,\n orgRole: claims.org_role ?? null,\n sessionId: null,\n getToken: async () => token,\n has: (params: { role?: string; permission?: string }) => {\n if (params.role && roles.includes(params.role)) return true;\n if (params.permission && permissions.includes(params.permission))\n return true;\n return false;\n },\n };\n}\n\nasync function runAuthCheck(\n req: NextRequest,\n signInUrl: string,\n apiUrl?: string,\n): Promise<{ authObj: AuthObject | null; response?: NextResponse }> {\n const { pathname } = req.nextUrl;\n const token = req.cookies.get(COOKIE_AUTH_TOKEN)?.value;\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = req.cookies.get(COOKIE_REFRESH_TOKEN)?.value;\n if (refreshToken) {\n try {\n if (apiUrl) {\n const refreshRes = await fetch(`${apiUrl}/api/platform/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n if (refreshRes.ok) {\n const newTokens = await refreshRes.json() as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n const meRes = await fetch(`${apiUrl}/api/platform/auth/me`, {\n headers: { Authorization: `Bearer ${newTokens.access_token}` },\n });\n if (meRes.ok) {\n const meData = await meRes.json();\n const newUser = meData.data ?? meData;\n const isProduction = process.env.NODE_ENV === \"production\";\n const response = NextResponse.next();\n response.cookies.set(COOKIE_AUTH_TOKEN, newTokens.access_token, {\n httpOnly: true, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n response.cookies.set(COOKIE_REFRESH_TOKEN, newTokens.refresh_token, {\n httpOnly: true, secure: isProduction, sameSite: \"strict\",\n path: \"/api/auth\", maxAge: 7 * 24 * 60 * 60,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, JSON.stringify({\n user: newUser,\n expiresAt: new Date(Date.now() + newTokens.expires_in * 1000).toISOString(),\n }), {\n httpOnly: false, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n return { authObj: null, response };\n }\n }\n } else {\n const refreshUrl = new URL(\"/api/auth/refresh\", req.url);\n const refreshRes = await fetch(refreshUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Cookie: req.headers.get(\"cookie\") ?? \"\",\n },\n });\n if (refreshRes.ok) {\n const response = NextResponse.next();\n const setCookies = refreshRes.headers.getSetCookie?.() ?? [];\n for (const cookie of setCookies) {\n response.headers.append(\"Set-Cookie\", cookie);\n }\n return { authObj: null, response };\n }\n }\n } catch {\n // Refresh failed, fall through to redirect\n }\n }\n\n const response = NextResponse.redirect(\n new URL(\n `${signInUrl}?returnTo=${encodeURIComponent(pathname)}`,\n req.url,\n ),\n );\n response.cookies.set(COOKIE_AUTH_TOKEN, \"\", { path: \"/\", maxAge: 0 });\n response.cookies.set(COOKIE_REFRESH_TOKEN, \"\", {\n path: \"/api/auth\",\n maxAge: 0,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, \"\", { path: \"/\", maxAge: 0 });\n return { authObj: null, response };\n }\n\n const claims = getClaimsFromToken(token);\n if (!claims) {\n return {\n authObj: null,\n response: NextResponse.redirect(new URL(signInUrl, req.url)),\n };\n }\n\n return { authObj: buildAuthObject(token, claims) };\n}\n\nexport function inaiAuthMiddleware(config: InAIMiddlewareConfig = {}) {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n if (isPublicRoute(req, publicRoutes, builtinPublic)) {\n return NextResponse.next();\n }\n\n const apiUrl = authMode === \"platform\" ? DEFAULT_API_URL : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n return NextResponse.next();\n };\n}\n\nexport function withInAIAuth(\n wrappedMiddleware: (\n req: NextRequest,\n ) => NextResponse | Response | Promise<NextResponse | Response>,\n config: InAIMiddlewareConfig = {},\n): (req: NextRequest) => Promise<NextResponse> {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);\n\n if (!isPublic) {\n const apiUrl = authMode === \"platform\" ? DEFAULT_API_URL : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n const authHeader = JSON.stringify({\n userId: authObj.userId,\n tenantId: authObj.tenantId,\n appId: authObj.appId,\n envId: authObj.envId,\n orgId: authObj.orgId,\n orgRole: authObj.orgRole,\n });\n req.headers.set(\"x-inai-auth\", authHeader);\n }\n\n const wrappedResponse = await wrappedMiddleware(req);\n if (wrappedResponse instanceof NextResponse) return wrappedResponse;\n return new NextResponse(wrappedResponse.body, wrappedResponse);\n };\n}\n"],"mappings":"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","names":["response"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport type { NextRequest } from \"next/server\";\nimport type { AuthObject } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_AUTH_SESSION,\n COOKIE_REFRESH_TOKEN,\n DEFAULT_API_URL,\n decodeJWTHeader,\n verifyES256,\n JWKSClient,\n} from \"@inai-dev/shared\";\nimport { isTokenExpired } from \"@inai-dev/shared\";\n\nexport interface InAIMiddlewareConfig {\n authMode?: \"app\" | \"platform\";\n publicRoutes?: string[] | ((req: NextRequest) => boolean);\n signInUrl?: string;\n beforeAuth?: (req: NextRequest) => NextResponse | void;\n afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;\n jwksUrl?: string;\n apiUrl?: string;\n}\n\n// Module-level JWKS client (shared across requests in the same worker/process)\nlet sharedJwksClient: JWKSClient | null = null;\nlet sharedJwksUrl: string | null = null;\n\nfunction getJwksClient(config: InAIMiddlewareConfig): JWKSClient {\n const jwksUrl = config.jwksUrl\n ?? `${config.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n\n if (!sharedJwksClient || sharedJwksUrl !== jwksUrl) {\n sharedJwksClient = new JWKSClient(jwksUrl);\n sharedJwksUrl = jwksUrl;\n }\n return sharedJwksClient;\n}\n\nexport function createRouteMatcher(\n patterns: (string | RegExp)[],\n): (req: NextRequest) => boolean {\n const matchers = patterns.map((pattern) => {\n if (pattern instanceof RegExp) return pattern;\n let regexStr = pattern;\n if (regexStr.endsWith(\"*\") && !regexStr.includes(\"(\")) {\n regexStr = regexStr.slice(0, -1) + \".*\";\n }\n return new RegExp(`^${regexStr}$`);\n });\n\n return (req: NextRequest) => {\n const pathname = req.nextUrl.pathname;\n return matchers.some((m) => m.test(pathname));\n };\n}\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n req: NextRequest,\n publicRoutes: string[] | ((req: NextRequest) => boolean),\n builtinPublic: string[],\n): boolean {\n const pathname = req.nextUrl.pathname;\n if (matchesRoute(pathname, builtinPublic)) return true;\n if (typeof publicRoutes === \"function\") return publicRoutes(req);\n return matchesRoute(pathname, publicRoutes);\n}\n\nasync function buildAuthObject(\n token: string,\n jwksClient: JWKSClient,\n): Promise<AuthObject | null> {\n const header = decodeJWTHeader(token);\n if (!header?.kid) return null;\n\n let publicKey: CryptoKey;\n try {\n publicKey = await jwksClient.getKey(header.kid);\n } catch {\n return null;\n }\n\n let claims = await verifyES256(token, publicKey);\n if (!claims) {\n // Signature failed with cached key — refetch once in case of key rotation\n jwksClient.invalidate();\n try {\n publicKey = await jwksClient.getKey(header.kid);\n } catch {\n return null;\n }\n claims = await verifyES256(token, publicKey);\n if (!claims) return null;\n }\n\n const roles = claims.roles ?? [];\n const permissions = claims.permissions ?? [];\n return {\n userId: claims.sub,\n tenantId: claims.tenant_id,\n appId: claims.app_id ?? null,\n envId: claims.env_id ?? null,\n orgId: claims.org_id ?? null,\n orgRole: claims.org_role ?? null,\n sessionId: null,\n getToken: async () => token,\n has: (params: { role?: string; permission?: string }) => {\n if (params.role && roles.includes(params.role)) return true;\n if (params.permission && permissions.includes(params.permission))\n return true;\n return false;\n },\n };\n}\n\nasync function runAuthCheck(\n req: NextRequest,\n signInUrl: string,\n jwksClient: JWKSClient,\n apiUrl?: string,\n): Promise<{ authObj: AuthObject | null; response?: NextResponse }> {\n const { pathname } = req.nextUrl;\n const token = req.cookies.get(COOKIE_AUTH_TOKEN)?.value;\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = req.cookies.get(COOKIE_REFRESH_TOKEN)?.value;\n if (refreshToken) {\n try {\n if (apiUrl) {\n const refreshRes = await fetch(`${apiUrl}/api/platform/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n if (refreshRes.ok) {\n const newTokens = await refreshRes.json() as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n const meRes = await fetch(`${apiUrl}/api/platform/auth/me`, {\n headers: { Authorization: `Bearer ${newTokens.access_token}` },\n });\n if (meRes.ok) {\n const meData = await meRes.json();\n const newUser = meData.data ?? meData;\n const isProduction = process.env.NODE_ENV === \"production\";\n const response = NextResponse.next();\n response.cookies.set(COOKIE_AUTH_TOKEN, newTokens.access_token, {\n httpOnly: true, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n response.cookies.set(COOKIE_REFRESH_TOKEN, newTokens.refresh_token, {\n httpOnly: true, secure: isProduction, sameSite: \"strict\",\n path: \"/api/auth\", maxAge: 7 * 24 * 60 * 60,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, JSON.stringify({\n user: newUser,\n expiresAt: new Date(Date.now() + newTokens.expires_in * 1000).toISOString(),\n }), {\n httpOnly: false, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n return { authObj: null, response };\n }\n }\n } else {\n const refreshUrl = new URL(\"/api/auth/refresh\", req.url);\n const refreshRes = await fetch(refreshUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Cookie: req.headers.get(\"cookie\") ?? \"\",\n },\n });\n if (refreshRes.ok) {\n const response = NextResponse.next();\n const setCookies = refreshRes.headers.getSetCookie?.() ?? [];\n for (const cookie of setCookies) {\n response.headers.append(\"Set-Cookie\", cookie);\n }\n return { authObj: null, response };\n }\n }\n } catch {\n // Refresh failed, fall through to redirect\n }\n }\n\n const response = NextResponse.redirect(\n new URL(\n `${signInUrl}?returnTo=${encodeURIComponent(pathname)}`,\n req.url,\n ),\n );\n response.cookies.set(COOKIE_AUTH_TOKEN, \"\", { path: \"/\", maxAge: 0 });\n response.cookies.set(COOKIE_REFRESH_TOKEN, \"\", {\n path: \"/api/auth\",\n maxAge: 0,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, \"\", { path: \"/\", maxAge: 0 });\n return { authObj: null, response };\n }\n\n const authObj = await buildAuthObject(token, jwksClient);\n if (!authObj) {\n return {\n authObj: null,\n response: NextResponse.redirect(new URL(signInUrl, req.url)),\n };\n }\n\n return { authObj };\n}\n\nexport function inaiAuthMiddleware(config: InAIMiddlewareConfig = {}) {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n const jwksClient = getJwksClient(config);\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n if (isPublicRoute(req, publicRoutes, builtinPublic)) {\n return NextResponse.next();\n }\n\n const apiUrl = authMode === \"platform\" ? (config.apiUrl ?? DEFAULT_API_URL) : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n return NextResponse.next();\n };\n}\n\nexport function withInAIAuth(\n wrappedMiddleware: (\n req: NextRequest,\n ) => NextResponse | Response | Promise<NextResponse | Response>,\n config: InAIMiddlewareConfig = {},\n): (req: NextRequest) => Promise<NextResponse> {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n const jwksClient = getJwksClient(config);\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);\n\n if (!isPublic) {\n const apiUrl = authMode === \"platform\" ? (config.apiUrl ?? DEFAULT_API_URL) : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n const authHeader = JSON.stringify({\n userId: authObj.userId,\n tenantId: authObj.tenantId,\n appId: authObj.appId,\n envId: authObj.envId,\n orgId: authObj.orgId,\n orgRole: authObj.orgRole,\n });\n req.headers.set(\"x-inai-auth\", authHeader);\n }\n\n const wrappedResponse = await wrappedMiddleware(req);\n if (wrappedResponse instanceof NextResponse) return wrappedResponse;\n return new NextResponse(wrappedResponse.body, wrappedResponse);\n };\n}\n"],"mappings":"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","names":["import_shared","response"]}
|
package/dist/middleware.d.cts
CHANGED
|
@@ -7,6 +7,8 @@ interface InAIMiddlewareConfig {
|
|
|
7
7
|
signInUrl?: string;
|
|
8
8
|
beforeAuth?: (req: NextRequest) => NextResponse | void;
|
|
9
9
|
afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;
|
|
10
|
+
jwksUrl?: string;
|
|
11
|
+
apiUrl?: string;
|
|
10
12
|
}
|
|
11
13
|
declare function createRouteMatcher(patterns: (string | RegExp)[]): (req: NextRequest) => boolean;
|
|
12
14
|
declare function inaiAuthMiddleware(config?: InAIMiddlewareConfig): (req: NextRequest) => Promise<NextResponse>;
|
package/dist/middleware.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ interface InAIMiddlewareConfig {
|
|
|
7
7
|
signInUrl?: string;
|
|
8
8
|
beforeAuth?: (req: NextRequest) => NextResponse | void;
|
|
9
9
|
afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;
|
|
10
|
+
jwksUrl?: string;
|
|
11
|
+
apiUrl?: string;
|
|
10
12
|
}
|
|
11
13
|
declare function createRouteMatcher(patterns: (string | RegExp)[]): (req: NextRequest) => boolean;
|
|
12
14
|
declare function inaiAuthMiddleware(config?: InAIMiddlewareConfig): (req: NextRequest) => Promise<NextResponse>;
|
package/dist/middleware.js
CHANGED
|
@@ -5,9 +5,21 @@ import {
|
|
|
5
5
|
COOKIE_AUTH_SESSION,
|
|
6
6
|
COOKIE_REFRESH_TOKEN,
|
|
7
7
|
DEFAULT_API_URL,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
decodeJWTHeader,
|
|
9
|
+
verifyES256,
|
|
10
|
+
JWKSClient
|
|
10
11
|
} from "@inai-dev/shared";
|
|
12
|
+
import { isTokenExpired } from "@inai-dev/shared";
|
|
13
|
+
var sharedJwksClient = null;
|
|
14
|
+
var sharedJwksUrl = null;
|
|
15
|
+
function getJwksClient(config) {
|
|
16
|
+
const jwksUrl = config.jwksUrl ?? `${config.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;
|
|
17
|
+
if (!sharedJwksClient || sharedJwksUrl !== jwksUrl) {
|
|
18
|
+
sharedJwksClient = new JWKSClient(jwksUrl);
|
|
19
|
+
sharedJwksUrl = jwksUrl;
|
|
20
|
+
}
|
|
21
|
+
return sharedJwksClient;
|
|
22
|
+
}
|
|
11
23
|
function createRouteMatcher(patterns) {
|
|
12
24
|
const matchers = patterns.map((pattern) => {
|
|
13
25
|
if (pattern instanceof RegExp) return pattern;
|
|
@@ -36,7 +48,26 @@ function isPublicRoute(req, publicRoutes, builtinPublic) {
|
|
|
36
48
|
if (typeof publicRoutes === "function") return publicRoutes(req);
|
|
37
49
|
return matchesRoute(pathname, publicRoutes);
|
|
38
50
|
}
|
|
39
|
-
function buildAuthObject(token,
|
|
51
|
+
async function buildAuthObject(token, jwksClient) {
|
|
52
|
+
const header = decodeJWTHeader(token);
|
|
53
|
+
if (!header?.kid) return null;
|
|
54
|
+
let publicKey;
|
|
55
|
+
try {
|
|
56
|
+
publicKey = await jwksClient.getKey(header.kid);
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
let claims = await verifyES256(token, publicKey);
|
|
61
|
+
if (!claims) {
|
|
62
|
+
jwksClient.invalidate();
|
|
63
|
+
try {
|
|
64
|
+
publicKey = await jwksClient.getKey(header.kid);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
claims = await verifyES256(token, publicKey);
|
|
69
|
+
if (!claims) return null;
|
|
70
|
+
}
|
|
40
71
|
const roles = claims.roles ?? [];
|
|
41
72
|
const permissions = claims.permissions ?? [];
|
|
42
73
|
return {
|
|
@@ -56,7 +87,7 @@ function buildAuthObject(token, claims) {
|
|
|
56
87
|
}
|
|
57
88
|
};
|
|
58
89
|
}
|
|
59
|
-
async function runAuthCheck(req, signInUrl, apiUrl) {
|
|
90
|
+
async function runAuthCheck(req, signInUrl, jwksClient, apiUrl) {
|
|
60
91
|
const { pathname } = req.nextUrl;
|
|
61
92
|
const token = req.cookies.get(COOKIE_AUTH_TOKEN)?.value;
|
|
62
93
|
if (!token || isTokenExpired(token)) {
|
|
@@ -141,14 +172,14 @@ async function runAuthCheck(req, signInUrl, apiUrl) {
|
|
|
141
172
|
response.cookies.set(COOKIE_AUTH_SESSION, "", { path: "/", maxAge: 0 });
|
|
142
173
|
return { authObj: null, response };
|
|
143
174
|
}
|
|
144
|
-
const
|
|
145
|
-
if (!
|
|
175
|
+
const authObj = await buildAuthObject(token, jwksClient);
|
|
176
|
+
if (!authObj) {
|
|
146
177
|
return {
|
|
147
178
|
authObj: null,
|
|
148
179
|
response: NextResponse.redirect(new URL(signInUrl, req.url))
|
|
149
180
|
};
|
|
150
181
|
}
|
|
151
|
-
return { authObj
|
|
182
|
+
return { authObj };
|
|
152
183
|
}
|
|
153
184
|
function inaiAuthMiddleware(config = {}) {
|
|
154
185
|
const {
|
|
@@ -159,6 +190,7 @@ function inaiAuthMiddleware(config = {}) {
|
|
|
159
190
|
afterAuth
|
|
160
191
|
} = config;
|
|
161
192
|
const builtinPublic = ["/_next/*", "/favicon.ico", "/api/*", signInUrl];
|
|
193
|
+
const jwksClient = getJwksClient(config);
|
|
162
194
|
return async function middleware(req) {
|
|
163
195
|
if (beforeAuth) {
|
|
164
196
|
const result = beforeAuth(req);
|
|
@@ -167,8 +199,8 @@ function inaiAuthMiddleware(config = {}) {
|
|
|
167
199
|
if (isPublicRoute(req, publicRoutes, builtinPublic)) {
|
|
168
200
|
return NextResponse.next();
|
|
169
201
|
}
|
|
170
|
-
const apiUrl = authMode === "platform" ? DEFAULT_API_URL : void 0;
|
|
171
|
-
const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);
|
|
202
|
+
const apiUrl = authMode === "platform" ? config.apiUrl ?? DEFAULT_API_URL : void 0;
|
|
203
|
+
const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);
|
|
172
204
|
if (response) return response;
|
|
173
205
|
if (!authObj)
|
|
174
206
|
return NextResponse.redirect(new URL(signInUrl, req.url));
|
|
@@ -188,6 +220,7 @@ function withInAIAuth(wrappedMiddleware, config = {}) {
|
|
|
188
220
|
afterAuth
|
|
189
221
|
} = config;
|
|
190
222
|
const builtinPublic = ["/_next/*", "/favicon.ico", "/api/*", signInUrl];
|
|
223
|
+
const jwksClient = getJwksClient(config);
|
|
191
224
|
return async function middleware(req) {
|
|
192
225
|
if (beforeAuth) {
|
|
193
226
|
const result = beforeAuth(req);
|
|
@@ -195,8 +228,8 @@ function withInAIAuth(wrappedMiddleware, config = {}) {
|
|
|
195
228
|
}
|
|
196
229
|
const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);
|
|
197
230
|
if (!isPublic) {
|
|
198
|
-
const apiUrl = authMode === "platform" ? DEFAULT_API_URL : void 0;
|
|
199
|
-
const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);
|
|
231
|
+
const apiUrl = authMode === "platform" ? config.apiUrl ?? DEFAULT_API_URL : void 0;
|
|
232
|
+
const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);
|
|
200
233
|
if (response) return response;
|
|
201
234
|
if (!authObj)
|
|
202
235
|
return NextResponse.redirect(new URL(signInUrl, req.url));
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport type { NextRequest } from \"next/server\";\nimport type { AuthObject } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_AUTH_SESSION,\n COOKIE_REFRESH_TOKEN,\n DEFAULT_API_URL,\n getClaimsFromToken,\n isTokenExpired,\n} from \"@inai-dev/shared\";\n\nexport interface InAIMiddlewareConfig {\n authMode?: \"app\" | \"platform\";\n publicRoutes?: string[] | ((req: NextRequest) => boolean);\n signInUrl?: string;\n beforeAuth?: (req: NextRequest) => NextResponse | void;\n afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;\n}\n\nexport function createRouteMatcher(\n patterns: (string | RegExp)[],\n): (req: NextRequest) => boolean {\n const matchers = patterns.map((pattern) => {\n if (pattern instanceof RegExp) return pattern;\n let regexStr = pattern;\n if (regexStr.endsWith(\"*\") && !regexStr.includes(\"(\")) {\n regexStr = regexStr.slice(0, -1) + \".*\";\n }\n return new RegExp(`^${regexStr}$`);\n });\n\n return (req: NextRequest) => {\n const pathname = req.nextUrl.pathname;\n return matchers.some((m) => m.test(pathname));\n };\n}\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n req: NextRequest,\n publicRoutes: string[] | ((req: NextRequest) => boolean),\n builtinPublic: string[],\n): boolean {\n const pathname = req.nextUrl.pathname;\n if (matchesRoute(pathname, builtinPublic)) return true;\n if (typeof publicRoutes === \"function\") return publicRoutes(req);\n return matchesRoute(pathname, publicRoutes);\n}\n\nfunction buildAuthObject(\n token: string,\n claims: NonNullable<ReturnType<typeof getClaimsFromToken>>,\n): AuthObject {\n const roles = claims.roles ?? [];\n const permissions = claims.permissions ?? [];\n return {\n userId: claims.sub,\n tenantId: claims.tenant_id,\n appId: claims.app_id ?? null,\n envId: claims.env_id ?? null,\n orgId: claims.org_id ?? null,\n orgRole: claims.org_role ?? null,\n sessionId: null,\n getToken: async () => token,\n has: (params: { role?: string; permission?: string }) => {\n if (params.role && roles.includes(params.role)) return true;\n if (params.permission && permissions.includes(params.permission))\n return true;\n return false;\n },\n };\n}\n\nasync function runAuthCheck(\n req: NextRequest,\n signInUrl: string,\n apiUrl?: string,\n): Promise<{ authObj: AuthObject | null; response?: NextResponse }> {\n const { pathname } = req.nextUrl;\n const token = req.cookies.get(COOKIE_AUTH_TOKEN)?.value;\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = req.cookies.get(COOKIE_REFRESH_TOKEN)?.value;\n if (refreshToken) {\n try {\n if (apiUrl) {\n const refreshRes = await fetch(`${apiUrl}/api/platform/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n if (refreshRes.ok) {\n const newTokens = await refreshRes.json() as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n const meRes = await fetch(`${apiUrl}/api/platform/auth/me`, {\n headers: { Authorization: `Bearer ${newTokens.access_token}` },\n });\n if (meRes.ok) {\n const meData = await meRes.json();\n const newUser = meData.data ?? meData;\n const isProduction = process.env.NODE_ENV === \"production\";\n const response = NextResponse.next();\n response.cookies.set(COOKIE_AUTH_TOKEN, newTokens.access_token, {\n httpOnly: true, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n response.cookies.set(COOKIE_REFRESH_TOKEN, newTokens.refresh_token, {\n httpOnly: true, secure: isProduction, sameSite: \"strict\",\n path: \"/api/auth\", maxAge: 7 * 24 * 60 * 60,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, JSON.stringify({\n user: newUser,\n expiresAt: new Date(Date.now() + newTokens.expires_in * 1000).toISOString(),\n }), {\n httpOnly: false, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n return { authObj: null, response };\n }\n }\n } else {\n const refreshUrl = new URL(\"/api/auth/refresh\", req.url);\n const refreshRes = await fetch(refreshUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Cookie: req.headers.get(\"cookie\") ?? \"\",\n },\n });\n if (refreshRes.ok) {\n const response = NextResponse.next();\n const setCookies = refreshRes.headers.getSetCookie?.() ?? [];\n for (const cookie of setCookies) {\n response.headers.append(\"Set-Cookie\", cookie);\n }\n return { authObj: null, response };\n }\n }\n } catch {\n // Refresh failed, fall through to redirect\n }\n }\n\n const response = NextResponse.redirect(\n new URL(\n `${signInUrl}?returnTo=${encodeURIComponent(pathname)}`,\n req.url,\n ),\n );\n response.cookies.set(COOKIE_AUTH_TOKEN, \"\", { path: \"/\", maxAge: 0 });\n response.cookies.set(COOKIE_REFRESH_TOKEN, \"\", {\n path: \"/api/auth\",\n maxAge: 0,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, \"\", { path: \"/\", maxAge: 0 });\n return { authObj: null, response };\n }\n\n const claims = getClaimsFromToken(token);\n if (!claims) {\n return {\n authObj: null,\n response: NextResponse.redirect(new URL(signInUrl, req.url)),\n };\n }\n\n return { authObj: buildAuthObject(token, claims) };\n}\n\nexport function inaiAuthMiddleware(config: InAIMiddlewareConfig = {}) {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n if (isPublicRoute(req, publicRoutes, builtinPublic)) {\n return NextResponse.next();\n }\n\n const apiUrl = authMode === \"platform\" ? DEFAULT_API_URL : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n return NextResponse.next();\n };\n}\n\nexport function withInAIAuth(\n wrappedMiddleware: (\n req: NextRequest,\n ) => NextResponse | Response | Promise<NextResponse | Response>,\n config: InAIMiddlewareConfig = {},\n): (req: NextRequest) => Promise<NextResponse> {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);\n\n if (!isPublic) {\n const apiUrl = authMode === \"platform\" ? DEFAULT_API_URL : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n const authHeader = JSON.stringify({\n userId: authObj.userId,\n tenantId: authObj.tenantId,\n appId: authObj.appId,\n envId: authObj.envId,\n orgId: authObj.orgId,\n orgRole: authObj.orgRole,\n });\n req.headers.set(\"x-inai-auth\", authHeader);\n }\n\n const wrappedResponse = await wrappedMiddleware(req);\n if (wrappedResponse instanceof NextResponse) return wrappedResponse;\n return new NextResponse(wrappedResponse.body, wrappedResponse);\n };\n}\n"],"mappings":"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","names":["response"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport type { NextRequest } from \"next/server\";\nimport type { AuthObject } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_AUTH_SESSION,\n COOKIE_REFRESH_TOKEN,\n DEFAULT_API_URL,\n decodeJWTHeader,\n verifyES256,\n JWKSClient,\n} from \"@inai-dev/shared\";\nimport { isTokenExpired } from \"@inai-dev/shared\";\n\nexport interface InAIMiddlewareConfig {\n authMode?: \"app\" | \"platform\";\n publicRoutes?: string[] | ((req: NextRequest) => boolean);\n signInUrl?: string;\n beforeAuth?: (req: NextRequest) => NextResponse | void;\n afterAuth?: (auth: AuthObject, req: NextRequest) => NextResponse | void;\n jwksUrl?: string;\n apiUrl?: string;\n}\n\n// Module-level JWKS client (shared across requests in the same worker/process)\nlet sharedJwksClient: JWKSClient | null = null;\nlet sharedJwksUrl: string | null = null;\n\nfunction getJwksClient(config: InAIMiddlewareConfig): JWKSClient {\n const jwksUrl = config.jwksUrl\n ?? `${config.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n\n if (!sharedJwksClient || sharedJwksUrl !== jwksUrl) {\n sharedJwksClient = new JWKSClient(jwksUrl);\n sharedJwksUrl = jwksUrl;\n }\n return sharedJwksClient;\n}\n\nexport function createRouteMatcher(\n patterns: (string | RegExp)[],\n): (req: NextRequest) => boolean {\n const matchers = patterns.map((pattern) => {\n if (pattern instanceof RegExp) return pattern;\n let regexStr = pattern;\n if (regexStr.endsWith(\"*\") && !regexStr.includes(\"(\")) {\n regexStr = regexStr.slice(0, -1) + \".*\";\n }\n return new RegExp(`^${regexStr}$`);\n });\n\n return (req: NextRequest) => {\n const pathname = req.nextUrl.pathname;\n return matchers.some((m) => m.test(pathname));\n };\n}\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n req: NextRequest,\n publicRoutes: string[] | ((req: NextRequest) => boolean),\n builtinPublic: string[],\n): boolean {\n const pathname = req.nextUrl.pathname;\n if (matchesRoute(pathname, builtinPublic)) return true;\n if (typeof publicRoutes === \"function\") return publicRoutes(req);\n return matchesRoute(pathname, publicRoutes);\n}\n\nasync function buildAuthObject(\n token: string,\n jwksClient: JWKSClient,\n): Promise<AuthObject | null> {\n const header = decodeJWTHeader(token);\n if (!header?.kid) return null;\n\n let publicKey: CryptoKey;\n try {\n publicKey = await jwksClient.getKey(header.kid);\n } catch {\n return null;\n }\n\n let claims = await verifyES256(token, publicKey);\n if (!claims) {\n // Signature failed with cached key — refetch once in case of key rotation\n jwksClient.invalidate();\n try {\n publicKey = await jwksClient.getKey(header.kid);\n } catch {\n return null;\n }\n claims = await verifyES256(token, publicKey);\n if (!claims) return null;\n }\n\n const roles = claims.roles ?? [];\n const permissions = claims.permissions ?? [];\n return {\n userId: claims.sub,\n tenantId: claims.tenant_id,\n appId: claims.app_id ?? null,\n envId: claims.env_id ?? null,\n orgId: claims.org_id ?? null,\n orgRole: claims.org_role ?? null,\n sessionId: null,\n getToken: async () => token,\n has: (params: { role?: string; permission?: string }) => {\n if (params.role && roles.includes(params.role)) return true;\n if (params.permission && permissions.includes(params.permission))\n return true;\n return false;\n },\n };\n}\n\nasync function runAuthCheck(\n req: NextRequest,\n signInUrl: string,\n jwksClient: JWKSClient,\n apiUrl?: string,\n): Promise<{ authObj: AuthObject | null; response?: NextResponse }> {\n const { pathname } = req.nextUrl;\n const token = req.cookies.get(COOKIE_AUTH_TOKEN)?.value;\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = req.cookies.get(COOKIE_REFRESH_TOKEN)?.value;\n if (refreshToken) {\n try {\n if (apiUrl) {\n const refreshRes = await fetch(`${apiUrl}/api/platform/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n if (refreshRes.ok) {\n const newTokens = await refreshRes.json() as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n const meRes = await fetch(`${apiUrl}/api/platform/auth/me`, {\n headers: { Authorization: `Bearer ${newTokens.access_token}` },\n });\n if (meRes.ok) {\n const meData = await meRes.json();\n const newUser = meData.data ?? meData;\n const isProduction = process.env.NODE_ENV === \"production\";\n const response = NextResponse.next();\n response.cookies.set(COOKIE_AUTH_TOKEN, newTokens.access_token, {\n httpOnly: true, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n response.cookies.set(COOKIE_REFRESH_TOKEN, newTokens.refresh_token, {\n httpOnly: true, secure: isProduction, sameSite: \"strict\",\n path: \"/api/auth\", maxAge: 7 * 24 * 60 * 60,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, JSON.stringify({\n user: newUser,\n expiresAt: new Date(Date.now() + newTokens.expires_in * 1000).toISOString(),\n }), {\n httpOnly: false, secure: isProduction, sameSite: \"lax\",\n path: \"/\", maxAge: newTokens.expires_in,\n });\n return { authObj: null, response };\n }\n }\n } else {\n const refreshUrl = new URL(\"/api/auth/refresh\", req.url);\n const refreshRes = await fetch(refreshUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Cookie: req.headers.get(\"cookie\") ?? \"\",\n },\n });\n if (refreshRes.ok) {\n const response = NextResponse.next();\n const setCookies = refreshRes.headers.getSetCookie?.() ?? [];\n for (const cookie of setCookies) {\n response.headers.append(\"Set-Cookie\", cookie);\n }\n return { authObj: null, response };\n }\n }\n } catch {\n // Refresh failed, fall through to redirect\n }\n }\n\n const response = NextResponse.redirect(\n new URL(\n `${signInUrl}?returnTo=${encodeURIComponent(pathname)}`,\n req.url,\n ),\n );\n response.cookies.set(COOKIE_AUTH_TOKEN, \"\", { path: \"/\", maxAge: 0 });\n response.cookies.set(COOKIE_REFRESH_TOKEN, \"\", {\n path: \"/api/auth\",\n maxAge: 0,\n });\n response.cookies.set(COOKIE_AUTH_SESSION, \"\", { path: \"/\", maxAge: 0 });\n return { authObj: null, response };\n }\n\n const authObj = await buildAuthObject(token, jwksClient);\n if (!authObj) {\n return {\n authObj: null,\n response: NextResponse.redirect(new URL(signInUrl, req.url)),\n };\n }\n\n return { authObj };\n}\n\nexport function inaiAuthMiddleware(config: InAIMiddlewareConfig = {}) {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n const jwksClient = getJwksClient(config);\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n if (isPublicRoute(req, publicRoutes, builtinPublic)) {\n return NextResponse.next();\n }\n\n const apiUrl = authMode === \"platform\" ? (config.apiUrl ?? DEFAULT_API_URL) : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n return NextResponse.next();\n };\n}\n\nexport function withInAIAuth(\n wrappedMiddleware: (\n req: NextRequest,\n ) => NextResponse | Response | Promise<NextResponse | Response>,\n config: InAIMiddlewareConfig = {},\n): (req: NextRequest) => Promise<NextResponse> {\n const {\n authMode = \"app\",\n publicRoutes = [],\n signInUrl = \"/login\",\n beforeAuth,\n afterAuth,\n } = config;\n\n const builtinPublic = [\"/_next/*\", \"/favicon.ico\", \"/api/*\", signInUrl];\n const jwksClient = getJwksClient(config);\n\n return async function middleware(\n req: NextRequest,\n ): Promise<NextResponse> {\n if (beforeAuth) {\n const result = beforeAuth(req);\n if (result) return result;\n }\n\n const isPublic = isPublicRoute(req, publicRoutes, builtinPublic);\n\n if (!isPublic) {\n const apiUrl = authMode === \"platform\" ? (config.apiUrl ?? DEFAULT_API_URL) : undefined;\n const { authObj, response } = await runAuthCheck(req, signInUrl, jwksClient, apiUrl);\n if (response) return response;\n if (!authObj)\n return NextResponse.redirect(new URL(signInUrl, req.url));\n\n if (afterAuth) {\n const result = afterAuth(authObj, req);\n if (result) return result;\n }\n\n const authHeader = JSON.stringify({\n userId: authObj.userId,\n tenantId: authObj.tenantId,\n appId: authObj.appId,\n envId: authObj.envId,\n orgId: authObj.orgId,\n orgRole: authObj.orgRole,\n });\n req.headers.set(\"x-inai-auth\", authHeader);\n }\n\n const wrappedResponse = await wrappedMiddleware(req);\n if (wrappedResponse instanceof NextResponse) return wrappedResponse;\n return new NextResponse(wrappedResponse.body, wrappedResponse);\n };\n}\n"],"mappings":"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","names":["response"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inai-dev/nextjs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Next.js integration for InAI Auth SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"prepublishOnly": "npm run build"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@inai-dev/types": "^1.
|
|
39
|
-
"@inai-dev/shared": "^1.
|
|
40
|
-
"@inai-dev/backend": "^1.
|
|
41
|
-
"@inai-dev/react": "^0.
|
|
38
|
+
"@inai-dev/types": "^1.3.0",
|
|
39
|
+
"@inai-dev/shared": "^1.3.0",
|
|
40
|
+
"@inai-dev/backend": "^1.4.0",
|
|
41
|
+
"@inai-dev/react": "^0.4.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"next": ">=14.0.0",
|