next-lite-auth 0.2.4 → 0.2.5

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
@@ -128,6 +128,17 @@ export const config = {
128
128
  };
129
129
  ```
130
130
 
131
+ Use `nonProtected` to keep specific pages public even when `protect` covers all routes:
132
+
133
+ ```ts
134
+ export default middleware({
135
+ protect: ["/"],
136
+ nonProtected: ["/docs", "/privacy-policy", "/terms"],
137
+ });
138
+ ```
139
+
140
+ `nonProtected` is checked first — matching routes always pass through, regardless of `protect`.
141
+
131
142
  ---
132
143
 
133
144
  ## Use anywhere
package/dist/index.d.mts CHANGED
@@ -22,6 +22,7 @@ declare function createLiteAuth(config: LiteAuthConfig): {
22
22
  };
23
23
  middleware: (options: {
24
24
  protect: (string | RegExp)[];
25
+ nonProtected?: (string | RegExp)[];
25
26
  redirectTo?: string;
26
27
  }) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
27
28
  getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ declare function createLiteAuth(config: LiteAuthConfig): {
22
22
  };
23
23
  middleware: (options: {
24
24
  protect: (string | RegExp)[];
25
+ nonProtected?: (string | RegExp)[];
25
26
  redirectTo?: string;
26
27
  }) => (req: next_server.NextRequest) => Promise<next_server.NextResponse>;
27
28
  getUserFromCookies: (cookies: next_dist_server_web_spec_extension_adapters_request_cookies.ReadonlyRequestCookies) => Promise<PublicUser | null>;
package/dist/index.js CHANGED
@@ -126,8 +126,11 @@ function makeMiddleware(ctx) {
126
126
  return function middleware(options) {
127
127
  return async function(req) {
128
128
  if (!ctx.enabled) return import_server2.NextResponse.next();
129
- const { protect, redirectTo = "/login" } = options;
129
+ const { protect, nonProtected = [], redirectTo = "/login" } = options;
130
130
  const { pathname } = req.nextUrl;
131
+ if (nonProtected.length > 0 && matchesProtect(nonProtected, pathname)) {
132
+ return import_server2.NextResponse.next();
133
+ }
131
134
  const isProtected = matchesProtect(protect, pathname);
132
135
  if (!isProtected) {
133
136
  return import_server2.NextResponse.next();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["export { createLiteAuth } from \"./core/createLiteAuth\";\nexport { usersFromEnv } from \"./core/usersFromEnv\";\nexport type { User, PublicUser, LiteAuthConfig } from \"./core/types\";\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeHandlers(ctx: LiteAuthContext) {\n async function login(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.next();\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":"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","names":["import_server"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["export { createLiteAuth } from \"./core/createLiteAuth\";\nexport { usersFromEnv } from \"./core/usersFromEnv\";\nexport type { User, PublicUser, LiteAuthConfig } from \"./core/types\";\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeHandlers(ctx: LiteAuthContext) {\n async function login(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\n nonProtected?: (string | RegExp)[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.next();\n const { protect, nonProtected = [], redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n if (nonProtected.length > 0 && matchesProtect(nonProtected, pathname)) {\n return NextResponse.next();\n }\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":"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","names":["import_server"]}
package/dist/index.mjs CHANGED
@@ -99,8 +99,11 @@ function makeMiddleware(ctx) {
99
99
  return function middleware(options) {
100
100
  return async function(req) {
101
101
  if (!ctx.enabled) return NextResponse2.next();
102
- const { protect, redirectTo = "/login" } = options;
102
+ const { protect, nonProtected = [], redirectTo = "/login" } = options;
103
103
  const { pathname } = req.nextUrl;
104
+ if (nonProtected.length > 0 && matchesProtect(nonProtected, pathname)) {
105
+ return NextResponse2.next();
106
+ }
104
107
  const isProtected = matchesProtect(protect, pathname);
105
108
  if (!isProtected) {
106
109
  return NextResponse2.next();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeHandlers(ctx: LiteAuthContext) {\n async function login(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.next();\n const { protect, redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
1
+ {"version":3,"sources":["../src/server/handlers.ts","../src/server/jwt.ts","../src/server/getUserFromCookies.ts","../src/middleware/index.ts","../src/core/matchesProtect.ts","../src/core/createLiteAuth.ts","../src/core/usersFromEnv.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { signToken, verifyToken } from \"./jwt\";\n\nexport function makeHandlers(ctx: LiteAuthContext) {\n async function login(req: NextRequest): Promise<NextResponse> {\n let body: { email?: string; password?: string };\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n const { email, password } = body;\n if (!email || !password) {\n return NextResponse.json({ error: \"Email and password are required\" }, { status: 400 });\n }\n\n const user = ctx.users.find((u) => u.email === email && u.password === password);\n if (!user) {\n return NextResponse.json({ error: \"Invalid credentials\" }, { status: 401 });\n }\n\n const { password: _, ...publicUser } = user;\n const token = await signToken(publicUser, ctx.jwtSecret);\n\n const res = NextResponse.json({ user: publicUser });\n res.cookies.set(ctx.cookieName, token, {\n httpOnly: true,\n path: \"/\",\n sameSite: \"lax\",\n secure: process.env.NODE_ENV === \"production\",\n maxAge: 60 * 60 * 24 * 7,\n });\n return res;\n }\n\n async function logout(_req: NextRequest): Promise<NextResponse> {\n const res = NextResponse.json({ ok: true });\n res.cookies.set(ctx.cookieName, \"\", { httpOnly: true, path: \"/\", maxAge: 0 });\n return res;\n }\n\n async function me(req: NextRequest): Promise<NextResponse> {\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (!token) return NextResponse.json({ user: null }, { status: 401 });\n const user = await verifyToken(token, ctx.jwtSecret);\n if (!user) return NextResponse.json({ user: null }, { status: 401 });\n return NextResponse.json({ user });\n }\n\n async function GET(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ user: null });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"me\") return me(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n async function POST(req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.json({ ok: true });\n const action = req.nextUrl.pathname.split(\"/\").pop();\n if (action === \"login\") return login(req);\n if (action === \"logout\") return logout(req);\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n }\n\n return { GET, POST };\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { PublicUser } from \"../core/types\";\n\nfunction getSecret(secret: string) {\n return new TextEncoder().encode(secret);\n}\n\nexport async function signToken(user: PublicUser, secret: string): Promise<string> {\n return new SignJWT({ ...user })\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(\"7d\")\n .sign(getSecret(secret));\n}\n\nexport async function verifyToken(token: string, secret: string): Promise<PublicUser | null> {\n try {\n const { payload } = await jwtVerify(token, getSecret(secret));\n return payload as unknown as PublicUser;\n } catch {\n return null;\n }\n}\n","import { ReadonlyRequestCookies } from \"next/dist/server/web/spec-extension/adapters/request-cookies\";\nimport { LiteAuthContext, PublicUser } from \"../core/types\";\nimport { verifyToken } from \"./jwt\";\n\nexport function getUserFromCookies(ctx: LiteAuthContext) {\n return async function (cookies: ReadonlyRequestCookies): Promise<PublicUser | null> {\n const token = cookies.get(ctx.cookieName)?.value;\n if (!token) return null;\n return verifyToken(token, ctx.jwtSecret);\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { LiteAuthContext } from \"../core/types\";\nimport { verifyToken } from \"../server/jwt\";\nimport { matchesProtect } from \"../core/matchesProtect\";\n\ntype MiddlewareOptions = {\n protect: (string | RegExp)[];\n nonProtected?: (string | RegExp)[];\n redirectTo?: string;\n};\n\nexport function makeMiddleware(ctx: LiteAuthContext) {\n return function middleware(options: MiddlewareOptions) {\n return async function (req: NextRequest): Promise<NextResponse> {\n if (!ctx.enabled) return NextResponse.next();\n const { protect, nonProtected = [], redirectTo = \"/login\" } = options;\n const { pathname } = req.nextUrl;\n\n if (nonProtected.length > 0 && matchesProtect(nonProtected, pathname)) {\n return NextResponse.next();\n }\n\n const isProtected = matchesProtect(protect, pathname);\n\n if (!isProtected) {\n return NextResponse.next();\n }\n\n const token = req.cookies.get(ctx.cookieName)?.value;\n if (token) {\n const user = await verifyToken(token, ctx.jwtSecret);\n if (user) return NextResponse.next();\n }\n\n const loginUrl = new URL(redirectTo, req.url);\n loginUrl.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(loginUrl);\n };\n };\n}\n","export function matchesProtect(patterns: (string | RegExp)[], pathname: string): boolean {\n return patterns.some((p) =>\n p instanceof RegExp\n ? p.test(pathname)\n : p === \"/\" || pathname === p || pathname.startsWith(p + \"/\")\n );\n}\n","import { LiteAuthConfig, LiteAuthContext } from \"./types\";\nimport { makeHandlers, getUserFromCookies } from \"../server\";\nimport { makeMiddleware } from \"../middleware\";\n\nexport function createLiteAuth(config: LiteAuthConfig) {\n const ctx: LiteAuthContext = {\n users: config.users,\n jwtSecret: config.jwtSecret,\n cookieName: config.cookieName ?? \"lite-auth-token\",\n enabled: config.enabled ?? true,\n };\n\n return {\n handlers: makeHandlers(ctx),\n middleware: makeMiddleware(ctx),\n getUserFromCookies: getUserFromCookies(ctx),\n };\n}\n","import { User } from \"./types\";\n\nexport function usersFromEnv(): User[] {\n const raw = process.env.LITE_AUTH_USERS;\n\n if (!raw) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS environment variable is not set. \" +\n \"Set it to a JSON array of users, e.g.: \" +\n 'LITE_AUTH_USERS=\\'[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]\\''\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS is not valid JSON. \" +\n \"Expected a JSON array of users.\"\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n \"[next-lite-auth] LITE_AUTH_USERS must be a JSON array, e.g.: \" +\n '[{\"email\":\"admin@example.com\",\"password\":\"secret\"}]'\n );\n }\n\n return parsed as User[];\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-lite-auth",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Lightweight JWT auth for Next.js using static JSON users (no database)",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",