@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 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)
@@ -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, claims) {
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, import_shared.isTokenExpired)(token)) {
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 claims = (0, import_shared.getClaimsFromToken)(token);
164
- if (!claims) {
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: buildAuthObject(token, claims) };
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));
@@ -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"]}
@@ -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>;
@@ -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>;
@@ -5,9 +5,21 @@ import {
5
5
  COOKIE_AUTH_SESSION,
6
6
  COOKIE_REFRESH_TOKEN,
7
7
  DEFAULT_API_URL,
8
- getClaimsFromToken,
9
- isTokenExpired
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, claims) {
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 claims = getClaimsFromToken(token);
145
- if (!claims) {
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: buildAuthObject(token, claims) };
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));
@@ -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":";AAAA,SAAS,oBAAoB;AAG7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUA,SAAS,mBACd,UAC+B;AAC/B,QAAM,WAAW,SAAS,IAAI,CAAC,YAAY;AACzC,QAAI,mBAAmB,OAAQ,QAAO;AACtC,QAAI,WAAW;AACf,QAAI,SAAS,SAAS,GAAG,KAAK,CAAC,SAAS,SAAS,GAAG,GAAG;AACrD,iBAAW,SAAS,MAAM,GAAG,EAAE,IAAI;AAAA,IACrC;AACA,WAAO,IAAI,OAAO,IAAI,QAAQ,GAAG;AAAA,EACnC,CAAC;AAED,SAAO,CAAC,QAAqB;AAC3B,UAAM,WAAW,IAAI,QAAQ;AAC7B,WAAO,SAAS,KAAK,CAAC,MAAM,EAAE,KAAK,QAAQ,CAAC;AAAA,EAC9C;AACF;AAEA,SAAS,aAAa,UAAkB,UAA6B;AACnE,SAAO,SAAS,KAAK,CAAC,YAAY;AAChC,QAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,aAAO,SAAS,WAAW,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IACjD;AACA,WAAO,aAAa;AAAA,EACtB,CAAC;AACH;AAEA,SAAS,cACP,KACA,cACA,eACS;AACT,QAAM,WAAW,IAAI,QAAQ;AAC7B,MAAI,aAAa,UAAU,aAAa,EAAG,QAAO;AAClD,MAAI,OAAO,iBAAiB,WAAY,QAAO,aAAa,GAAG;AAC/D,SAAO,aAAa,UAAU,YAAY;AAC5C;AAEA,SAAS,gBACP,OACA,QACY;AACZ,QAAM,QAAQ,OAAO,SAAS,CAAC;AAC/B,QAAM,cAAc,OAAO,eAAe,CAAC;AAC3C,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,OAAO,OAAO,UAAU;AAAA,IACxB,OAAO,OAAO,UAAU;AAAA,IACxB,OAAO,OAAO,UAAU;AAAA,IACxB,SAAS,OAAO,YAAY;AAAA,IAC5B,WAAW;AAAA,IACX,UAAU,YAAY;AAAA,IACtB,KAAK,CAAC,WAAmD;AACvD,UAAI,OAAO,QAAQ,MAAM,SAAS,OAAO,IAAI,EAAG,QAAO;AACvD,UAAI,OAAO,cAAc,YAAY,SAAS,OAAO,UAAU;AAC7D,eAAO;AACT,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAe,aACb,KACA,WACA,QACkE;AAClE,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,QAAM,QAAQ,IAAI,QAAQ,IAAI,iBAAiB,GAAG;AAElD,MAAI,CAAC,SAAS,eAAe,KAAK,GAAG;AACnC,UAAM,eAAe,IAAI,QAAQ,IAAI,oBAAoB,GAAG;AAC5D,QAAI,cAAc;AAChB,UAAI;AACF,YAAI,QAAQ;AACV,gBAAM,aAAa,MAAM,MAAM,GAAG,MAAM,8BAA8B;AAAA,YACpE,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,EAAE,eAAe,aAAa,CAAC;AAAA,UACtD,CAAC;AACD,cAAI,WAAW,IAAI;AACjB,kBAAM,YAAY,MAAM,WAAW,KAAK;AAKxC,kBAAM,QAAQ,MAAM,MAAM,GAAG,MAAM,yBAAyB;AAAA,cAC1D,SAAS,EAAE,eAAe,UAAU,UAAU,YAAY,GAAG;AAAA,YAC/D,CAAC;AACD,gBAAI,MAAM,IAAI;AACZ,oBAAM,SAAS,MAAM,MAAM,KAAK;AAChC,oBAAM,UAAU,OAAO,QAAQ;AAC/B,oBAAM,eAAe,QAAQ,IAAI,aAAa;AAC9C,oBAAMA,YAAW,aAAa,KAAK;AACnC,cAAAA,UAAS,QAAQ,IAAI,mBAAmB,UAAU,cAAc;AAAA,gBAC9D,UAAU;AAAA,gBAAM,QAAQ;AAAA,gBAAc,UAAU;AAAA,gBAChD,MAAM;AAAA,gBAAK,QAAQ,UAAU;AAAA,cAC/B,CAAC;AACD,cAAAA,UAAS,QAAQ,IAAI,sBAAsB,UAAU,eAAe;AAAA,gBAClE,UAAU;AAAA,gBAAM,QAAQ;AAAA,gBAAc,UAAU;AAAA,gBAChD,MAAM;AAAA,gBAAa,QAAQ,IAAI,KAAK,KAAK;AAAA,cAC3C,CAAC;AACD,cAAAA,UAAS,QAAQ,IAAI,qBAAqB,KAAK,UAAU;AAAA,gBACvD,MAAM;AAAA,gBACN,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,UAAU,aAAa,GAAI,EAAE,YAAY;AAAA,cAC5E,CAAC,GAAG;AAAA,gBACF,UAAU;AAAA,gBAAO,QAAQ;AAAA,gBAAc,UAAU;AAAA,gBACjD,MAAM;AAAA,gBAAK,QAAQ,UAAU;AAAA,cAC/B,CAAC;AACD,qBAAO,EAAE,SAAS,MAAM,UAAAA,UAAS;AAAA,YACnC;AAAA,UACF;AAAA,QACF,OAAO;AACL,gBAAM,aAAa,IAAI,IAAI,qBAAqB,IAAI,GAAG;AACvD,gBAAM,aAAa,MAAM,MAAM,WAAW,SAAS,GAAG;AAAA,YACpD,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,gBAAgB;AAAA,cAChB,QAAQ,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAAA,YACvC;AAAA,UACF,CAAC;AACD,cAAI,WAAW,IAAI;AACjB,kBAAMA,YAAW,aAAa,KAAK;AACnC,kBAAM,aAAa,WAAW,QAAQ,eAAe,KAAK,CAAC;AAC3D,uBAAW,UAAU,YAAY;AAC/B,cAAAA,UAAS,QAAQ,OAAO,cAAc,MAAM;AAAA,YAC9C;AACA,mBAAO,EAAE,SAAS,MAAM,UAAAA,UAAS;AAAA,UACnC;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,WAAW,aAAa;AAAA,MAC5B,IAAI;AAAA,QACF,GAAG,SAAS,aAAa,mBAAmB,QAAQ,CAAC;AAAA,QACrD,IAAI;AAAA,MACN;AAAA,IACF;AACA,aAAS,QAAQ,IAAI,mBAAmB,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;AACpE,aAAS,QAAQ,IAAI,sBAAsB,IAAI;AAAA,MAC7C,MAAM;AAAA,MACN,QAAQ;AAAA,IACV,CAAC;AACD,aAAS,QAAQ,IAAI,qBAAqB,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;AACtE,WAAO,EAAE,SAAS,MAAM,SAAS;AAAA,EACnC;AAEA,QAAM,SAAS,mBAAmB,KAAK;AACvC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU,aAAa,SAAS,IAAI,IAAI,WAAW,IAAI,GAAG,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,gBAAgB,OAAO,MAAM,EAAE;AACnD;AAEO,SAAS,mBAAmB,SAA+B,CAAC,GAAG;AACpE,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,eAAe,CAAC;AAAA,IAChB,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,gBAAgB,CAAC,YAAY,gBAAgB,UAAU,SAAS;AAEtE,SAAO,eAAe,WACpB,KACuB;AACvB,QAAI,YAAY;AACd,YAAM,SAAS,WAAW,GAAG;AAC7B,UAAI,OAAQ,QAAO;AAAA,IACrB;AAEA,QAAI,cAAc,KAAK,cAAc,aAAa,GAAG;AACnD,aAAO,aAAa,KAAK;AAAA,IAC3B;AAEA,UAAM,SAAS,aAAa,aAAa,kBAAkB;AAC3D,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,aAAa,KAAK,WAAW,MAAM;AACvE,QAAI,SAAU,QAAO;AACrB,QAAI,CAAC;AACH,aAAO,aAAa,SAAS,IAAI,IAAI,WAAW,IAAI,GAAG,CAAC;AAE1D,QAAI,WAAW;AACb,YAAM,SAAS,UAAU,SAAS,GAAG;AACrC,UAAI,OAAQ,QAAO;AAAA,IACrB;AAEA,WAAO,aAAa,KAAK;AAAA,EAC3B;AACF;AAEO,SAAS,aACd,mBAGA,SAA+B,CAAC,GACa;AAC7C,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,eAAe,CAAC;AAAA,IAChB,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,gBAAgB,CAAC,YAAY,gBAAgB,UAAU,SAAS;AAEtE,SAAO,eAAe,WACpB,KACuB;AACvB,QAAI,YAAY;AACd,YAAM,SAAS,WAAW,GAAG;AAC7B,UAAI,OAAQ,QAAO;AAAA,IACrB;AAEA,UAAM,WAAW,cAAc,KAAK,cAAc,aAAa;AAE/D,QAAI,CAAC,UAAU;AACb,YAAM,SAAS,aAAa,aAAa,kBAAkB;AAC3D,YAAM,EAAE,SAAS,SAAS,IAAI,MAAM,aAAa,KAAK,WAAW,MAAM;AACvE,UAAI,SAAU,QAAO;AACrB,UAAI,CAAC;AACH,eAAO,aAAa,SAAS,IAAI,IAAI,WAAW,IAAI,GAAG,CAAC;AAE1D,UAAI,WAAW;AACb,cAAM,SAAS,UAAU,SAAS,GAAG;AACrC,YAAI,OAAQ,QAAO;AAAA,MACrB;AAEA,YAAM,aAAa,KAAK,UAAU;AAAA,QAChC,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,OAAO,QAAQ;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,SAAS,QAAQ;AAAA,MACnB,CAAC;AACD,UAAI,QAAQ,IAAI,eAAe,UAAU;AAAA,IAC3C;AAEA,UAAM,kBAAkB,MAAM,kBAAkB,GAAG;AACnD,QAAI,2BAA2B,aAAc,QAAO;AACpD,WAAO,IAAI,aAAa,gBAAgB,MAAM,eAAe;AAAA,EAC/D;AACF;","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.2.0",
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.1.0",
39
- "@inai-dev/shared": "^1.1.0",
40
- "@inai-dev/backend": "^1.2.0",
41
- "@inai-dev/react": "^0.2.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",