/
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/account.mjs
(19527B)
import { parseAccountOutput } from "../../db/schema.mjs"; import { getAwaitableValue } from "../../context/helpers.mjs"; import { getAccountCookie, setAccountCookie } from "../../cookies/session-store.mjs"; import { generateState } from "../../oauth2/state.mjs"; import { decryptOAuthToken, setTokenUtil } from "../../oauth2/utils.mjs"; import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "./session.mjs"; import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error"; import { SocialProviderListEnum } from "@better-auth/core/social-providers"; import { createAuthEndpoint } from "@better-auth/core/api"; import * as z from "zod"; //#region src/api/routes/account.ts const listUserAccounts = createAuthEndpoint("/list-accounts", { method: "GET", use: [sessionMiddleware], metadata: { openapi: { operationId: "listUserAccounts", description: "List all accounts linked to the user", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "array", items: { type: "object", properties: { id: { type: "string" }, providerId: { type: "string" }, createdAt: { type: "string", format: "date-time" }, updatedAt: { type: "string", format: "date-time" }, accountId: { type: "string" }, userId: { type: "string" }, scopes: { type: "array", items: { type: "string" } } }, required: [ "id", "providerId", "createdAt", "updatedAt", "accountId", "userId", "scopes" ] } } } } } } } } }, async (c) => { const session = c.context.session; const accounts = await c.context.internalAdapter.findAccounts(session.user.id); return c.json(accounts.map((a) => { const { scope, ...parsed } = parseAccountOutput(c.context.options, a); return { ...parsed, scopes: scope?.split(",") || [] }; })); }); const linkSocialAccount = createAuthEndpoint("/link-social", { method: "POST", requireHeaders: true, body: z.object({ callbackURL: z.string().meta({ description: "The URL to redirect to after the user has signed in" }).optional(), provider: SocialProviderListEnum, idToken: z.object({ token: z.string(), nonce: z.string().optional(), accessToken: z.string().optional(), refreshToken: z.string().optional(), scopes: z.array(z.string()).optional() }).optional(), requestSignUp: z.boolean().optional(), scopes: z.array(z.string()).meta({ description: "Additional scopes to request from the provider" }).optional(), errorCallbackURL: z.string().meta({ description: "The URL to redirect to if there is an error during the link process" }).optional(), disableRedirect: z.boolean().meta({ description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself" }).optional(), additionalData: z.record(z.string(), z.any()).optional() }), use: [sessionMiddleware], metadata: { openapi: { description: "Link a social account to the user", operationId: "linkSocialAccount", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { url: { type: "string", description: "The authorization URL to redirect the user to" }, redirect: { type: "boolean", description: "Indicates if the user should be redirected to the authorization URL" }, status: { type: "boolean" } }, required: ["redirect"] } } } } } } } }, async (c) => { const session = c.context.session; const provider = await getAwaitableValue(c.context.socialProviders, { value: c.body.provider }); if (!provider) { c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider }); throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.PROVIDER_NOT_FOUND); } if (c.body.idToken) { if (!provider.verifyIdToken) { c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider }); throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED); } const { token, nonce } = c.body.idToken; if (!await provider.verifyIdToken(token, nonce)) { c.context.logger.error("Invalid id token", { provider: c.body.provider }); throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_TOKEN); } const linkingUserInfo = await provider.getUserInfo({ idToken: token, accessToken: c.body.idToken.accessToken, refreshToken: c.body.idToken.refreshToken }); if (!linkingUserInfo || !linkingUserInfo?.user) { c.context.logger.error("Failed to get user info", { provider: c.body.provider }); throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO); } const linkingUserId = String(linkingUserInfo.user.id); if (!linkingUserInfo.user.email) { c.context.logger.error("User email not found", { provider: c.body.provider }); throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND); } if ((await c.context.internalAdapter.findAccounts(session.user.id)).find((a) => a.providerId === provider.id && a.accountId === linkingUserId)) return c.json({ url: "", status: true, redirect: false }); if (!c.context.trustedProviders.includes(provider.id) && !linkingUserInfo.user.emailVerified || c.context.options.account?.accountLinking?.enabled === false) throw APIError.from("UNAUTHORIZED", { message: "Account not linked - linking not allowed", code: "LINKING_NOT_ALLOWED" }); if (linkingUserInfo.user.email?.toLowerCase() !== session.user.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) throw APIError.from("UNAUTHORIZED", { message: "Account not linked - different emails not allowed", code: "LINKING_DIFFERENT_EMAILS_NOT_ALLOWED" }); try { await c.context.internalAdapter.createAccount({ userId: session.user.id, providerId: provider.id, accountId: linkingUserId, accessToken: c.body.idToken.accessToken, idToken: token, refreshToken: c.body.idToken.refreshToken, scope: c.body.idToken.scopes?.join(",") }); } catch (_e) { throw APIError.from("EXPECTATION_FAILED", { message: "Account not linked - unable to create account", code: "LINKING_FAILED" }); } if (c.context.options.account?.accountLinking?.updateUserInfoOnLink === true) try { await c.context.internalAdapter.updateUser(session.user.id, { name: linkingUserInfo.user?.name, image: linkingUserInfo.user?.image }); } catch (e) { console.warn("Could not update user - " + e.toString()); } return c.json({ url: "", status: true, redirect: false }); } const state = await generateState(c, { userId: session.user.id, email: session.user.email }, c.body.additionalData); const url = await provider.createAuthorizationURL({ state: state.state, codeVerifier: state.codeVerifier, redirectURI: `${c.context.baseURL}/callback/${provider.id}`, scopes: c.body.scopes }); if (!c.body.disableRedirect) c.setHeader("Location", url.toString()); return c.json({ url: url.toString(), redirect: !c.body.disableRedirect }); }); const unlinkAccount = createAuthEndpoint("/unlink-account", { method: "POST", body: z.object({ providerId: z.string(), accountId: z.string().optional() }), use: [freshSessionMiddleware], metadata: { openapi: { description: "Unlink an account", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { status: { type: "boolean" } } } } } } } } } }, async (ctx) => { const { providerId, accountId } = ctx.body; const accounts = await ctx.context.internalAdapter.findAccounts(ctx.context.session.user.id); if (accounts.length === 1 && !ctx.context.options.account?.accountLinking?.allowUnlinkingAll) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT); const accountExist = accounts.find((account) => accountId ? account.accountId === accountId && account.providerId === providerId : account.providerId === providerId); if (!accountExist) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND); await ctx.context.internalAdapter.deleteAccount(accountExist.id); return ctx.json({ status: true }); }); const getAccessToken = createAuthEndpoint("/get-access-token", { method: "POST", body: z.object({ providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), userId: z.string().meta({ description: "The user ID associated with the account" }).optional() }), metadata: { openapi: { description: "Get a valid access token, doing a refresh if needed", responses: { 200: { description: "A Valid access token", content: { "application/json": { schema: { type: "object", properties: { tokenType: { type: "string" }, idToken: { type: "string" }, accessToken: { type: "string" }, accessTokenExpiresAt: { type: "string", format: "date-time" } } } } } }, 400: { description: "Invalid refresh token or provider configuration" } } } } }, async (ctx) => { const { providerId, accountId, userId } = ctx.body || {}; const req = ctx.request; const session = await getSessionFromCtx(ctx); if (req && !session) throw ctx.error("UNAUTHORIZED"); const resolvedUserId = session?.user?.id || userId; if (!resolvedUserId) throw ctx.error("UNAUTHORIZED"); const provider = await getAwaitableValue(ctx.context.socialProviders, { value: providerId }); if (!provider) throw APIError.from("BAD_REQUEST", { message: `Provider ${providerId} is not supported.`, code: "PROVIDER_NOT_SUPPORTED" }); const accountData = await getAccountCookie(ctx); let account = void 0; if (accountData && providerId === accountData.providerId && (!accountId || accountData.id === accountId)) account = accountData; else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.accountId === accountId && acc.providerId === providerId : acc.providerId === providerId); if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND); try { let newTokens = null; const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3; if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) { const refreshToken = await decryptOAuthToken(account.refreshToken, ctx.context); newTokens = await provider.refreshAccessToken(refreshToken); const updatedData = { accessToken: await setTokenUtil(newTokens?.accessToken, ctx.context), accessTokenExpiresAt: newTokens?.accessTokenExpiresAt, refreshToken: newTokens?.refreshToken ? await setTokenUtil(newTokens.refreshToken, ctx.context) : account.refreshToken, refreshTokenExpiresAt: newTokens?.refreshTokenExpiresAt ?? account.refreshTokenExpiresAt, idToken: newTokens?.idToken || account.idToken }; let updatedAccount = null; if (account.id) updatedAccount = await ctx.context.internalAdapter.updateAccount(account.id, updatedData); if (ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { ...account, ...updatedAccount ?? updatedData }); } const accessTokenExpiresAt = (() => { if (newTokens?.accessTokenExpiresAt) { if (typeof newTokens.accessTokenExpiresAt === "string") return new Date(newTokens.accessTokenExpiresAt); return newTokens.accessTokenExpiresAt; } if (account.accessTokenExpiresAt) { if (typeof account.accessTokenExpiresAt === "string") return new Date(account.accessTokenExpiresAt); return account.accessTokenExpiresAt; } })(); const tokens = { accessToken: newTokens?.accessToken ?? await decryptOAuthToken(account.accessToken ?? "", ctx.context), accessTokenExpiresAt, scopes: account.scope?.split(",") ?? [], idToken: newTokens?.idToken ?? account.idToken ?? void 0 }; return ctx.json(tokens); } catch (_error) { throw APIError.from("BAD_REQUEST", { message: "Failed to get a valid access token", code: "FAILED_TO_GET_ACCESS_TOKEN" }); } }); const refreshToken = createAuthEndpoint("/refresh-token", { method: "POST", body: z.object({ providerId: z.string().meta({ description: "The provider ID for the OAuth provider" }), accountId: z.string().meta({ description: "The account ID associated with the refresh token" }).optional(), userId: z.string().meta({ description: "The user ID associated with the account" }).optional() }), metadata: { openapi: { description: "Refresh the access token using a refresh token", responses: { 200: { description: "Access token refreshed successfully", content: { "application/json": { schema: { type: "object", properties: { tokenType: { type: "string" }, idToken: { type: "string" }, accessToken: { type: "string" }, refreshToken: { type: "string" }, accessTokenExpiresAt: { type: "string", format: "date-time" }, refreshTokenExpiresAt: { type: "string", format: "date-time" } } } } } }, 400: { description: "Invalid refresh token or provider configuration" } } } } }, async (ctx) => { const { providerId, accountId, userId } = ctx.body; const req = ctx.request; const session = await getSessionFromCtx(ctx); if (req && !session) throw ctx.error("UNAUTHORIZED"); const resolvedUserId = session?.user?.id || userId; if (!resolvedUserId) throw APIError.from("BAD_REQUEST", { message: `Either userId or session is required`, code: "USER_ID_OR_SESSION_REQUIRED" }); const provider = await getAwaitableValue(ctx.context.socialProviders, { value: providerId }); if (!provider) throw APIError.from("BAD_REQUEST", { message: `Provider ${providerId} is not supported.`, code: "PROVIDER_NOT_SUPPORTED" }); if (!provider.refreshAccessToken) throw APIError.from("BAD_REQUEST", { message: `Provider ${providerId} does not support token refreshing.`, code: "TOKEN_REFRESH_NOT_SUPPORTED" }); let account = void 0; const accountData = await getAccountCookie(ctx); if (accountData && (!providerId || providerId === accountData?.providerId)) account = accountData; else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.accountId === accountId && acc.providerId === providerId : acc.providerId === providerId); if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND); let refreshToken = void 0; if (accountData && providerId === accountData.providerId) refreshToken = accountData.refreshToken ?? void 0; else refreshToken = account.refreshToken ?? void 0; if (!refreshToken) throw APIError.from("BAD_REQUEST", { message: "Refresh token not found", code: "REFRESH_TOKEN_NOT_FOUND" }); try { const decryptedRefreshToken = await decryptOAuthToken(refreshToken, ctx.context); const tokens = await provider.refreshAccessToken(decryptedRefreshToken); const resolvedRefreshToken = tokens.refreshToken ? await setTokenUtil(tokens.refreshToken, ctx.context) : refreshToken; const resolvedRefreshTokenExpiresAt = tokens.refreshTokenExpiresAt ?? account.refreshTokenExpiresAt; if (account.id) { const updateData = { ...account || {}, accessToken: await setTokenUtil(tokens.accessToken, ctx.context), refreshToken: resolvedRefreshToken, accessTokenExpiresAt: tokens.accessTokenExpiresAt, refreshTokenExpiresAt: resolvedRefreshTokenExpiresAt, scope: tokens.scopes?.join(",") || account.scope, idToken: tokens.idToken || account.idToken }; await ctx.context.internalAdapter.updateAccount(account.id, updateData); } if (accountData && providerId === accountData.providerId && ctx.context.options.account?.storeAccountCookie) await setAccountCookie(ctx, { ...accountData, accessToken: await setTokenUtil(tokens.accessToken, ctx.context), refreshToken: resolvedRefreshToken, accessTokenExpiresAt: tokens.accessTokenExpiresAt, refreshTokenExpiresAt: resolvedRefreshTokenExpiresAt, scope: tokens.scopes?.join(",") || accountData.scope, idToken: tokens.idToken || accountData.idToken }); return ctx.json({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken ?? decryptedRefreshToken, accessTokenExpiresAt: tokens.accessTokenExpiresAt, refreshTokenExpiresAt: resolvedRefreshTokenExpiresAt, scope: tokens.scopes?.join(",") || account.scope, idToken: tokens.idToken || account.idToken, providerId: account.providerId, accountId: account.accountId }); } catch (_error) { throw APIError.from("BAD_REQUEST", { message: "Failed to refresh access token", code: "FAILED_TO_REFRESH_ACCESS_TOKEN" }); } }); const accountInfoQuerySchema = z.optional(z.object({ accountId: z.string().meta({ description: "The provider given account id for which to get the account info" }).optional() })); const accountInfo = createAuthEndpoint("/account-info", { method: "GET", use: [sessionMiddleware], metadata: { openapi: { description: "Get the account info provided by the provider", responses: { "200": { description: "Success", content: { "application/json": { schema: { type: "object", properties: { user: { type: "object", properties: { id: { type: "string" }, name: { type: "string" }, email: { type: "string" }, image: { type: "string" }, emailVerified: { type: "boolean" } }, required: ["id", "emailVerified"] }, data: { type: "object", properties: {}, additionalProperties: true } }, required: ["user", "data"], additionalProperties: false } } } } } } }, query: accountInfoQuerySchema }, async (ctx) => { const providedAccountId = ctx.query?.accountId; let account = void 0; if (!providedAccountId) { if (ctx.context.options.account?.storeAccountCookie) { const accountData = await getAccountCookie(ctx); if (accountData) account = accountData; } } else { const accountData = await ctx.context.internalAdapter.findAccount(providedAccountId); if (accountData) account = accountData; } if (!account || account.userId !== ctx.context.session.user.id) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND); const provider = await getAwaitableValue(ctx.context.socialProviders, { value: account.providerId }); if (!provider) throw APIError.from("INTERNAL_SERVER_ERROR", { message: `Provider account provider is ${account.providerId} but it is not configured`, code: "PROVIDER_NOT_CONFIGURED" }); const tokens = await getAccessToken({ ...ctx, method: "POST", body: { accountId: account.accountId, providerId: account.providerId }, returnHeaders: false, returnStatus: false }); if (!tokens.accessToken) throw APIError.from("BAD_REQUEST", { message: "Access token not found", code: "ACCESS_TOKEN_NOT_FOUND" }); const info = await provider.getUserInfo({ ...tokens, accessToken: tokens.accessToken }); return ctx.json(info); }); //#endregion export { accountInfo, getAccessToken, linkSocialAccount, listUserAccounts, refreshToken, unlinkAccount }; //# sourceMappingURL=account.mjs.map
Save
cmd:
run