/
opt
/
canhelp
/
node_modules
/
better-auth
/
dist
/
api
/
routes
/
/opt/canhelp/node_modules/better-auth/dist/api/routes
mkdir
upload
Name
Size
Mode
Actions
account.d.mts
11924
0644
edit
dl
rm
account.mjs
19527
0644
edit
dl
rm
account.mjs.map
40509
0644
edit
dl
rm
callback.d.mts
1014
0644
edit
dl
rm
callback.mjs
6979
0644
edit
dl
rm
callback.mjs.map
13572
0644
edit
dl
rm
email-verification.d.mts
4080
0644
edit
dl
rm
email-verification.mjs
11402
0644
edit
dl
rm
email-verification.mjs.map
23367
0644
edit
dl
rm
error.d.mts
603
0644
edit
dl
rm
error.mjs
12968
0644
edit
dl
rm
error.mjs.map
17009
0644
edit
dl
rm
index.d.mts
1044
0644
edit
dl
rm
index.mjs
1058
0644
edit
dl
rm
ok.d.mts
773
0644
edit
dl
rm
ok.mjs
704
0644
edit
dl
rm
ok.mjs.map
1424
0644
edit
dl
rm
password.d.mts
4514
0644
edit
dl
rm
password.mjs
8458
0644
edit
dl
rm
password.mjs.map
16864
0644
edit
dl
rm
session.d.mts
11608
0644
edit
dl
rm
session.mjs
18652
0644
edit
dl
rm
session.mjs.map
40494
0644
edit
dl
rm
sign-in.d.mts
7353
0644
edit
dl
rm
sign-in.mjs
10948
0644
edit
dl
rm
sign-in.mjs.map
25364
0644
edit
dl
rm
sign-out.d.mts
788
0644
edit
dl
rm
sign-out.mjs
1026
0644
edit
dl
rm
sign-out.mjs.map
2010
0644
edit
dl
rm
sign-up.d.mts
4657
0644
edit
dl
rm
sign-up.mjs
9719
0644
edit
dl
rm
sign-up.mjs.map
20386
0644
edit
dl
rm
update-session.d.mts
1991
0644
edit
dl
rm
update-session.mjs
1984
0644
edit
dl
rm
update-session.mjs.map
4018
0644
edit
dl
rm
update-user.d.mts
11568
0644
edit
dl
rm
update-user.mjs
19158
0644
edit
dl
rm
update-user.mjs.map
39053
0644
edit
dl
rm
Edit:
/opt/canhelp/node_modules/better-auth/dist/api/routes/session.mjs
(18652B)
import { isAPIError } from "../../utils/is-api-error.mjs"; import { getDate } from "../../utils/date.mjs"; import { parseSessionOutput, parseUserOutput } from "../../db/schema.mjs"; import "../../db/index.mjs"; import { symmetricDecodeJWT, verifyJWT } from "../../crypto/jwt.mjs"; import "../../crypto/index.mjs"; import { getChunkedCookie, getSessionQuerySchema } from "../../cookies/session-store.mjs"; import { deleteSessionCookie, expireCookie, setCookieCache, setSessionCookie } from "../../cookies/index.mjs"; import { getShouldSkipSessionRefresh } from "../state/should-session-refresh.mjs"; import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error"; import { safeJSONParse } from "@better-auth/core/utils/json"; import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api"; import * as z from "zod"; import { base64Url } from "@better-auth/utils/base64"; import { binary } from "@better-auth/utils/binary"; import { createHMAC } from "@better-auth/utils/hmac"; //#region src/api/routes/session.ts const getSession = () => createAuthEndpoint("/get-session", { method: ["GET", "POST"], operationId: "getSession", query: getSessionQuerySchema, requireHeaders: true, metadata: { openapi: { operationId: "getSession", description: "Get the current session", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", nullable: true, properties: { session: { $ref: "#/components/schemas/Session" }, user: { $ref: "#/components/schemas/User" } }, required: ["session", "user"] } } } } } } } }, async (ctx) => { const deferSessionRefresh = ctx.context.options.session?.deferSessionRefresh; const isPostRequest = ctx.method === "POST"; if (isPostRequest && !deferSessionRefresh) throw APIError.from("METHOD_NOT_ALLOWED", BASE_ERROR_CODES.METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED); try { const sessionCookieToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret); if (!sessionCookieToken) return null; const sessionDataCookie = getChunkedCookie(ctx, ctx.context.authCookies.sessionData.name); let sessionDataPayload = null; if (sessionDataCookie) { const strategy = ctx.context.options.session?.cookieCache?.strategy || "compact"; if (strategy === "jwe") { const payload = await symmetricDecodeJWT(sessionDataCookie, ctx.context.secretConfig, "better-auth-session"); if (payload && payload.session && payload.user) sessionDataPayload = { session: { session: payload.session, user: payload.user, updatedAt: payload.updatedAt, version: payload.version }, expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() }; else { expireCookie(ctx, ctx.context.authCookies.sessionData); return ctx.json(null); } } else if (strategy === "jwt") { const payload = await verifyJWT(sessionDataCookie, ctx.context.secret); if (payload && payload.session && payload.user) sessionDataPayload = { session: { session: payload.session, user: payload.user, updatedAt: payload.updatedAt, version: payload.version }, expiresAt: payload.exp ? payload.exp * 1e3 : Date.now() }; else { expireCookie(ctx, ctx.context.authCookies.sessionData); return ctx.json(null); } } else { const parsed = safeJSONParse(binary.decode(base64Url.decode(sessionDataCookie))); if (parsed) if (await createHMAC("SHA-256", "base64urlnopad").verify(ctx.context.secret, JSON.stringify({ ...parsed.session, expiresAt: parsed.expiresAt }), parsed.signature)) sessionDataPayload = parsed; else { expireCookie(ctx, ctx.context.authCookies.sessionData); return ctx.json(null); } } } const dontRememberMe = await ctx.getSignedCookie(ctx.context.authCookies.dontRememberToken.name, ctx.context.secret); /** * If session data is present in the cookie, check if it should be used or refreshed */ if (sessionDataPayload?.session && ctx.context.options.session?.cookieCache?.enabled && !ctx.query?.disableCookieCache) { const session = sessionDataPayload.session; const versionConfig = ctx.context.options.session?.cookieCache?.version; let expectedVersion = "1"; if (versionConfig) { if (typeof versionConfig === "string") expectedVersion = versionConfig; else if (typeof versionConfig === "function") { const result = versionConfig(session.session, session.user); expectedVersion = result instanceof Promise ? await result : result; } } if ((session.version || "1") !== expectedVersion) expireCookie(ctx, ctx.context.authCookies.sessionData); else { const cachedSessionExpiresAt = new Date(session.session.expiresAt); if (sessionDataPayload.expiresAt < Date.now() || cachedSessionExpiresAt < /* @__PURE__ */ new Date()) expireCookie(ctx, ctx.context.authCookies.sessionData); else { const cookieRefreshCache = ctx.context.sessionConfig.cookieRefreshCache; if (cookieRefreshCache === false) { ctx.context.session = session; const parsedSession = parseSessionOutput(ctx.context.options, { ...session.session, expiresAt: new Date(session.session.expiresAt), createdAt: new Date(session.session.createdAt), updatedAt: new Date(session.session.updatedAt) }); const parsedUser = parseUserOutput(ctx.context.options, { ...session.user, createdAt: new Date(session.user.createdAt), updatedAt: new Date(session.user.updatedAt) }); return ctx.json({ session: parsedSession, user: parsedUser }); } const timeUntilExpiry = sessionDataPayload.expiresAt - Date.now(); const updateAge = cookieRefreshCache.updateAge * 1e3; const shouldSkipSessionRefresh = await getShouldSkipSessionRefresh(); if (timeUntilExpiry < updateAge && !shouldSkipSessionRefresh) { const newExpiresAt = getDate(ctx.context.options.session?.cookieCache?.maxAge || 300, "sec"); const refreshedSession = { session: { ...session.session, expiresAt: newExpiresAt }, user: session.user, updatedAt: Date.now() }; await setCookieCache(ctx, refreshedSession, false); const sessionTokenOptions = ctx.context.authCookies.sessionToken.attributes; const sessionTokenMaxAge = dontRememberMe ? void 0 : ctx.context.sessionConfig.expiresIn; await ctx.setSignedCookie(ctx.context.authCookies.sessionToken.name, session.session.token, ctx.context.secret, { ...sessionTokenOptions, maxAge: sessionTokenMaxAge }); const parsedRefreshedSession = parseSessionOutput(ctx.context.options, { ...refreshedSession.session, expiresAt: new Date(refreshedSession.session.expiresAt), createdAt: new Date(refreshedSession.session.createdAt), updatedAt: new Date(refreshedSession.session.updatedAt) }); const parsedRefreshedUser = parseUserOutput(ctx.context.options, { ...refreshedSession.user, createdAt: new Date(refreshedSession.user.createdAt), updatedAt: new Date(refreshedSession.user.updatedAt) }); ctx.context.session = { session: parsedRefreshedSession, user: parsedRefreshedUser }; return ctx.json({ session: parsedRefreshedSession, user: parsedRefreshedUser }); } const parsedSession = parseSessionOutput(ctx.context.options, { ...session.session, expiresAt: new Date(session.session.expiresAt), createdAt: new Date(session.session.createdAt), updatedAt: new Date(session.session.updatedAt) }); const parsedUser = parseUserOutput(ctx.context.options, { ...session.user, createdAt: new Date(session.user.createdAt), updatedAt: new Date(session.user.updatedAt) }); ctx.context.session = { session: parsedSession, user: parsedUser }; return ctx.json({ session: parsedSession, user: parsedUser }); } } } const session = await ctx.context.internalAdapter.findSession(sessionCookieToken); ctx.context.session = session; if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) { deleteSessionCookie(ctx); if (session) { /** * if session expired clean up the session * Only delete on POST when deferSessionRefresh is enabled */ if (!deferSessionRefresh || isPostRequest) await ctx.context.internalAdapter.deleteSession(session.session.token); } return ctx.json(null); } /** * We don't need to update the session if the user doesn't want to be remembered * or if the session refresh is disabled */ if (dontRememberMe || ctx.query?.disableRefresh) { const parsedSession = parseSessionOutput(ctx.context.options, session.session); const parsedUser = parseUserOutput(ctx.context.options, session.user); return ctx.json({ session: parsedSession, user: parsedUser }); } const expiresIn = ctx.context.sessionConfig.expiresIn; const updateAge = ctx.context.sessionConfig.updateAge; const shouldBeUpdated = session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3 <= Date.now(); const disableRefresh = ctx.query?.disableRefresh || ctx.context.options.session?.disableSessionRefresh; const shouldSkipSessionRefresh = await getShouldSkipSessionRefresh(); const needsRefresh = shouldBeUpdated && !disableRefresh && !shouldSkipSessionRefresh; /** * When deferSessionRefresh is enabled and this is a GET request, * return the session without performing writes, but include needsRefresh flag */ if (deferSessionRefresh && !isPostRequest) { await setCookieCache(ctx, session, !!dontRememberMe); const parsedSession = parseSessionOutput(ctx.context.options, session.session); const parsedUser = parseUserOutput(ctx.context.options, session.user); return ctx.json({ session: parsedSession, user: parsedUser, needsRefresh }); } if (needsRefresh) { const updatedSession = await ctx.context.internalAdapter.updateSession(session.session.token, { expiresAt: getDate(ctx.context.sessionConfig.expiresIn, "sec"), updatedAt: /* @__PURE__ */ new Date() }); if (!updatedSession) { /** * Handle case where session update fails (e.g., concurrent deletion) */ deleteSessionCookie(ctx); throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_GET_SESSION); } const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3; await setSessionCookie(ctx, { session: updatedSession, user: session.user }, false, { maxAge }); const parsedUpdatedSession = parseSessionOutput(ctx.context.options, updatedSession); const parsedUser = parseUserOutput(ctx.context.options, session.user); return ctx.json({ session: parsedUpdatedSession, user: parsedUser }); } await setCookieCache(ctx, session, !!dontRememberMe); const parsedSession = parseSessionOutput(ctx.context.options, session.session); const parsedUser = parseUserOutput(ctx.context.options, session.user); return ctx.json({ session: parsedSession, user: parsedUser }); } catch (error) { if (isAPIError(error)) throw error; ctx.context.logger.error("INTERNAL_SERVER_ERROR", error); throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.FAILED_TO_GET_SESSION); } }); const getSessionFromCtx = async (ctx, config) => { if (ctx.context.session) return ctx.context.session; const session = await getSession()({ ...ctx, method: "GET", asResponse: false, headers: ctx.headers, returnHeaders: false, returnStatus: false, query: { ...config, ...ctx.query } }).catch((e) => { return null; }); ctx.context.session = session; return session; }; /** * The middleware forces the endpoint to require a valid session. */ const sessionMiddleware = createAuthMiddleware(async (ctx) => { const session = await getSessionFromCtx(ctx); if (!session?.session) throw APIError.from("UNAUTHORIZED", { message: "Unauthorized", code: "UNAUTHORIZED" }); return { session }; }); /** * This middleware forces the endpoint to require a valid session and ignores cookie cache. * This should be used for sensitive operations like password changes, account deletion, etc. * to ensure that revoked sessions cannot be used even if they're still cached in cookies. */ const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => { const session = await getSessionFromCtx(ctx, { disableCookieCache: true }); if (!session?.session) throw APIError.from("UNAUTHORIZED", { message: "Unauthorized", code: "UNAUTHORIZED" }); return { session }; }); /** * This middleware allows you to call the endpoint on the client if session is valid. * However, if called on the server, no session is required. */ const requestOnlySessionMiddleware = createAuthMiddleware(async (ctx) => { const session = await getSessionFromCtx(ctx); if (!session?.session && (ctx.request || ctx.headers)) throw APIError.from("UNAUTHORIZED", { message: "Unauthorized", code: "UNAUTHORIZED" }); return { session }; }); /** * This middleware forces the endpoint to require a valid session, * as well as making sure the session is fresh before proceeding. * * Session freshness check will be skipped if the session config's freshAge * is set to 0 */ const freshSessionMiddleware = createAuthMiddleware(async (ctx) => { const session = await getSessionFromCtx(ctx); if (!session?.session) throw APIError.from("UNAUTHORIZED", { message: "Unauthorized", code: "UNAUTHORIZED" }); if (ctx.context.sessionConfig.freshAge === 0) return { session }; const freshAge = ctx.context.sessionConfig.freshAge; const lastUpdated = new Date(session.session.updatedAt || session.session.createdAt).getTime(); if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.SESSION_NOT_FRESH); return { session }; }); /** * user active sessions list */ const listSessions = () => createAuthEndpoint("/list-sessions", { method: "GET", operationId: "listUserSessions", use: [sessionMiddleware], requireHeaders: true, metadata: { openapi: { operationId: "listUserSessions", description: "List all active sessions for the user", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/Session" } } } } } } } } }, async (ctx) => { try { const activeSessions = (await ctx.context.internalAdapter.listSessions(ctx.context.session.user.id, { onlyActiveSessions: true })).filter((session) => { return session.expiresAt > /* @__PURE__ */ new Date(); }); return ctx.json(activeSessions.map((session) => parseSessionOutput(ctx.context.options, session))); } catch (e) { ctx.context.logger.error(e); throw ctx.error("INTERNAL_SERVER_ERROR"); } }); /** * revoke a single session */ const revokeSession = createAuthEndpoint("/revoke-session", { method: "POST", body: z.object({ token: z.string().meta({ description: "The token to revoke" }) }), use: [sensitiveSessionMiddleware], requireHeaders: true, metadata: { openapi: { description: "Revoke a single session", requestBody: { content: { "application/json": { schema: { type: "object", properties: { token: { type: "string", description: "The token to revoke" } }, required: ["token"] } } } }, responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { status: { type: "boolean", description: "Indicates if the session was revoked successfully" } }, required: ["status"] } } } } } } } }, async (ctx) => { const token = ctx.body.token; if ((await ctx.context.internalAdapter.findSession(token))?.session.userId === ctx.context.session.user.id) try { await ctx.context.internalAdapter.deleteSession(token); } catch (error) { ctx.context.logger.error(error && typeof error === "object" && "name" in error ? error.name : "", error); throw APIError.from("INTERNAL_SERVER_ERROR", { message: "Internal Server Error", code: "INTERNAL_SERVER_ERROR" }); } return ctx.json({ status: true }); }); /** * revoke all user sessions */ const revokeSessions = createAuthEndpoint("/revoke-sessions", { method: "POST", use: [sensitiveSessionMiddleware], requireHeaders: true, metadata: { openapi: { description: "Revoke all sessions for the user", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { status: { type: "boolean", description: "Indicates if all sessions were revoked successfully" } }, required: ["status"] } } } } } } } }, async (ctx) => { try { await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id); } catch (error) { ctx.context.logger.error(error && typeof error === "object" && "name" in error ? error.name : "", error); throw APIError.from("INTERNAL_SERVER_ERROR", { message: "Internal Server Error", code: "INTERNAL_SERVER_ERROR" }); } return ctx.json({ status: true }); }); const revokeOtherSessions = createAuthEndpoint("/revoke-other-sessions", { method: "POST", requireHeaders: true, use: [sensitiveSessionMiddleware], metadata: { openapi: { description: "Revoke all other sessions for the user except the current one", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { status: { type: "boolean", description: "Indicates if all other sessions were revoked successfully" } }, required: ["status"] } } } } } } } }, async (ctx) => { const session = ctx.context.session; if (!session.user) throw APIError.from("UNAUTHORIZED", { message: "Unauthorized", code: "UNAUTHORIZED" }); const otherSessions = (await ctx.context.internalAdapter.listSessions(session.user.id)).filter((session) => { return session.expiresAt > /* @__PURE__ */ new Date(); }).filter((session) => session.token !== ctx.context.session.session.token); await Promise.all(otherSessions.map((session) => ctx.context.internalAdapter.deleteSession(session.token))); return ctx.json({ status: true }); }); //#endregion export { freshSessionMiddleware, getSession, getSessionFromCtx, listSessions, requestOnlySessionMiddleware, revokeOtherSessions, revokeSession, revokeSessions, sensitiveSessionMiddleware, sessionMiddleware }; //# sourceMappingURL=session.mjs.map
Save
cmd:
run