@light-auth/astro
Version:
light auth framework for astro, using arctic
261 lines (253 loc) • 11.1 kB
JavaScript
/*! @light-auth/astro v0.3.1 2025-06-13 */
;
import { createFetchUserServerFunction, createSigninServerFunction, createSignoutServerFunction, createHttpHandlerFunction, resolveBasePath, createSetUserServerFunction, createSetSessionServerFunction, createFetchSessionServerFunction, buildFullUrl, encryptJwt, buildSecret, getSessionExpirationMaxAge, DEFAULT_SESSION_NAME, decryptJwt } from '@light-auth/core';
import * as cookieParser from 'cookie';
const createGetAuthSession = (config) => {
const getSession = createFetchSessionServerFunction(config);
return async (context) => await getSession({ context });
};
const createSetAuthSession = (config) => {
const setSession = createSetSessionServerFunction(config);
return async (context, session) => await setSession({ context, session });
};
const createGetAuthUser = (config) => {
const getUser = createFetchUserServerFunction(config);
return async (context, providerUserId) => await getUser({ providerUserId, context });
};
const createSetAuthUser = (config) => {
const setUser = createSetUserServerFunction(config);
return async (context, user) => await setUser({ context, user });
};
function createSignin(config) {
const signInFunction = createSigninServerFunction(config);
return async (context, providerName, callbackUrl = "/") => {
return await signInFunction({ providerName, callbackUrl, context });
};
}
function createSignout(config) {
const signOutFunction = createSignoutServerFunction(config);
return async (context, revokeToken = false, callbackUrl = "/") => {
return await signOutFunction({ revokeToken, callbackUrl, context });
};
}
const createHandler = (config) => {
const lightAuthHandler = createHttpHandlerFunction(config);
return {
GET: async (context) => {
const response = await lightAuthHandler({ context });
return response;
},
POST: async (context) => {
const response = await lightAuthHandler({ context });
return response;
},
};
};
function CreateLightAuth(config) {
// check if we are on the server side
const isServerSide = typeof window === "undefined";
if (!isServerSide)
throw new Error("light-auth-nextjs: DO NOT use this function [CreateLightAuth] on the client side as you may expose sensitive data to the client.");
if (!config.providers || config.providers.length === 0)
throw new Error("At least one provider is required");
// dynamic imports to avoid error if we are on the client side
if (!config.userAdapter && typeof window === "undefined") {
import('@light-auth/core/adapters').then((module) => {
config.userAdapter = module.createLightAuthUserAdapter({ base: "./users_db", isEncrypted: false });
});
}
if (!config.sessionStore && typeof window === "undefined") {
Promise.resolve().then(function () { return astroLightAuthSessionStore$1; }).then((module) => {
config.sessionStore = module.astroLightAuthSessionStore;
});
}
if (!config.router && typeof window === "undefined") {
Promise.resolve().then(function () { return astroLightAuthRouter$1; }).then((module) => {
config.router = module.astroLightAuthRouter;
});
}
// @ts-ignore
config.env = config.env || import.meta.env;
config.basePath = resolveBasePath(config.basePath, config.env);
if (!config.env || !config.env["LIGHT_AUTH_SECRET_VALUE"])
throw new Error("LIGHT_AUTH_SECRET_VALUE is required in environment variables");
return {
providers: config.providers,
handlers: createHandler(config),
basePath: config.basePath,
getAuthSession: createGetAuthSession(config),
setAuthSession: createSetAuthSession(config),
getUser: createGetAuthUser(config),
setUser: createSetAuthUser(config),
signIn: createSignin(config),
signOut: createSignout(config),
};
}
const astroLightAuthRouter = {
returnJson: function ({ data, context, init }) {
const json = data ? JSON.stringify(data) : undefined;
const status = init?.status ?? 200;
return new Response(json, {
...(init ?? {}),
status,
});
},
getUrl: function ({ endpoint, context, req }) {
const request = context?.request ?? req;
let url = endpoint;
if (!url)
url = context?.request?.url || req?.url;
if (!url)
throw new Error("light-auth: No url provided and no request object available in getUrl of astroLightAuthRouter.");
if (url.startsWith("http"))
return url;
const isServerSide = typeof window === "undefined";
if (!isServerSide)
return url;
if (!request)
return url;
const parsedUrl = buildFullUrl({ url, incomingHeaders: request.headers });
return parsedUrl.toString();
},
redirectTo: function ({ url, context }) {
if (!context)
throw new Error("AstroSharedContext is required in redirectTo function of astroLightAuthRouter");
return context.redirect(url, 302);
},
getHeaders: function ({ search, context, req }) {
const request = context?.request ?? req;
if (!request)
return new Headers();
const incomingHeaders = request.headers;
// Convert search to RegExp if it's a string
const regex = typeof search === "string" ? new RegExp(search) : search;
// Create a new Headers object to hold filtered headers
const filteredHeaders = new Headers();
// Iterate and filter headers whose names match the regex
for (const [key, value] of incomingHeaders.entries()) {
if (!search || !regex)
filteredHeaders.append(key, value);
else if (regex.test(key)) {
filteredHeaders.append(key, value);
}
}
return filteredHeaders;
},
setCookies: function ({ cookies, context }) {
if (!context)
throw new Error("AstroSharedContext is required in setCookies of expressLightAuthRouter");
for (const cookie of cookies ?? []) {
context.cookies.set(cookie.name, cookie.value, {
httpOnly: cookie.httpOnly,
secure: cookie.secure,
sameSite: cookie.sameSite,
maxAge: cookie.maxAge,
path: cookie.path,
});
}
},
getCookies: function ({ search, context }) {
if (!context)
throw new Error("AstroSharedContext is required in getCookies of expressLightAuthRouter");
const cookies = [];
const regex = typeof search === "string" ? new RegExp(search) : search;
for (const cookieString of context.cookies.headers()) {
const cookie = cookieParser.parse(cookieString);
const name = Object.keys(cookie)[0];
const value = cookie[name];
if (!search || !regex || regex.test(name))
cookies.push({ name: name, value: value || "" });
}
const cookieString = context.request?.headers?.get("cookie");
if (cookieString) {
const cookie = cookieParser.parse(cookieString);
for (const cookieString of Object.entries(cookie)) {
const [name, value] = cookieString;
if (!search || !regex || regex.test(name))
cookies.push({ name: name, value: value || "" });
}
}
return cookies;
},
getRequest: function ({ context }) {
if (!context)
throw new Error("AstroSharedContext is required in getRequest of expressLightAuthRouter");
return context.request;
},
};
var astroLightAuthRouter$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
astroLightAuthRouter: astroLightAuthRouter
});
/**
* A concrete CookieStore implementation for Node.js server-side,
* using the 'cookie' npm package and returning Response objects
* with appropriate Set-Cookie headers.
*/
const astroLightAuthSessionStore = {
async getSession(args) {
const { env, context, req } = args;
if (!env)
throw new Error("light-auth: Env is required in getSession of astroLightAuthSessionStore");
const request = context?.request || req;
if (!request)
throw new Error("light-auth: Request is required in getSession of astroLightAuthSessionStore");
const cookieHeader = request.headers.get("cookie");
if (!cookieHeader)
return null;
const requestCookies = cookieParser.parse(cookieHeader);
const sessionCookie = requestCookies[DEFAULT_SESSION_NAME];
if (!sessionCookie)
return null;
try {
const decryptedSession = await decryptJwt(sessionCookie, buildSecret(env));
return decryptedSession;
}
catch (error) {
console.error("Failed to decrypt session cookie:", error);
return null;
}
},
async deleteSession(args) {
const { env, context } = args;
if (!env)
throw new Error("light-auth: Env is required in deleteSession of astroLightAuthSessionStore");
if (!context)
throw new Error("light-auth: Context is required in deleteSession of astroLightAuthSessionStore");
context.cookies.set(DEFAULT_SESSION_NAME, "", {
maxAge: 0,
path: "/",
});
},
async setSession(args) {
const { env, session, context } = args;
if (!context)
throw new Error("light-auth: Context is required in setSession of astroLightAuthSessionStore");
const value = await encryptJwt(session, buildSecret(env));
// Check the size of the cookie value in bytes
const encoder = new TextEncoder();
const valueBytes = encoder.encode(value);
if (valueBytes.length > 4096)
throw new Error("light-auth: Cookie value exceeds 4096 bytes, which may not be supported by your browser.");
// get the cookie expiration time
const maxAge = getSessionExpirationMaxAge(); // 30 days if no env var is set
// maxAge: Specifies the number (in seconds) to be the value for the `Max-Age`
context.cookies.set(DEFAULT_SESSION_NAME, value, {
httpOnly: true,
secure: true,
sameSite: "lax",
path: "/",
maxAge: maxAge,
});
return session;
},
generateSessionId() {
return Math.random().toString(36).slice(2);
},
};
var astroLightAuthSessionStore$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
astroLightAuthSessionStore: astroLightAuthSessionStore
});
export { CreateLightAuth, astroLightAuthRouter, astroLightAuthSessionStore, createGetAuthUser, createHandler, createSignin, createSignout };
//# sourceMappingURL=index.mjs.map