@vaultix.ai/nextjs 0.2.0 → 0.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/dist/index.mjs CHANGED
@@ -1,36 +1,56 @@
1
1
  // src/middleware.ts
2
- import { importSPKI, jwtVerify } from "jose";
2
+ import { createRemoteJWKSet, importSPKI, jwtVerify } from "jose";
3
3
  import { NextResponse } from "next/server";
4
4
  var HEADER_USER_ID = "x-vaultix-user-id";
5
5
  var HEADER_ORG_ID = "x-vaultix-org-id";
6
6
  var HEADER_ORG_ROLE = "x-vaultix-org-role";
7
7
  var HEADER_SESSION_ID = "x-vaultix-session-id";
8
8
  var HEADER_RISK_LEVEL = "x-vaultix-risk-level";
9
- var cachedKey = null;
10
- var cachedPem = null;
11
- async function getPublicKey() {
12
- const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;
13
- if (!pem) return null;
14
- if (cachedKey && cachedPem === pem) return cachedKey;
9
+ function decodeApiUrlFromKey(pk) {
15
10
  try {
16
- cachedKey = await importSPKI(pem.replace(/\\n/g, "\n"), "RS256");
17
- cachedPem = pem;
18
- return cachedKey;
11
+ const parts = pk.split("_");
12
+ if (parts.length >= 4 && parts[0] === "vaultix" && parts[1] === "pk") {
13
+ return atob(parts.slice(3).join("_")).replace(/\/$/, "");
14
+ }
19
15
  } catch {
20
- return null;
21
16
  }
17
+ return "";
18
+ }
19
+ function resolveApiUrl(options) {
20
+ if (options.apiUrl) return options.apiUrl.replace(/\/$/, "");
21
+ if (process.env.VAULTIX_API_URL) return process.env.VAULTIX_API_URL.replace(/\/$/, "");
22
+ const pk = process.env.NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY ?? "";
23
+ return decodeApiUrlFromKey(pk);
24
+ }
25
+ var remoteJwks = null;
26
+ var remoteJwksUrl = null;
27
+ var staticKey = null;
28
+ var staticPem = null;
29
+ async function getVerifyKey(apiUrl) {
30
+ const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;
31
+ if (pem) {
32
+ const normalized = pem.replace(/\\n/g, "\n");
33
+ if (staticKey && staticPem === normalized) return { key: staticKey, mode: "static" };
34
+ staticKey = await importSPKI(normalized, "RS256");
35
+ staticPem = normalized;
36
+ return { key: staticKey, mode: "static" };
37
+ }
38
+ if (!apiUrl) return null;
39
+ const jwksUrl = `${apiUrl}/api/v1/.well-known/jwks.json`;
40
+ if (!remoteJwks || remoteJwksUrl !== jwksUrl) {
41
+ remoteJwks = createRemoteJWKSet(new URL(jwksUrl));
42
+ remoteJwksUrl = jwksUrl;
43
+ }
44
+ return { key: remoteJwks, mode: "remote" };
22
45
  }
23
46
  function isPublic(pathname, rules) {
24
- return rules.some((rule) => {
25
- if (typeof rule === "string") {
26
- return pathname === rule || pathname.startsWith(rule);
27
- }
28
- return rule.test(pathname);
29
- });
47
+ return rules.some(
48
+ (rule) => typeof rule === "string" ? pathname === rule || pathname.startsWith(rule) : rule.test(pathname)
49
+ );
30
50
  }
31
51
  async function handleHandshake(req, handshakeToken, apiUrl) {
32
52
  try {
33
- const res = await fetch(`${apiUrl}/v1/tokens/exchange`, {
53
+ const res = await fetch(`${apiUrl}/api/v1/tokens/exchange`, {
34
54
  method: "POST",
35
55
  headers: { "Content-Type": "application/json" },
36
56
  body: JSON.stringify({ handshake_token: handshakeToken })
@@ -46,7 +66,6 @@ async function handleHandshake(req, handshakeToken, apiUrl) {
46
66
  sameSite: "lax",
47
67
  path: "/",
48
68
  maxAge: 30 * 24 * 60 * 60
49
- // 30 days
50
69
  });
51
70
  return response;
52
71
  } catch {
@@ -54,21 +73,16 @@ async function handleHandshake(req, handshakeToken, apiUrl) {
54
73
  }
55
74
  }
56
75
  function authMiddleware(options = {}) {
57
- const {
58
- publicRoutes = [],
59
- signInUrl = "/sign-in",
60
- afterAuth
61
- } = options;
76
+ const { publicRoutes = [], afterAuth } = options;
62
77
  return async function middleware(req) {
63
78
  const { pathname } = req.nextUrl;
64
79
  const publicRoute = isPublic(pathname, publicRoutes);
80
+ const apiUrl = resolveApiUrl(options);
81
+ const signInUrl = options.signInUrl ?? (apiUrl ? `${apiUrl}/auth/sign-in` : "/sign-in");
65
82
  const handshakeToken = req.nextUrl.searchParams.get("__vaultix_handshake");
66
- if (handshakeToken) {
67
- const apiUrl = options.apiUrl ?? process.env.VAULTIX_API_URL ?? "";
68
- if (apiUrl) {
69
- const response = await handleHandshake(req, handshakeToken, apiUrl);
70
- if (response) return response;
71
- }
83
+ if (handshakeToken && apiUrl) {
84
+ const response = await handleHandshake(req, handshakeToken, apiUrl);
85
+ if (response) return response;
72
86
  }
73
87
  let result = {
74
88
  userId: null,
@@ -79,12 +93,12 @@ function authMiddleware(options = {}) {
79
93
  isSignedIn: false,
80
94
  isPublicRoute: publicRoute
81
95
  };
82
- const sessionCookie = req.cookies.get("vaultix-session")?.value ?? extractBearer(req.headers.get("authorization") ?? "");
83
- if (sessionCookie) {
84
- const key = await getPublicKey();
85
- if (key) {
96
+ const token = req.cookies.get("vaultix-session")?.value ?? extractBearer(req.headers.get("authorization") ?? "");
97
+ if (token) {
98
+ const verifyKey = await getVerifyKey(apiUrl);
99
+ if (verifyKey) {
86
100
  try {
87
- const { payload } = await jwtVerify(sessionCookie, key, {
101
+ const { payload } = await jwtVerify(token, verifyKey.key, {
88
102
  algorithms: ["RS256"]
89
103
  });
90
104
  result = {
@@ -127,50 +141,127 @@ function extractBearer(header) {
127
141
  }
128
142
 
129
143
  // src/server.ts
130
- import { headers } from "next/headers";
144
+ import { cookies, headers } from "next/headers";
131
145
  import { redirect } from "next/navigation";
146
+ import { createRemoteJWKSet as createRemoteJWKSet2, importSPKI as importSPKI2, jwtVerify as jwtVerify2 } from "jose";
147
+ function resolveApiUrl2() {
148
+ if (process.env.VAULTIX_API_URL) return process.env.VAULTIX_API_URL.replace(/\/$/, "");
149
+ const pk = process.env.NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY ?? "";
150
+ if (!pk) return "";
151
+ try {
152
+ const parts = pk.split("_");
153
+ if (parts.length >= 4 && parts[0] === "vaultix" && parts[1] === "pk") {
154
+ return atob(parts.slice(3).join("_")).replace(/\/$/, "");
155
+ }
156
+ } catch {
157
+ }
158
+ return "";
159
+ }
160
+ var _remoteJwks = null;
161
+ var _remoteJwksUrl = null;
162
+ var _staticKey = null;
163
+ var _staticPem = null;
164
+ async function verifyJwt(token) {
165
+ const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;
166
+ if (pem) {
167
+ const normalized = pem.replace(/\\n/g, "\n");
168
+ if (!_staticKey || _staticPem !== normalized) {
169
+ _staticKey = await importSPKI2(normalized, "RS256");
170
+ _staticPem = normalized;
171
+ }
172
+ try {
173
+ const { payload } = await jwtVerify2(token, _staticKey, { algorithms: ["RS256"] });
174
+ return payload;
175
+ } catch {
176
+ return null;
177
+ }
178
+ }
179
+ const apiUrl = resolveApiUrl2();
180
+ if (!apiUrl) return null;
181
+ const jwksUrl = `${apiUrl}/api/v1/.well-known/jwks.json`;
182
+ if (!_remoteJwks || _remoteJwksUrl !== jwksUrl) {
183
+ _remoteJwks = createRemoteJWKSet2(new URL(jwksUrl));
184
+ _remoteJwksUrl = jwksUrl;
185
+ }
186
+ try {
187
+ const { payload } = await jwtVerify2(token, _remoteJwks, { algorithms: ["RS256"] });
188
+ return payload;
189
+ } catch {
190
+ return null;
191
+ }
192
+ }
132
193
  async function auth() {
194
+ function makeProtect(isSignedIn) {
195
+ return (redirectTo) => {
196
+ if (!isSignedIn) {
197
+ const apiUrl = resolveApiUrl2();
198
+ const dest = redirectTo ?? (apiUrl ? `${apiUrl}/auth/sign-in` : "/sign-in");
199
+ redirect(dest);
200
+ }
201
+ };
202
+ }
133
203
  const h = await headers();
134
204
  const userId = h.get(HEADER_USER_ID);
135
- if (!userId) {
205
+ if (userId) {
206
+ return {
207
+ userId,
208
+ orgId: h.get(HEADER_ORG_ID) || null,
209
+ orgRole: h.get(HEADER_ORG_ROLE) || null,
210
+ sessionId: h.get(HEADER_SESSION_ID) || null,
211
+ riskLevel: h.get(HEADER_RISK_LEVEL) ?? "low",
212
+ isSignedIn: true,
213
+ protect: makeProtect(true)
214
+ };
215
+ }
216
+ const jar = await cookies();
217
+ const token = jar.get("vaultix-session")?.value;
218
+ if (!token) {
219
+ return {
220
+ userId: null,
221
+ orgId: null,
222
+ orgRole: null,
223
+ sessionId: null,
224
+ riskLevel: null,
225
+ isSignedIn: false,
226
+ protect: makeProtect(false)
227
+ };
228
+ }
229
+ const payload = await verifyJwt(token);
230
+ if (!payload) {
136
231
  return {
137
232
  userId: null,
138
233
  orgId: null,
139
234
  orgRole: null,
140
235
  sessionId: null,
141
236
  riskLevel: null,
142
- isSignedIn: false
237
+ isSignedIn: false,
238
+ protect: makeProtect(false)
143
239
  };
144
240
  }
145
241
  return {
146
- userId,
147
- orgId: h.get(HEADER_ORG_ID) || null,
148
- orgRole: h.get(HEADER_ORG_ROLE) || null,
149
- sessionId: h.get(HEADER_SESSION_ID) || null,
150
- riskLevel: h.get(HEADER_RISK_LEVEL) ?? "low",
151
- isSignedIn: true
242
+ userId: payload["uid"] ?? null,
243
+ orgId: payload["org"] ?? null,
244
+ orgRole: payload["rol"] ?? null,
245
+ sessionId: payload["sid"] ?? null,
246
+ riskLevel: payload["risk"] ?? "low",
247
+ isSignedIn: true,
248
+ protect: makeProtect(true)
152
249
  };
153
250
  }
154
- async function protect(redirectTo = "/sign-in") {
155
- const authObj = await auth();
156
- if (!authObj.isSignedIn) {
157
- redirect(redirectTo);
158
- }
159
- return authObj;
160
- }
161
251
  async function currentUser() {
162
- const { userId } = await auth();
163
- if (!userId) return null;
164
- const apiUrl = process.env["VAULTIX_API_URL"];
165
- const secret = process.env["VAULTIX_SECRET_KEY"];
166
- if (!apiUrl || !secret) return null;
252
+ const jar = await cookies();
253
+ const token = jar.get("vaultix-session")?.value;
254
+ if (!token) return null;
255
+ const apiUrl = resolveApiUrl2();
256
+ if (!apiUrl) return null;
167
257
  try {
168
- const res = await fetch(`${apiUrl}/v1/users/${userId}`, {
169
- headers: { Authorization: `Bearer ${secret}` },
258
+ const res = await fetch(`${apiUrl}/api/v1/me`, {
259
+ headers: { Authorization: `Bearer ${token}` },
170
260
  cache: "no-store"
171
261
  });
172
262
  if (!res.ok) return null;
173
- return await res.json();
263
+ const data = await res.json();
264
+ return data.user ?? null;
174
265
  } catch {
175
266
  return null;
176
267
  }
@@ -178,21 +269,25 @@ async function currentUser() {
178
269
  async function currentOrg() {
179
270
  const { orgId } = await auth();
180
271
  if (!orgId) return null;
181
- const apiUrl = process.env["VAULTIX_API_URL"];
182
- const secret = process.env["VAULTIX_SECRET_KEY"];
272
+ const apiUrl = resolveApiUrl2();
273
+ const secret = process.env.VAULTIX_SECRET_KEY;
183
274
  if (!apiUrl || !secret) return null;
184
275
  try {
185
- const orgFetchInit = {
276
+ const res = await fetch(`${apiUrl}/api/v1/orgs/${orgId}`, {
186
277
  headers: { Authorization: `Bearer ${secret}` },
187
278
  next: { revalidate: 30 }
188
- };
189
- const res = await fetch(`${apiUrl}/v1/orgs/${orgId}`, orgFetchInit);
279
+ });
190
280
  if (!res.ok) return null;
191
281
  return await res.json();
192
282
  } catch {
193
283
  return null;
194
284
  }
195
285
  }
286
+ async function protect(redirectTo) {
287
+ const authObj = await auth();
288
+ authObj.protect(redirectTo);
289
+ return authObj;
290
+ }
196
291
 
197
292
  // src/index.ts
198
293
  import {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["// Edge-runtime compatible. Uses jose (not Node crypto) for JWT verification.\nimport { importSPKI, jwtVerify, type KeyLike } from \"jose\";\nimport { NextRequest, NextResponse } from \"next/server\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface AuthResult {\n /** Authenticated user ID (`sub` claim), or null if unauthenticated. */\n userId: string | null;\n orgId: string | null;\n orgRole: string | null;\n sessionId: string | null;\n riskLevel: string | null;\n isSignedIn: boolean;\n isPublicRoute: boolean;\n}\n\nexport interface AuthMiddlewareOptions {\n /**\n * Routes that do not require authentication.\n * Strings are matched by exact path or prefix (e.g. \"/sign-in\" or \"/api/public/\").\n * RegExps are tested against `pathname`.\n */\n publicRoutes?: Array<string | RegExp>;\n\n /** Where to redirect unauthenticated users. Default: \"/sign-in\". */\n signInUrl?: string;\n\n /**\n * Vaultix API origin — required to exchange handshake tokens.\n * Falls back to VAULTIX_API_URL env var.\n * Example: \"https://vaultix.smritix-ai.com\"\n */\n apiUrl?: string;\n\n /**\n * Custom logic after auth state is determined.\n * Return a `NextResponse` to short-circuit the default redirect behaviour;\n * return `undefined` to continue with defaults.\n */\n afterAuth?: (\n auth: AuthResult,\n req: NextRequest,\n ) => NextResponse | Response | undefined | void;\n}\n\n// ─── Header names injected into RSC requests ──────────────────────────────────\n\nexport const HEADER_USER_ID = \"x-vaultix-user-id\";\nexport const HEADER_ORG_ID = \"x-vaultix-org-id\";\nexport const HEADER_ORG_ROLE = \"x-vaultix-org-role\";\nexport const HEADER_SESSION_ID = \"x-vaultix-session-id\";\nexport const HEADER_RISK_LEVEL = \"x-vaultix-risk-level\";\n\n// ─── Public-key cache ─────────────────────────────────────────────────────────\n\nlet cachedKey: KeyLike | null = null;\nlet cachedPem: string | null = null;\n\nasync function getPublicKey(): Promise<KeyLike | null> {\n const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;\n if (!pem) return null;\n if (cachedKey && cachedPem === pem) return cachedKey;\n\n try {\n cachedKey = await importSPKI(pem.replace(/\\\\n/g, \"\\n\"), \"RS256\");\n cachedPem = pem;\n return cachedKey;\n } catch {\n return null;\n }\n}\n\n// ─── Route matching ───────────────────────────────────────────────────────────\n\nfunction isPublic(pathname: string, rules: Array<string | RegExp>): boolean {\n return rules.some((rule) => {\n if (typeof rule === \"string\") {\n return pathname === rule || pathname.startsWith(rule);\n }\n return rule.test(pathname);\n });\n}\n\n// ─── Handshake token exchange ─────────────────────────────────────────────────\n// Called when `__vaultix_handshake` appears in the URL.\n// Exchanges the short-lived token for a full session JWT, sets a same-domain\n// cookie, and redirects to the clean URL — mirroring Clerk's __clerk_handshake.\n\nasync function handleHandshake(\n req: NextRequest,\n handshakeToken: string,\n apiUrl: string,\n): Promise<NextResponse | null> {\n try {\n const res = await fetch(`${apiUrl}/v1/tokens/exchange`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ handshake_token: handshakeToken }),\n });\n\n if (!res.ok) return null;\n\n const { session_jwt } = (await res.json()) as { session_jwt: string };\n\n const cleanUrl = req.nextUrl.clone();\n cleanUrl.searchParams.delete(\"__vaultix_handshake\");\n\n const response = NextResponse.redirect(cleanUrl);\n response.cookies.set(\"vaultix-session\", session_jwt, {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 30 * 24 * 60 * 60, // 30 days\n });\n return response;\n } catch {\n return null;\n }\n}\n\n// ─── authMiddleware factory ───────────────────────────────────────────────────\n\n/**\n * authMiddleware wraps your Next.js middleware.ts export.\n *\n * @example\n * // middleware.ts\n * import { authMiddleware } from \"@vaultix.ai/nextjs/middleware\";\n * export default authMiddleware({\n * apiUrl: \"https://vaultix.smritix-ai.com\",\n * publicRoutes: [\"/sign-in\", \"/sign-up\"],\n * });\n * export const config = { matcher: [\"/((?!_next|.*\\\\..*).*)\"] };\n */\nexport function authMiddleware(options: AuthMiddlewareOptions = {}) {\n const {\n publicRoutes = [],\n signInUrl = \"/sign-in\",\n afterAuth,\n } = options;\n\n return async function middleware(req: NextRequest): Promise<NextResponse> {\n const { pathname } = req.nextUrl;\n const publicRoute = isPublic(pathname, publicRoutes);\n\n // ── Handshake exchange ─────────────────────────────────────────────────\n const handshakeToken = req.nextUrl.searchParams.get(\"__vaultix_handshake\");\n if (handshakeToken) {\n const apiUrl =\n options.apiUrl ??\n process.env.VAULTIX_API_URL ??\n \"\";\n if (apiUrl) {\n const response = await handleHandshake(req, handshakeToken, apiUrl);\n if (response) return response;\n // If exchange failed, fall through to normal auth check\n }\n }\n\n // ── JWT verification ───────────────────────────────────────────────────\n let result: AuthResult = {\n userId: null,\n orgId: null,\n orgRole: null,\n sessionId: null,\n riskLevel: null,\n isSignedIn: false,\n isPublicRoute: publicRoute,\n };\n\n const sessionCookie =\n req.cookies.get(\"vaultix-session\")?.value ??\n extractBearer(req.headers.get(\"authorization\") ?? \"\");\n\n if (sessionCookie) {\n const key = await getPublicKey();\n if (key) {\n try {\n const { payload } = await jwtVerify(sessionCookie, key, {\n algorithms: [\"RS256\"],\n });\n\n result = {\n userId: (payload[\"uid\"] as string) ?? null,\n orgId: (payload[\"org\"] as string) ?? null,\n orgRole: (payload[\"rol\"] as string) ?? null,\n sessionId: (payload[\"sid\"] as string) ?? null,\n riskLevel: (payload[\"risk\"] as string) ?? \"low\",\n isSignedIn: true,\n isPublicRoute: publicRoute,\n };\n } catch {\n // Expired or tampered token → treat as signed-out.\n }\n }\n }\n\n // Let callers override the default redirect logic.\n if (afterAuth) {\n const override = afterAuth(result, req);\n if (override) return override as NextResponse;\n }\n\n // Default: redirect unauthenticated requests to the sign-in page.\n if (!result.isSignedIn && !publicRoute) {\n const dest = new URL(signInUrl, req.url);\n dest.searchParams.set(\"redirect_url\", req.url);\n return NextResponse.redirect(dest);\n }\n\n // Propagate auth claims to Server Components via request headers.\n const next = new Headers(req.headers);\n if (result.userId) {\n next.set(HEADER_USER_ID, result.userId);\n next.set(HEADER_ORG_ID, result.orgId ?? \"\");\n next.set(HEADER_ORG_ROLE, result.orgRole ?? \"\");\n next.set(HEADER_SESSION_ID, result.sessionId ?? \"\");\n next.set(HEADER_RISK_LEVEL, result.riskLevel ?? \"low\");\n } else {\n [HEADER_USER_ID, HEADER_ORG_ID, HEADER_ORG_ROLE, HEADER_SESSION_ID, HEADER_RISK_LEVEL]\n .forEach((h) => next.delete(h));\n }\n\n return NextResponse.next({ request: { headers: next } });\n };\n}\n\nfunction extractBearer(header: string): string {\n return header.startsWith(\"Bearer \") ? header.slice(7) : \"\";\n}\n","// This file is server-only. Import from \"@smritix.ai/nextjs/server\".\n// Do NOT import in Client Components — it will throw at runtime.\nimport { headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\nimport type { VaultixOrganization, VaultixUser } from \"@vaultix.ai/react\";\nimport {\n HEADER_ORG_ID,\n HEADER_ORG_ROLE,\n HEADER_RISK_LEVEL,\n HEADER_SESSION_ID,\n HEADER_USER_ID,\n} from \"./middleware\";\n\n// Next.js extends RequestInit with cache and next options for its data cache.\ntype NextRequestInit = RequestInit & {\n cache?: RequestCache;\n next?: { revalidate?: number | false; tags?: string[] };\n};\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface AuthObject {\n userId: string | null;\n orgId: string | null;\n orgRole: string | null;\n sessionId: string | null;\n riskLevel: \"low\" | \"medium\" | \"high\" | \"critical\" | null;\n isSignedIn: boolean;\n}\n\n// ─── auth() ───────────────────────────────────────────────────────────────────\n\n/**\n * Returns the current auth state by reading the headers injected by\n * `authMiddleware`. Call this in Server Components, Route Handlers, and\n * Server Actions — never in Client Components.\n *\n * @example\n * import { auth } from \"@smritix.ai/nextjs/server\";\n * export default async function Page() {\n * const { userId, orgId } = await auth();\n * …\n * }\n */\nexport async function auth(): Promise<AuthObject> {\n const h = await headers();\n const userId = h.get(HEADER_USER_ID);\n\n if (!userId) {\n return {\n userId: null,\n orgId: null,\n orgRole: null,\n sessionId: null,\n riskLevel: null,\n isSignedIn: false,\n };\n }\n\n return {\n userId,\n orgId: h.get(HEADER_ORG_ID) || null,\n orgRole: h.get(HEADER_ORG_ROLE) || null,\n sessionId: h.get(HEADER_SESSION_ID) || null,\n riskLevel: (h.get(HEADER_RISK_LEVEL) ?? \"low\") as AuthObject[\"riskLevel\"],\n isSignedIn: true,\n };\n}\n\n// ─── protect() ────────────────────────────────────────────────────────────────\n\n/**\n * Asserts that the current user is authenticated. Redirects to `/sign-in`\n * if not. Returns the auth object for convenience.\n *\n * @example\n * export default async function ProtectedPage() {\n * const { userId } = await protect();\n * …\n * }\n */\nexport async function protect(redirectTo = \"/sign-in\"): Promise<AuthObject> {\n const authObj = await auth();\n if (!authObj.isSignedIn) {\n redirect(redirectTo);\n }\n return authObj;\n}\n\n// ─── currentUser() ────────────────────────────────────────────────────────────\n\n/**\n * Fetches the full `VaultixUser` record from the auth engine using server-to-server\n * credentials (`VAULTIX_API_URL` + `VAULTIX_SECRET_KEY` env vars).\n * Returns null when unauthenticated or when env vars are missing.\n *\n * Responses are never cached (`cache: \"no-store\"`) — user data must be fresh.\n */\nexport async function currentUser(): Promise<VaultixUser | null> {\n const { userId } = await auth();\n if (!userId) return null;\n\n const apiUrl = process.env[\"VAULTIX_API_URL\"];\n const secret = process.env[\"VAULTIX_SECRET_KEY\"];\n if (!apiUrl || !secret) return null;\n\n try {\n const res = await fetch(`${apiUrl}/v1/users/${userId}`, {\n headers: { Authorization: `Bearer ${secret}` },\n cache: \"no-store\",\n });\n if (!res.ok) return null;\n return (await res.json()) as VaultixUser;\n } catch {\n return null;\n }\n}\n\n// ─── currentOrg() ────────────────────────────────────────────────────────────\n\n/**\n * Fetches the active `VaultixOrganization` from the auth engine.\n * Returns null when the user has no active org or env vars are missing.\n *\n * Responses are cached for 30 seconds — org data changes infrequently.\n */\nexport async function currentOrg(): Promise<VaultixOrganization | null> {\n const { orgId } = await auth();\n if (!orgId) return null;\n\n const apiUrl = process.env[\"VAULTIX_API_URL\"];\n const secret = process.env[\"VAULTIX_SECRET_KEY\"];\n if (!apiUrl || !secret) return null;\n\n try {\n const orgFetchInit: NextRequestInit = {\n headers: { Authorization: `Bearer ${secret}` },\n next: { revalidate: 30 },\n };\n const res = await fetch(`${apiUrl}/v1/orgs/${orgId}`, orgFetchInit as RequestInit);\n if (!res.ok) return null;\n return (await res.json()) as VaultixOrganization;\n } catch {\n return null;\n }\n}\n","// @smritix.ai/nextjs — barrel export\n// Safe to import in all contexts (client, server, middleware).\n// For server-only utilities: import from \"@smritix.ai/nextjs/server\"\n// For the middleware factory: import from \"@smritix.ai/nextjs/middleware\"\n\n// ── Middleware ────────────────────────────────────────────────────────────────\nexport { authMiddleware } from \"./middleware\";\nexport type { AuthMiddlewareOptions, AuthResult } from \"./middleware\";\n\n// ── Server helpers ────────────────────────────────────────────────────────────\n// Re-exported for convenience; callers on client must use the explicit subpath.\nexport { auth, currentOrg, currentUser, protect } from \"./server\";\nexport type { AuthObject } from \"./server\";\n\n// ── Client SDK re-exports ─────────────────────────────────────────────────────\n// VaultixProvider, hooks, and UI components — safe for Client Components.\nexport {\n OrganizationSwitcher,\n SignIn,\n SignUp,\n VaultixProvider,\n UserButton,\n useOrganization,\n useSession,\n useVaultix,\n useUser,\n} from \"@vaultix.ai/react\";\n\nexport type {\n ChallengeType,\n RiskLevel,\n SessionClaims,\n VaultixContextValue,\n VaultixOrganization,\n VaultixProviderProps,\n VaultixSession,\n VaultixUser,\n} from \"@vaultix.ai/react\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/middleware.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["// Edge-runtime compatible. Uses jose for JWT verification.\nimport { createRemoteJWKSet, importSPKI, jwtVerify, type KeyLike } from \"jose\";\nimport { NextRequest, NextResponse } from \"next/server\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface AuthResult {\n userId: string | null;\n orgId: string | null;\n orgRole: string | null;\n sessionId: string | null;\n riskLevel: string | null;\n isSignedIn: boolean;\n isPublicRoute: boolean;\n}\n\nexport interface AuthMiddlewareOptions {\n /**\n * Routes that do not require authentication.\n * Strings: exact match or prefix. RegExps: tested against pathname.\n */\n publicRoutes?: Array<string | RegExp>;\n\n /**\n * Where to redirect unauthenticated users.\n * Defaults to the Vaultix hosted sign-in page (decoded from publishable key).\n * Override with \"/sign-in\" to use your own page.\n */\n signInUrl?: string;\n\n /**\n * Vaultix API origin. Auto-decoded from NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY.\n * Only needed if you're not using the standard publishable key format.\n */\n apiUrl?: string;\n\n /**\n * Custom logic after auth state is resolved.\n * Return a NextResponse to override default behaviour.\n */\n afterAuth?: (auth: AuthResult, req: NextRequest) => NextResponse | Response | undefined | void;\n}\n\n// ─── Header names ─────────────────────────────────────────────────────────────\n\nexport const HEADER_USER_ID = \"x-vaultix-user-id\";\nexport const HEADER_ORG_ID = \"x-vaultix-org-id\";\nexport const HEADER_ORG_ROLE = \"x-vaultix-org-role\";\nexport const HEADER_SESSION_ID = \"x-vaultix-session-id\";\nexport const HEADER_RISK_LEVEL = \"x-vaultix-risk-level\";\n\n// ─── Publishable key → API URL ────────────────────────────────────────────────\n\nfunction decodeApiUrlFromKey(pk: string): string {\n try {\n const parts = pk.split(\"_\");\n if (parts.length >= 4 && parts[0] === \"vaultix\" && parts[1] === \"pk\") {\n return atob(parts.slice(3).join(\"_\")).replace(/\\/$/, \"\");\n }\n } catch {}\n return \"\";\n}\n\nfunction resolveApiUrl(options: AuthMiddlewareOptions): string {\n if (options.apiUrl) return options.apiUrl.replace(/\\/$/, \"\");\n if (process.env.VAULTIX_API_URL) return process.env.VAULTIX_API_URL.replace(/\\/$/, \"\");\n const pk = process.env.NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY ?? \"\";\n return decodeApiUrlFromKey(pk);\n}\n\n// ─── JWKS cache ───────────────────────────────────────────────────────────────\n// createRemoteJWKSet fetches and caches the key set, re-fetches on rotation.\n// Falls back to a static PEM key if VAULTIX_JWT_PUBLIC_KEY is set (backward compat).\n\nlet remoteJwks: ReturnType<typeof createRemoteJWKSet> | null = null;\nlet remoteJwksUrl: string | null = null;\n\nlet staticKey: KeyLike | null = null;\nlet staticPem: string | null = null;\n\nasync function getVerifyKey(apiUrl: string) {\n // Prefer static PEM (set by env var) for zero-network-call verification\n const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;\n if (pem) {\n const normalized = pem.replace(/\\\\n/g, \"\\n\");\n if (staticKey && staticPem === normalized) return { key: staticKey, mode: \"static\" as const };\n staticKey = await importSPKI(normalized, \"RS256\");\n staticPem = normalized;\n return { key: staticKey, mode: \"static\" as const };\n }\n\n // Auto-fetch JWKS from the API — no env var needed\n if (!apiUrl) return null;\n const jwksUrl = `${apiUrl}/api/v1/.well-known/jwks.json`;\n if (!remoteJwks || remoteJwksUrl !== jwksUrl) {\n remoteJwks = createRemoteJWKSet(new URL(jwksUrl));\n remoteJwksUrl = jwksUrl;\n }\n return { key: remoteJwks, mode: \"remote\" as const };\n}\n\n// ─── Route matching ───────────────────────────────────────────────────────────\n\nfunction isPublic(pathname: string, rules: Array<string | RegExp>): boolean {\n return rules.some((rule) =>\n typeof rule === \"string\"\n ? pathname === rule || pathname.startsWith(rule)\n : rule.test(pathname),\n );\n}\n\n// ─── Handshake exchange ───────────────────────────────────────────────────────\n\nasync function handleHandshake(\n req: NextRequest,\n handshakeToken: string,\n apiUrl: string,\n): Promise<NextResponse | null> {\n try {\n const res = await fetch(`${apiUrl}/api/v1/tokens/exchange`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ handshake_token: handshakeToken }),\n });\n if (!res.ok) return null;\n\n const { session_jwt } = (await res.json()) as { session_jwt: string };\n const cleanUrl = req.nextUrl.clone();\n cleanUrl.searchParams.delete(\"__vaultix_handshake\");\n\n const response = NextResponse.redirect(cleanUrl);\n response.cookies.set(\"vaultix-session\", session_jwt, {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 30 * 24 * 60 * 60,\n });\n return response;\n } catch {\n return null;\n }\n}\n\n// ─── authMiddleware ───────────────────────────────────────────────────────────\n\n/**\n * Drop-in auth middleware — works with zero config when\n * NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY is set.\n *\n * @example\n * // middleware.ts\n * import { authMiddleware } from \"@vaultix.ai/nextjs/middleware\";\n * export default authMiddleware({ publicRoutes: [\"/\", \"/about\"] });\n * export const config = { matcher: [\"/((?!_next|.*\\\\..*).*)\"] };\n */\nexport function authMiddleware(options: AuthMiddlewareOptions = {}) {\n const { publicRoutes = [], afterAuth } = options;\n\n return async function middleware(req: NextRequest): Promise<NextResponse> {\n const { pathname } = req.nextUrl;\n const publicRoute = isPublic(pathname, publicRoutes);\n\n const apiUrl = resolveApiUrl(options);\n\n // Default sign-in URL: hosted Vaultix page decoded from publishable key\n const signInUrl =\n options.signInUrl ?? (apiUrl ? `${apiUrl}/auth/sign-in` : \"/sign-in\");\n\n // ── Handshake exchange ─────────────────────────────────────────────────\n const handshakeToken = req.nextUrl.searchParams.get(\"__vaultix_handshake\");\n if (handshakeToken && apiUrl) {\n const response = await handleHandshake(req, handshakeToken, apiUrl);\n if (response) return response;\n }\n\n // ── JWT verification ───────────────────────────────────────────────────\n let result: AuthResult = {\n userId: null, orgId: null, orgRole: null,\n sessionId: null, riskLevel: null,\n isSignedIn: false, isPublicRoute: publicRoute,\n };\n\n const token =\n req.cookies.get(\"vaultix-session\")?.value ??\n extractBearer(req.headers.get(\"authorization\") ?? \"\");\n\n if (token) {\n const verifyKey = await getVerifyKey(apiUrl);\n if (verifyKey) {\n try {\n const { payload } = await jwtVerify(token, verifyKey.key as Parameters<typeof jwtVerify>[1], {\n algorithms: [\"RS256\"],\n });\n result = {\n userId: (payload[\"uid\"] as string) ?? null,\n orgId: (payload[\"org\"] as string) ?? null,\n orgRole: (payload[\"rol\"] as string) ?? null,\n sessionId: (payload[\"sid\"] as string) ?? null,\n riskLevel: (payload[\"risk\"] as string) ?? \"low\",\n isSignedIn: true,\n isPublicRoute: publicRoute,\n };\n } catch {\n // expired / tampered\n }\n }\n }\n\n // ── Custom afterAuth hook ──────────────────────────────────────────────\n if (afterAuth) {\n const override = afterAuth(result, req);\n if (override) return override as NextResponse;\n }\n\n // ── Default: redirect unauthenticated to sign-in ───────────────────────\n if (!result.isSignedIn && !publicRoute) {\n const dest = new URL(signInUrl, req.url);\n dest.searchParams.set(\"redirect_url\", req.url);\n return NextResponse.redirect(dest);\n }\n\n // ── Inject auth headers for Server Components ──────────────────────────\n const next = new Headers(req.headers);\n if (result.userId) {\n next.set(HEADER_USER_ID, result.userId);\n next.set(HEADER_ORG_ID, result.orgId ?? \"\");\n next.set(HEADER_ORG_ROLE, result.orgRole ?? \"\");\n next.set(HEADER_SESSION_ID, result.sessionId ?? \"\");\n next.set(HEADER_RISK_LEVEL, result.riskLevel ?? \"low\");\n } else {\n [HEADER_USER_ID, HEADER_ORG_ID, HEADER_ORG_ROLE, HEADER_SESSION_ID, HEADER_RISK_LEVEL]\n .forEach((h) => next.delete(h));\n }\n\n return NextResponse.next({ request: { headers: next } });\n };\n}\n\nfunction extractBearer(header: string): string {\n return header.startsWith(\"Bearer \") ? header.slice(7) : \"\";\n}\n","// Server-only. Import from \"@vaultix.ai/nextjs/server\".\n// Never import this in Client Components.\nimport { cookies, headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\nimport { createRemoteJWKSet, importSPKI, jwtVerify } from \"jose\";\nimport type { VaultixOrganization, VaultixUser } from \"@vaultix.ai/react\";\nimport {\n HEADER_USER_ID,\n HEADER_ORG_ID,\n HEADER_ORG_ROLE,\n HEADER_SESSION_ID,\n HEADER_RISK_LEVEL,\n} from \"./middleware\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface AuthObject {\n userId: string | null;\n orgId: string | null;\n orgRole: string | null;\n sessionId: string | null;\n riskLevel: \"low\" | \"medium\" | \"high\" | \"critical\" | null;\n isSignedIn: boolean;\n /**\n * Throws a redirect if the user is not authenticated.\n * Usage: const { userId } = await auth(); — or call auth().then(a => a.protect())\n */\n protect: (redirectTo?: string) => void;\n}\n\n// ─── API URL resolution (mirrors middleware logic) ────────────────────────────\n\nfunction resolveApiUrl(): string {\n if (process.env.VAULTIX_API_URL) return process.env.VAULTIX_API_URL.replace(/\\/$/, \"\");\n const pk = process.env.NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY ?? \"\";\n if (!pk) return \"\";\n try {\n const parts = pk.split(\"_\");\n if (parts.length >= 4 && parts[0] === \"vaultix\" && parts[1] === \"pk\") {\n return atob(parts.slice(3).join(\"_\")).replace(/\\/$/, \"\");\n }\n } catch {}\n return \"\";\n}\n\n// ─── JWT verification (server-side, no edge constraints) ─────────────────────\n\nlet _remoteJwks: ReturnType<typeof createRemoteJWKSet> | null = null;\nlet _remoteJwksUrl: string | null = null;\nlet _staticKey: Awaited<ReturnType<typeof importSPKI>> | null = null;\nlet _staticPem: string | null = null;\n\nasync function verifyJwt(token: string) {\n // 1. Static PEM key (fastest, no network call)\n const pem = process.env.VAULTIX_JWT_PUBLIC_KEY;\n if (pem) {\n const normalized = pem.replace(/\\\\n/g, \"\\n\");\n if (!_staticKey || _staticPem !== normalized) {\n _staticKey = await importSPKI(normalized, \"RS256\");\n _staticPem = normalized;\n }\n try {\n const { payload } = await jwtVerify(token, _staticKey, { algorithms: [\"RS256\"] });\n return payload;\n } catch { return null; }\n }\n\n // 2. Remote JWKS (auto-fetched, cached)\n const apiUrl = resolveApiUrl();\n if (!apiUrl) return null;\n const jwksUrl = `${apiUrl}/api/v1/.well-known/jwks.json`;\n if (!_remoteJwks || _remoteJwksUrl !== jwksUrl) {\n _remoteJwks = createRemoteJWKSet(new URL(jwksUrl));\n _remoteJwksUrl = jwksUrl;\n }\n try {\n const { payload } = await jwtVerify(token, _remoteJwks, { algorithms: [\"RS256\"] });\n return payload;\n } catch { return null; }\n}\n\n// ─── auth() ───────────────────────────────────────────────────────────────────\n\n/**\n * Returns the current auth state. Works in Server Components, Route Handlers,\n * and Server Actions. Falls back to verifying the session cookie directly\n * if middleware headers are not present.\n *\n * @example\n * import { auth } from \"@vaultix.ai/nextjs/server\";\n *\n * export default async function Page() {\n * const { userId, protect } = await auth();\n * protect(); // redirects to sign-in if not authenticated\n * return <div>Hello {userId}</div>;\n * }\n */\nexport async function auth(): Promise<AuthObject> {\n function makeProtect(isSignedIn: boolean) {\n return (redirectTo?: string) => {\n if (!isSignedIn) {\n const apiUrl = resolveApiUrl();\n const dest = redirectTo ?? (apiUrl ? `${apiUrl}/auth/sign-in` : \"/sign-in\");\n redirect(dest);\n }\n };\n }\n\n // ── Fast path: headers injected by authMiddleware ──────────────────────\n const h = await headers();\n const userId = h.get(HEADER_USER_ID);\n if (userId) {\n return {\n userId,\n orgId: h.get(HEADER_ORG_ID) || null,\n orgRole: h.get(HEADER_ORG_ROLE) || null,\n sessionId: h.get(HEADER_SESSION_ID) || null,\n riskLevel: (h.get(HEADER_RISK_LEVEL) ?? \"low\") as AuthObject[\"riskLevel\"],\n isSignedIn: true,\n protect: makeProtect(true),\n };\n }\n\n // ── Fallback: verify session cookie directly (no middleware needed) ────\n const jar = await cookies();\n const token = jar.get(\"vaultix-session\")?.value;\n if (!token) {\n return {\n userId: null, orgId: null, orgRole: null,\n sessionId: null, riskLevel: null, isSignedIn: false,\n protect: makeProtect(false),\n };\n }\n\n const payload = await verifyJwt(token);\n if (!payload) {\n return {\n userId: null, orgId: null, orgRole: null,\n sessionId: null, riskLevel: null, isSignedIn: false,\n protect: makeProtect(false),\n };\n }\n\n return {\n userId: (payload[\"uid\"] as string) ?? null,\n orgId: (payload[\"org\"] as string) ?? null,\n orgRole: (payload[\"rol\"] as string) ?? null,\n sessionId: (payload[\"sid\"] as string) ?? null,\n riskLevel: ((payload[\"risk\"] as string) ?? \"low\") as AuthObject[\"riskLevel\"],\n isSignedIn: true,\n protect: makeProtect(true),\n };\n}\n\n// ─── currentUser() ────────────────────────────────────────────────────────────\n\n/**\n * Returns the full user record for the currently signed-in user.\n * Calls GET /api/v1/me using the session JWT from the cookie as a Bearer token.\n * No extra env vars required.\n *\n * @example\n * import { currentUser } from \"@vaultix.ai/nextjs/server\";\n *\n * export default async function Page() {\n * const user = await currentUser();\n * if (!user) redirect(\"/sign-in\");\n * return <div>Hello {user.email}</div>;\n * }\n */\nexport async function currentUser(): Promise<VaultixUser | null> {\n const jar = await cookies();\n const token = jar.get(\"vaultix-session\")?.value;\n if (!token) return null;\n\n const apiUrl = resolveApiUrl();\n if (!apiUrl) return null;\n\n try {\n const res = await fetch(`${apiUrl}/api/v1/me`, {\n headers: { Authorization: `Bearer ${token}` },\n cache: \"no-store\",\n });\n if (!res.ok) return null;\n const data = await res.json() as { user: VaultixUser };\n return data.user ?? null;\n } catch {\n return null;\n }\n}\n\n// ─── currentOrg() ────────────────────────────────────────────────────────────\n\n/**\n * Returns the active organization for the current user.\n * Requires VAULTIX_SECRET_KEY env var.\n */\nexport async function currentOrg(): Promise<VaultixOrganization | null> {\n const { orgId } = await auth();\n if (!orgId) return null;\n\n const apiUrl = resolveApiUrl();\n const secret = process.env.VAULTIX_SECRET_KEY;\n if (!apiUrl || !secret) return null;\n\n try {\n const res = await fetch(`${apiUrl}/api/v1/orgs/${orgId}`, {\n headers: { Authorization: `Bearer ${secret}` },\n next: { revalidate: 30 },\n } as RequestInit);\n if (!res.ok) return null;\n return (await res.json()) as VaultixOrganization;\n } catch {\n return null;\n }\n}\n\n// ─── protect() — standalone helper ───────────────────────────────────────────\n\n/**\n * Asserts the current user is authenticated. Redirects to sign-in if not.\n * Prefer calling `protect()` from the auth object returned by `auth()`.\n *\n * @example\n * import { protect } from \"@vaultix.ai/nextjs/server\";\n * export default async function Page() {\n * const { userId } = await protect();\n * return <div>{userId}</div>;\n * }\n */\nexport async function protect(redirectTo?: string): Promise<AuthObject> {\n const authObj = await auth();\n authObj.protect(redirectTo);\n return authObj;\n}\n","// @smritix.ai/nextjs — barrel export\n// Safe to import in all contexts (client, server, middleware).\n// For server-only utilities: import from \"@smritix.ai/nextjs/server\"\n// For the middleware factory: import from \"@smritix.ai/nextjs/middleware\"\n\n// ── Middleware ────────────────────────────────────────────────────────────────\nexport { authMiddleware } from \"./middleware\";\nexport type { AuthMiddlewareOptions, AuthResult } from \"./middleware\";\n\n// ── Server helpers ────────────────────────────────────────────────────────────\n// Re-exported for convenience; callers on client must use the explicit subpath.\nexport { auth, currentOrg, currentUser, protect } from \"./server\";\nexport type { AuthObject } from \"./server\";\n\n// ── Client SDK re-exports ─────────────────────────────────────────────────────\n// VaultixProvider, hooks, and UI components — safe for Client Components.\nexport {\n OrganizationSwitcher,\n SignIn,\n SignUp,\n VaultixProvider,\n UserButton,\n useOrganization,\n useSession,\n useVaultix,\n useUser,\n} from \"@vaultix.ai/react\";\n\nexport type {\n ChallengeType,\n RiskLevel,\n SessionClaims,\n VaultixContextValue,\n VaultixOrganization,\n VaultixProviderProps,\n VaultixSession,\n VaultixUser,\n} from \"@vaultix.ai/react\";\n"],"mappings":"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","names":["createRemoteJWKSet","importSPKI","jwtVerify","resolveApiUrl","importSPKI","jwtVerify","createRemoteJWKSet"]}
@@ -1,7 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
3
  interface AuthResult {
4
- /** Authenticated user ID (`sub` claim), or null if unauthenticated. */
5
4
  userId: string | null;
6
5
  orgId: string | null;
7
6
  orgRole: string | null;
@@ -13,22 +12,23 @@ interface AuthResult {
13
12
  interface AuthMiddlewareOptions {
14
13
  /**
15
14
  * Routes that do not require authentication.
16
- * Strings are matched by exact path or prefix (e.g. "/sign-in" or "/api/public/").
17
- * RegExps are tested against `pathname`.
15
+ * Strings: exact match or prefix. RegExps: tested against pathname.
18
16
  */
19
17
  publicRoutes?: Array<string | RegExp>;
20
- /** Where to redirect unauthenticated users. Default: "/sign-in". */
18
+ /**
19
+ * Where to redirect unauthenticated users.
20
+ * Defaults to the Vaultix hosted sign-in page (decoded from publishable key).
21
+ * Override with "/sign-in" to use your own page.
22
+ */
21
23
  signInUrl?: string;
22
24
  /**
23
- * Vaultix API origin required to exchange handshake tokens.
24
- * Falls back to VAULTIX_API_URL env var.
25
- * Example: "https://vaultix.smritix-ai.com"
25
+ * Vaultix API origin. Auto-decoded from NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY.
26
+ * Only needed if you're not using the standard publishable key format.
26
27
  */
27
28
  apiUrl?: string;
28
29
  /**
29
- * Custom logic after auth state is determined.
30
- * Return a `NextResponse` to short-circuit the default redirect behaviour;
31
- * return `undefined` to continue with defaults.
30
+ * Custom logic after auth state is resolved.
31
+ * Return a NextResponse to override default behaviour.
32
32
  */
33
33
  afterAuth?: (auth: AuthResult, req: NextRequest) => NextResponse | Response | undefined | void;
34
34
  }
@@ -38,15 +38,13 @@ declare const HEADER_ORG_ROLE = "x-vaultix-org-role";
38
38
  declare const HEADER_SESSION_ID = "x-vaultix-session-id";
39
39
  declare const HEADER_RISK_LEVEL = "x-vaultix-risk-level";
40
40
  /**
41
- * authMiddleware wraps your Next.js middleware.ts export.
41
+ * Drop-in auth middleware works with zero config when
42
+ * NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY is set.
42
43
  *
43
44
  * @example
44
45
  * // middleware.ts
45
46
  * import { authMiddleware } from "@vaultix.ai/nextjs/middleware";
46
- * export default authMiddleware({
47
- * apiUrl: "https://vaultix.smritix-ai.com",
48
- * publicRoutes: ["/sign-in", "/sign-up"],
49
- * });
47
+ * export default authMiddleware({ publicRoutes: ["/", "/about"] });
50
48
  * export const config = { matcher: ["/((?!_next|.*\\..*).*)"] };
51
49
  */
52
50
  declare function authMiddleware(options?: AuthMiddlewareOptions): (req: NextRequest) => Promise<NextResponse>;
@@ -1,7 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
3
  interface AuthResult {
4
- /** Authenticated user ID (`sub` claim), or null if unauthenticated. */
5
4
  userId: string | null;
6
5
  orgId: string | null;
7
6
  orgRole: string | null;
@@ -13,22 +12,23 @@ interface AuthResult {
13
12
  interface AuthMiddlewareOptions {
14
13
  /**
15
14
  * Routes that do not require authentication.
16
- * Strings are matched by exact path or prefix (e.g. "/sign-in" or "/api/public/").
17
- * RegExps are tested against `pathname`.
15
+ * Strings: exact match or prefix. RegExps: tested against pathname.
18
16
  */
19
17
  publicRoutes?: Array<string | RegExp>;
20
- /** Where to redirect unauthenticated users. Default: "/sign-in". */
18
+ /**
19
+ * Where to redirect unauthenticated users.
20
+ * Defaults to the Vaultix hosted sign-in page (decoded from publishable key).
21
+ * Override with "/sign-in" to use your own page.
22
+ */
21
23
  signInUrl?: string;
22
24
  /**
23
- * Vaultix API origin required to exchange handshake tokens.
24
- * Falls back to VAULTIX_API_URL env var.
25
- * Example: "https://vaultix.smritix-ai.com"
25
+ * Vaultix API origin. Auto-decoded from NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY.
26
+ * Only needed if you're not using the standard publishable key format.
26
27
  */
27
28
  apiUrl?: string;
28
29
  /**
29
- * Custom logic after auth state is determined.
30
- * Return a `NextResponse` to short-circuit the default redirect behaviour;
31
- * return `undefined` to continue with defaults.
30
+ * Custom logic after auth state is resolved.
31
+ * Return a NextResponse to override default behaviour.
32
32
  */
33
33
  afterAuth?: (auth: AuthResult, req: NextRequest) => NextResponse | Response | undefined | void;
34
34
  }
@@ -38,15 +38,13 @@ declare const HEADER_ORG_ROLE = "x-vaultix-org-role";
38
38
  declare const HEADER_SESSION_ID = "x-vaultix-session-id";
39
39
  declare const HEADER_RISK_LEVEL = "x-vaultix-risk-level";
40
40
  /**
41
- * authMiddleware wraps your Next.js middleware.ts export.
41
+ * Drop-in auth middleware works with zero config when
42
+ * NEXT_PUBLIC_VAULTIX_PUBLISHABLE_KEY is set.
42
43
  *
43
44
  * @example
44
45
  * // middleware.ts
45
46
  * import { authMiddleware } from "@vaultix.ai/nextjs/middleware";
46
- * export default authMiddleware({
47
- * apiUrl: "https://vaultix.smritix-ai.com",
48
- * publicRoutes: ["/sign-in", "/sign-up"],
49
- * });
47
+ * export default authMiddleware({ publicRoutes: ["/", "/about"] });
50
48
  * export const config = { matcher: ["/((?!_next|.*\\..*).*)"] };
51
49
  */
52
50
  declare function authMiddleware(options?: AuthMiddlewareOptions): (req: NextRequest) => Promise<NextResponse>;