@thecodeorigin/auth 0.0.10 → 0.0.12

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.
Files changed (46) hide show
  1. package/README.md +137 -72
  2. package/dist/contract/index.d.mts +80 -3
  3. package/dist/contract/index.d.ts +80 -3
  4. package/dist/contract/index.mjs +34 -2
  5. package/dist/module.d.mts +4 -0
  6. package/dist/module.d.ts +4 -0
  7. package/dist/module.json +1 -1
  8. package/dist/module.mjs +33 -12
  9. package/dist/runtime/app/composables/useAuth.d.ts +5 -0
  10. package/dist/runtime/app/composables/useAuth.js +50 -10
  11. package/dist/runtime/app/composables/useAuthLogin.d.ts +11 -0
  12. package/dist/runtime/app/composables/useAuthLogin.js +73 -0
  13. package/dist/runtime/app/middleware/auth.global.js +2 -0
  14. package/dist/runtime/app/plugins/session-sync.client.d.ts +2 -0
  15. package/dist/runtime/app/plugins/session-sync.client.js +47 -0
  16. package/dist/runtime/app/utils/return-path.d.ts +1 -0
  17. package/dist/runtime/app/utils/return-path.js +18 -0
  18. package/dist/runtime/app/utils/session-recovery.d.ts +5 -0
  19. package/dist/runtime/app/utils/session-recovery.js +23 -0
  20. package/dist/runtime/server/api/_auth/impersonate.post.d.ts +1 -0
  21. package/dist/runtime/server/api/_auth/impersonate.post.js +47 -27
  22. package/dist/runtime/server/api/_auth/organizations/switch.post.d.ts +1 -0
  23. package/dist/runtime/server/api/_auth/organizations/switch.post.js +12 -17
  24. package/dist/runtime/server/api/_auth/session-restore.get.d.ts +5 -0
  25. package/dist/runtime/server/api/_auth/session-restore.get.js +6 -0
  26. package/dist/runtime/server/api/_auth/session.get.d.ts +1 -0
  27. package/dist/runtime/server/api/_auth/sign-out.post.js +3 -0
  28. package/dist/runtime/server/api/_auth/stop-impersonating.post.d.ts +1 -0
  29. package/dist/runtime/server/api/_auth/stop-impersonating.post.js +18 -16
  30. package/dist/runtime/server/index.d.ts +2 -2
  31. package/dist/runtime/server/index.js +1 -1
  32. package/dist/runtime/server/routes/callback.get.js +62 -32
  33. package/dist/runtime/server/routes/sign-in.get.js +8 -6
  34. package/dist/runtime/server/routes/sign-out.get.d.ts +1 -0
  35. package/dist/runtime/server/routes/sign-out.get.js +4 -8
  36. package/dist/runtime/server/utils/idp.d.ts +2 -7
  37. package/dist/runtime/server/utils/idp.js +16 -64
  38. package/dist/runtime/server/utils/integration-key.d.ts +18 -0
  39. package/dist/runtime/server/utils/local-auth.d.ts +351 -0
  40. package/dist/runtime/server/utils/local-auth.js +43 -0
  41. package/dist/runtime/server/utils/oidc.d.ts +23 -2
  42. package/dist/runtime/server/utils/oidc.js +82 -5
  43. package/dist/runtime/server/utils/session.d.ts +30 -9
  44. package/dist/runtime/server/utils/session.js +189 -61
  45. package/dist/runtime/types.d.ts +12 -0
  46. package/package.json +9 -33
@@ -1,10 +1,10 @@
1
- import { defineEventHandler, deleteCookie, getCookie, getQuery, sendRedirect } from "h3";
1
+ import { defineEventHandler, deleteCookie, getCookie, getQuery, sendRedirect, setResponseHeader } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
3
  import { z } from "zod";
4
4
  import { UserinfoClaimsSchema } from "../../../contract";
5
5
  import { clearLogoutIntent } from "../utils/logout-intent.js";
6
- import { callbackRedirectUri, exchangeCode, fetchUserinfo, safePath } from "../utils/oidc.js";
7
- import { newSessionId, setSessionCookie, writeSessionRecord } from "../utils/session.js";
6
+ import { assertPendingAuthentication, callbackRedirectUri, clearPendingAuthentication, decodeTransaction, exchangeCode, fetchUserinfo, safePath, transactionCookieName, verifyIdToken } from "../utils/oidc.js";
7
+ import { issueSession } from "../utils/session.js";
8
8
  const RawUserinfoSchema = UserinfoClaimsSchema.extend({
9
9
  sub: z.string(),
10
10
  email: z.string().optional(),
@@ -15,20 +15,39 @@ const RawUserinfoSchema = UserinfoClaimsSchema.extend({
15
15
  export default defineEventHandler(async (event) => {
16
16
  const { public: { auth: publicRuntimeConfig } } = useRuntimeConfig();
17
17
  const q = getQuery(event);
18
- const fail = (e) => sendRedirect(event, `${publicRuntimeConfig.routes.error}?error=${encodeURIComponent(e)}`);
19
- if (q.error)
20
- return fail(String(q.error));
21
- const state = getCookie(event, "tco_state");
22
- const verifier = getCookie(event, "tco_verifier");
23
- const redirectTo = safePath(getCookie(event, "tco_redirect"), publicRuntimeConfig.routes.home);
24
- for (const c of ["tco_state", "tco_verifier", "tco_redirect"])
25
- deleteCookie(event, c, { path: publicRuntimeConfig.routes.callback });
26
- if (!q.code || !q.state || !state || q.state !== state || !verifier)
18
+ setResponseHeader(event, "cache-control", "no-store");
19
+ let redirectTo = publicRuntimeConfig.routes.home;
20
+ let verifiedTransaction = false;
21
+ const fail = async (error) => {
22
+ if (verifiedTransaction)
23
+ await clearPendingAuthentication(event, typeof q.state === "string" ? q.state : void 0);
24
+ const query = new URLSearchParams({ error, redirect: redirectTo });
25
+ return sendRedirect(event, `${publicRuntimeConfig.routes.error}?${query}`);
26
+ };
27
+ if (typeof q.state !== "string" || !/^[\w-]{32}$/.test(q.state))
28
+ return fail("invalid_state");
29
+ const cookieName = transactionCookieName(q.state);
30
+ const transactionValue = getCookie(event, cookieName);
31
+ deleteCookie(event, cookieName, { path: publicRuntimeConfig.routes.callback });
32
+ if (!transactionValue)
33
+ return fail("invalid_state");
34
+ let transaction;
35
+ try {
36
+ transaction = await decodeTransaction(transactionValue, q.state);
37
+ await assertPendingAuthentication(event, q.state, transaction.flowId);
38
+ verifiedTransaction = true;
39
+ } catch {
40
+ return fail("invalid_state");
41
+ }
42
+ redirectTo = safePath(transaction.redirect, publicRuntimeConfig.routes.home);
43
+ if (typeof q.error === "string")
44
+ return fail(q.error);
45
+ if (typeof q.code !== "string")
27
46
  return fail("invalid_state");
28
47
  let tokens;
29
48
  let userinfoRaw;
30
49
  try {
31
- tokens = await exchangeCode(String(q.code), verifier, callbackRedirectUri(event));
50
+ tokens = await exchangeCode(q.code, transaction.verifier, callbackRedirectUri(event));
32
51
  userinfoRaw = await fetchUserinfo(tokens.access_token);
33
52
  } catch (err) {
34
53
  const detail = err instanceof Error ? err.message : String(err);
@@ -42,25 +61,36 @@ export default defineEventHandler(async (event) => {
42
61
  const verified = u.email_verified === true || u.email_verified === "true";
43
62
  if (!u.sub || !u.email || !verified)
44
63
  return fail("email_unverified");
45
- const id = newSessionId();
46
- await writeSessionRecord(id, {
47
- sub: u.sub,
48
- user: { sub: u.sub, email: u.email, name: u.name ?? null, picture: u.picture ?? null },
49
- abilities: u.abilities,
50
- systemRole: u.role,
51
- organizations: u.organizations,
52
- activeOrg: u.org,
53
- entitlement: u.entitlement,
54
- accessToken: tokens.access_token,
55
- refreshToken: tokens.refresh_token ?? null,
56
- idToken: tokens.id_token ?? null,
57
- accessExpiresAt: Date.now() + (tokens.expires_in ?? 3600) * 1e3,
58
- authorizationRefreshedAt: Date.now(),
59
- isImpersonation: false,
60
- impersonator: null,
61
- backupId: null
62
- });
63
- await setSessionCookie(event, id);
64
+ try {
65
+ if (!tokens.id_token)
66
+ return fail("id_token_missing");
67
+ await verifyIdToken(tokens.id_token, transaction.nonce, u.sub);
68
+ } catch {
69
+ return fail("id_token_invalid");
70
+ }
71
+ const organizationAuthorizations = { ...u.organizationAuthorizations };
72
+ if (u.org && !Object.hasOwn(organizationAuthorizations, u.org))
73
+ organizationAuthorizations[u.org] = u.abilities;
74
+ try {
75
+ await issueSession(event, {
76
+ sub: u.sub,
77
+ user: { sub: u.sub, email: u.email, name: u.name ?? null, picture: u.picture ?? null },
78
+ abilities: u.abilities,
79
+ organizationAuthorizations,
80
+ systemRole: u.role,
81
+ organizations: u.organizations,
82
+ activeOrg: u.org,
83
+ entitlement: u.entitlement,
84
+ accessToken: tokens.access_token,
85
+ accessExpiresAt: Date.now() + (tokens.expires_in ?? 3600) * 1e3,
86
+ isImpersonation: false,
87
+ impersonator: null,
88
+ backupId: null
89
+ }, { validate: () => assertPendingAuthentication(event, q.state, transaction.flowId) });
90
+ } catch {
91
+ return fail("authentication_canceled");
92
+ }
93
+ await clearPendingAuthentication(event, typeof q.state === "string" ? q.state : void 0);
64
94
  clearLogoutIntent(event);
65
95
  return sendRedirect(event, redirectTo);
66
96
  });
@@ -1,29 +1,31 @@
1
- import { createError, defineEventHandler, getQuery, sendRedirect, setCookie } from "h3";
1
+ import { createError, defineEventHandler, getQuery, getRequestURL, sendRedirect, setCookie, setResponseHeader } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
3
  import { withQuery } from "ufo";
4
4
  import { clearLogoutIntent } from "../utils/logout-intent.js";
5
- import { callbackRedirectUri, idpBaseUrl, pkceChallenge, randomString, safePath } from "../utils/oidc.js";
5
+ import { beginAuthentication, callbackRedirectUri, encodeTransaction, idpBaseUrl, pkceChallenge, randomString, safePath, transactionCookieName } from "../utils/oidc.js";
6
6
  const ALLOWED_PROMPTS = /* @__PURE__ */ new Set(["login", "select_account", "consent", "none"]);
7
7
  export default defineEventHandler(async (event) => {
8
8
  const { auth: runtimeConfig, public: { auth: publicRuntimeConfig } } = useRuntimeConfig();
9
9
  if (!publicRuntimeConfig.domain || !publicRuntimeConfig.clientId || !runtimeConfig.clientSecret)
10
10
  throw createError({ statusCode: 503, statusMessage: "Auth not configured" });
11
+ setResponseHeader(event, "cache-control", "no-store");
11
12
  clearLogoutIntent(event);
12
13
  const query = getQuery(event);
13
14
  const state = randomString(32);
14
15
  const verifier = randomString(64);
16
+ const nonce = randomString(32);
17
+ const flowId = await beginAuthentication(event, state);
15
18
  const redirectTo = safePath(query.redirect, publicRuntimeConfig.routes.home);
16
19
  const prompt = typeof query.prompt === "string" && ALLOWED_PROMPTS.has(query.prompt) ? query.prompt : void 0;
17
- const opts = { httpOnly: true, secure: !import.meta.dev, sameSite: "lax", maxAge: 600, path: publicRuntimeConfig.routes.callback };
18
- setCookie(event, "tco_state", state, opts);
19
- setCookie(event, "tco_verifier", verifier, opts);
20
- setCookie(event, "tco_redirect", redirectTo, opts);
20
+ const opts = { httpOnly: true, secure: getRequestURL(event).protocol === "https:", sameSite: "lax", maxAge: 600, path: publicRuntimeConfig.routes.callback };
21
+ setCookie(event, transactionCookieName(state), await encodeTransaction({ state, verifier, nonce, redirect: redirectTo, flowId }), opts);
21
22
  return sendRedirect(event, withQuery(`${idpBaseUrl()}/api/auth/oauth2/authorize`, {
22
23
  client_id: publicRuntimeConfig.clientId,
23
24
  redirect_uri: callbackRedirectUri(event),
24
25
  response_type: "code",
25
26
  scope: publicRuntimeConfig.scopes.join(" "),
26
27
  state,
28
+ nonce,
27
29
  code_challenge: await pkceChallenge(verifier),
28
30
  code_challenge_method: "S256",
29
31
  ...prompt ? { prompt } : {}
@@ -1,2 +1,3 @@
1
+ /** A navigation cannot revoke authentication; logout is a same-origin POST. */
1
2
  declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
2
3
  export default _default;
@@ -1,10 +1,6 @@
1
- import { defineEventHandler, sendRedirect } from "h3";
1
+ import { defineEventHandler, sendRedirect, setResponseHeader } from "h3";
2
2
  import { useRuntimeConfig } from "nitropack/runtime";
3
- import { setLogoutIntent } from "../utils/logout-intent.js";
4
- import { destroySession } from "../utils/session.js";
5
- export default defineEventHandler(async (event) => {
6
- const { public: { auth: publicRuntimeConfig } } = useRuntimeConfig();
7
- await destroySession(event);
8
- setLogoutIntent(event);
9
- return sendRedirect(event, publicRuntimeConfig.routes.home);
3
+ export default defineEventHandler((event) => {
4
+ setResponseHeader(event, "cache-control", "no-store");
5
+ return sendRedirect(event, useRuntimeConfig().public.auth.routes.login);
10
6
  });
@@ -1,12 +1,7 @@
1
1
  import type { H3Event } from 'h3';
2
- import type { OrganizationContext } from '../../../contract/index.js';
3
2
  import type { SessionRecord } from './session.js';
4
- export declare function refreshAuthorizationContext(event: H3Event, id: string, rec: SessionRecord): Promise<OrganizationContext>;
5
- /**
6
- * Call an IdP path with the session's bearer token. Refreshes once on expiry/401.
7
- * Persists the rotated record. Returns parsed JSON.
8
- */
9
- export declare function idpFetch<T>(event: H3Event, id: string, rec: SessionRecord, path: string, opts?: {
3
+ /** Explicit online directory/support operation; never refresh or mutate local authentication. */
4
+ export declare function idpFetch<T>(_event: H3Event, _id: string, rec: SessionRecord, path: string, opts?: {
10
5
  method?: string;
11
6
  body?: Record<string, unknown>;
12
7
  query?: Record<string, string | number>;
@@ -1,70 +1,22 @@
1
1
  import { createError } from "h3";
2
- import { useRuntimeConfig } from "nitropack/runtime";
3
2
  import { $fetch } from "ofetch";
4
3
  import { idpBaseUrl } from "./oidc.js";
5
- import { readSessionRecordById, writeSessionRecord } from "./session.js";
6
- const SKEW_MS = 6e4;
7
- export async function refreshAuthorizationContext(event, id, rec) {
8
- if (!rec.activeOrg)
9
- throw createError({ statusCode: 403, statusMessage: "No active organization" });
10
- return idpFetch(
11
- event,
12
- id,
13
- rec,
14
- "/api/auth/rp/organizations/context",
15
- { method: "POST", body: { organizationId: rec.activeOrg } }
16
- );
17
- }
18
- async function refresh(rec) {
19
- if (rec.isImpersonation || !rec.refreshToken)
20
- return false;
21
- const { auth: runtimeConfig, public: { auth: publicRuntimeConfig } } = useRuntimeConfig();
22
- try {
23
- const t = await $fetch(
24
- `${idpBaseUrl()}/api/auth/oauth2/token`,
25
- {
26
- method: "POST",
27
- headers: {
28
- "Content-Type": "application/x-www-form-urlencoded",
29
- "Authorization": `Basic ${btoa(`${publicRuntimeConfig.clientId}:${runtimeConfig.clientSecret}`)}`
30
- },
31
- body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: rec.refreshToken }).toString()
32
- }
33
- );
34
- rec.accessToken = t.access_token;
35
- rec.refreshToken = t.refresh_token ?? rec.refreshToken;
36
- rec.accessExpiresAt = Date.now() + (t.expires_in ?? 3600) * 1e3;
37
- return true;
38
- } catch {
39
- return false;
40
- }
41
- }
42
- export async function idpFetch(event, id, rec, path, opts = {}) {
43
- if (!rec.isImpersonation && Date.now() > rec.accessExpiresAt - SKEW_MS) {
44
- if (await refresh(rec))
45
- await writeSessionRecord(id, rec);
46
- }
47
- const call = () => $fetch(`${idpBaseUrl()}${path}`, {
48
- method: opts.method,
49
- body: opts.body,
50
- query: opts.query,
51
- headers: { Authorization: `Bearer ${rec.accessToken}` }
52
- });
4
+ export async function idpFetch(_event, _id, rec, path, opts = {}) {
5
+ if (!rec.accessToken || Date.now() >= rec.accessExpiresAt)
6
+ throw createError({ statusCode: 409, statusMessage: "Sign in again to use this identity service operation" });
53
7
  try {
54
- return await call();
55
- } catch (e) {
56
- const status = e?.response?.status;
57
- if (status !== 401)
58
- throw e;
59
- const fresh = await readSessionRecordById(id);
60
- if (fresh && fresh.accessToken !== rec.accessToken) {
61
- Object.assign(rec, fresh);
62
- return call();
63
- }
64
- if (await refresh(rec)) {
65
- await writeSessionRecord(id, rec);
66
- return call();
67
- }
68
- throw createError({ statusCode: 401, statusMessage: "Session expired" });
8
+ return await $fetch(`${idpBaseUrl()}${path}`, {
9
+ method: opts.method,
10
+ body: opts.body,
11
+ query: opts.query,
12
+ headers: { Authorization: `Bearer ${rec.accessToken}` },
13
+ timeout: 1e4,
14
+ retry: 0
15
+ });
16
+ } catch (error) {
17
+ const status = error.response?.status;
18
+ if (status === 401)
19
+ throw createError({ statusCode: 409, statusMessage: "Sign in again to use this identity service operation" });
20
+ throw error;
69
21
  }
70
22
  }
@@ -1,5 +1,22 @@
1
1
  import type { H3Event } from 'h3';
2
2
  export declare function verifyOrganizationIntegrationKey(_event: H3Event, key: string): Promise<{
3
+ keyId: string;
4
+ organizationId: string;
5
+ version: 2;
6
+ clientId: string;
7
+ audience: "vault";
8
+ createdBy: string;
9
+ capabilities: {
10
+ resourceType: "environment";
11
+ resourceId: string;
12
+ actions: ("secrets:read" | "secrets:create")[];
13
+ keyPrefixes?: string[] | undefined;
14
+ }[];
15
+ permissions: ("secrets:read" | "secrets:create")[];
16
+ name: string;
17
+ prefix: string;
18
+ expiresAt: number;
19
+ } | {
3
20
  keyId: string;
4
21
  organizationId: string;
5
22
  clientId: string;
@@ -10,4 +27,5 @@ export declare function verifyOrganizationIntegrationKey(_event: H3Event, key: s
10
27
  name: string;
11
28
  prefix: string;
12
29
  expiresAt: number | null;
30
+ createdBy?: string | undefined;
13
31
  }>;
@@ -0,0 +1,351 @@
1
+ import type { BetterAuthOptions } from 'better-auth';
2
+ export interface LocalIdentity {
3
+ sub: string;
4
+ email: string;
5
+ name: string | null;
6
+ picture: string | null;
7
+ }
8
+ export interface LocalSessionInput {
9
+ user: LocalIdentity;
10
+ expiresAt: number;
11
+ snapshot: string;
12
+ }
13
+ /** A fresh instance keeps the temporary identity adapter isolated per request. */
14
+ export declare function createLocalAuth(options: BetterAuthOptions, input?: LocalSessionInput): import("better-auth").Auth<{
15
+ account: {
16
+ storeAccountCookie: false;
17
+ };
18
+ session: {
19
+ disableSessionRefresh: true;
20
+ storeSessionInDatabase: false;
21
+ cookieCache: {
22
+ enabled: false;
23
+ };
24
+ additionalFields: {
25
+ snapshot: {
26
+ type: "string";
27
+ required: true;
28
+ input: false;
29
+ };
30
+ };
31
+ modelName?: "session" | import("better-auth").LiteralString | undefined;
32
+ fields?: Partial<Record<"expiresAt" | "createdAt" | "updatedAt" | "userId" | "token" | "ipAddress" | "userAgent", string>> | undefined;
33
+ expiresIn?: number;
34
+ updateAge?: number;
35
+ deferSessionRefresh?: boolean;
36
+ preserveSessionInDatabase?: boolean;
37
+ freshAge?: number;
38
+ };
39
+ plugins: [{
40
+ id: "application-session";
41
+ endpoints: {
42
+ establishLocalSession: import("better-auth").StrictEndpoint<"/internal-establish-local-session", {
43
+ method: "POST";
44
+ }, {
45
+ token: string;
46
+ }>;
47
+ };
48
+ }];
49
+ appName?: string | undefined;
50
+ baseURL?: import("better-auth").BaseURLConfig | undefined;
51
+ basePath?: string | undefined;
52
+ secret?: string | undefined;
53
+ secrets?: Array<{
54
+ version: number;
55
+ value: string;
56
+ }> | undefined;
57
+ database?: (any) | undefined;
58
+ secondaryStorage?: import("better-auth").SecondaryStorage | undefined;
59
+ emailVerification?: {
60
+ sendVerificationEmail?: (data: {
61
+ user: import("better-auth").User;
62
+ url: string;
63
+ token: string;
64
+ }, request?: Request) => Promise<void>;
65
+ sendOnSignUp?: boolean;
66
+ sendOnSignIn?: boolean;
67
+ autoSignInAfterVerification?: boolean;
68
+ expiresIn?: number;
69
+ beforeEmailVerification?: (user: import("better-auth").User, request?: Request) => Promise<void>;
70
+ afterEmailVerification?: (user: import("better-auth").User, request?: Request) => Promise<void>;
71
+ } | undefined;
72
+ emailAndPassword?: {
73
+ enabled: boolean;
74
+ disableSignUp?: boolean;
75
+ requireEmailVerification?: boolean;
76
+ maxPasswordLength?: number;
77
+ minPasswordLength?: number;
78
+ sendResetPassword?: (data: {
79
+ user: import("better-auth").User;
80
+ url: string;
81
+ token: string;
82
+ }, request?: Request) => Promise<void>;
83
+ resetPasswordTokenExpiresIn?: number;
84
+ onPasswordReset?: (data: {
85
+ user: import("better-auth").User;
86
+ }, request?: Request) => Promise<void>;
87
+ password?: {
88
+ hash?: (password: string) => Promise<string>;
89
+ verify?: (data: {
90
+ hash: string;
91
+ password: string;
92
+ }) => Promise<boolean>;
93
+ };
94
+ autoSignIn?: boolean;
95
+ revokeSessionsOnPasswordReset?: boolean;
96
+ onExistingUserSignUp?: (data: {
97
+ user: import("better-auth").User;
98
+ }, request?: Request) => Promise<void>;
99
+ customSyntheticUser?: (params: {
100
+ coreFields: {
101
+ name: string;
102
+ email: string;
103
+ emailVerified: boolean;
104
+ image: string | null;
105
+ createdAt: Date;
106
+ updatedAt: Date;
107
+ };
108
+ additionalFields: Record<string, unknown>;
109
+ id: string;
110
+ }) => Record<string, unknown>;
111
+ } | undefined;
112
+ socialProviders?: import("better-auth").SocialProviders | undefined;
113
+ user?: (import("better-auth").BetterAuthDBOptions<"user", keyof import("better-auth").BaseUser> & {
114
+ changeEmail?: {
115
+ enabled: boolean;
116
+ sendChangeEmailConfirmation?: (data: {
117
+ user: import("better-auth").User;
118
+ newEmail: string;
119
+ url: string;
120
+ token: string;
121
+ }, request?: Request) => Promise<void>;
122
+ updateEmailWithoutVerification?: boolean;
123
+ };
124
+ deleteUser?: {
125
+ enabled?: boolean;
126
+ sendDeleteAccountVerification?: (data: {
127
+ user: import("better-auth").User;
128
+ url: string;
129
+ token: string;
130
+ }, request?: Request) => Promise<void>;
131
+ beforeDelete?: (user: import("better-auth").User, request?: Request) => Promise<void>;
132
+ afterDelete?: (user: import("better-auth").User, request?: Request) => Promise<void>;
133
+ deleteTokenExpiresIn?: number;
134
+ };
135
+ }) | undefined;
136
+ verification?: (import("better-auth").BetterAuthDBOptions<"verification", keyof import("better-auth").BaseVerification> & {
137
+ disableCleanup?: boolean;
138
+ storeIdentifier?: import("better-auth").StoreIdentifierOption | {
139
+ default: import("better-auth").StoreIdentifierOption;
140
+ overrides?: Record<string, import("better-auth").StoreIdentifierOption>;
141
+ };
142
+ storeInDatabase?: boolean;
143
+ }) | undefined;
144
+ trustedOrigins?: (string[] | ((request?: Request | undefined) => import("better-auth").Awaitable<(string | undefined | null)[]>)) | undefined;
145
+ rateLimit?: import("better-auth").BetterAuthRateLimitOptions | undefined;
146
+ advanced?: import("better-auth").BetterAuthAdvancedOptions | undefined;
147
+ logger?: import("better-auth").Logger | undefined;
148
+ databaseHooks?: {
149
+ user?: {
150
+ create?: {
151
+ before?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
152
+ data: {
153
+ id?: string | undefined;
154
+ createdAt?: Date | undefined;
155
+ updatedAt?: Date | undefined;
156
+ email?: string | undefined;
157
+ emailVerified?: boolean | undefined;
158
+ name?: string | undefined;
159
+ image?: string | null | undefined;
160
+ } & Record<string, any>;
161
+ }>;
162
+ after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
163
+ };
164
+ update?: {
165
+ before?: (user: Partial<import("better-auth").User> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
166
+ data: {
167
+ [x: string]: any;
168
+ id?: string | undefined;
169
+ createdAt?: Date | undefined;
170
+ updatedAt?: Date | undefined;
171
+ email?: string | undefined;
172
+ emailVerified?: boolean | undefined;
173
+ name?: string | undefined;
174
+ image?: string | null | undefined;
175
+ };
176
+ }>;
177
+ after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
178
+ };
179
+ delete?: {
180
+ before?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
181
+ after?: (user: import("better-auth").User & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
182
+ };
183
+ };
184
+ session?: {
185
+ create?: {
186
+ before?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
187
+ data: {
188
+ id?: string | undefined;
189
+ createdAt?: Date | undefined;
190
+ updatedAt?: Date | undefined;
191
+ userId?: string | undefined;
192
+ expiresAt?: Date | undefined;
193
+ token?: string | undefined;
194
+ ipAddress?: string | null | undefined;
195
+ userAgent?: string | null | undefined;
196
+ } & Record<string, any>;
197
+ }>;
198
+ after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
199
+ };
200
+ update?: {
201
+ before?: (session: Partial<import("better-auth").Session> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
202
+ data: {
203
+ [x: string]: any;
204
+ id?: string | undefined;
205
+ createdAt?: Date | undefined;
206
+ updatedAt?: Date | undefined;
207
+ userId?: string | undefined;
208
+ expiresAt?: Date | undefined;
209
+ token?: string | undefined;
210
+ ipAddress?: string | null | undefined;
211
+ userAgent?: string | null | undefined;
212
+ };
213
+ }>;
214
+ after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
215
+ };
216
+ delete?: {
217
+ before?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
218
+ after?: (session: import("better-auth").Session & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
219
+ };
220
+ };
221
+ account?: {
222
+ create?: {
223
+ before?: (account: import("better-auth").Account, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
224
+ data: {
225
+ id?: string | undefined;
226
+ createdAt?: Date | undefined;
227
+ updatedAt?: Date | undefined;
228
+ providerId?: string | undefined;
229
+ accountId?: string | undefined;
230
+ userId?: string | undefined;
231
+ accessToken?: string | null | undefined;
232
+ refreshToken?: string | null | undefined;
233
+ idToken?: string | null | undefined;
234
+ accessTokenExpiresAt?: Date | null | undefined;
235
+ refreshTokenExpiresAt?: Date | null | undefined;
236
+ scope?: string | null | undefined;
237
+ password?: string | null | undefined;
238
+ } & Record<string, any>;
239
+ }>;
240
+ after?: (account: import("better-auth").Account, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
241
+ };
242
+ update?: {
243
+ before?: (account: Partial<import("better-auth").Account> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
244
+ data: {
245
+ [x: string]: any;
246
+ id?: string | undefined;
247
+ createdAt?: Date | undefined;
248
+ updatedAt?: Date | undefined;
249
+ providerId?: string | undefined;
250
+ accountId?: string | undefined;
251
+ userId?: string | undefined;
252
+ accessToken?: string | null | undefined;
253
+ refreshToken?: string | null | undefined;
254
+ idToken?: string | null | undefined;
255
+ accessTokenExpiresAt?: Date | null | undefined;
256
+ refreshTokenExpiresAt?: Date | null | undefined;
257
+ scope?: string | null | undefined;
258
+ password?: string | null | undefined;
259
+ };
260
+ }>;
261
+ after?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
262
+ };
263
+ delete?: {
264
+ before?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
265
+ after?: (account: import("better-auth").Account & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
266
+ };
267
+ };
268
+ verification?: {
269
+ create?: {
270
+ before?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
271
+ data: {
272
+ id?: string | undefined;
273
+ createdAt?: Date | undefined;
274
+ updatedAt?: Date | undefined;
275
+ value?: string | undefined;
276
+ expiresAt?: Date | undefined;
277
+ identifier?: string | undefined;
278
+ } & Record<string, any>;
279
+ }>;
280
+ after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
281
+ };
282
+ update?: {
283
+ before?: (verification: Partial<import("better-auth").Verification> & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void | {
284
+ data: {
285
+ [x: string]: any;
286
+ id?: string | undefined;
287
+ createdAt?: Date | undefined;
288
+ updatedAt?: Date | undefined;
289
+ value?: string | undefined;
290
+ expiresAt?: Date | undefined;
291
+ identifier?: string | undefined;
292
+ };
293
+ }>;
294
+ after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
295
+ };
296
+ delete?: {
297
+ before?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<boolean | void>;
298
+ after?: (verification: import("better-auth").Verification & Record<string, unknown>, context: import("better-auth").GenericEndpointContext | null) => Promise<void>;
299
+ };
300
+ };
301
+ } | undefined;
302
+ onAPIError?: {
303
+ throw?: boolean;
304
+ onError?: (error: unknown, ctx: import("better-auth").AuthContext) => void | Promise<void>;
305
+ errorURL?: string;
306
+ customizeDefaultErrorPage?: {
307
+ colors?: {
308
+ background?: string;
309
+ foreground?: string;
310
+ primary?: string;
311
+ primaryForeground?: string;
312
+ mutedForeground?: string;
313
+ border?: string;
314
+ destructive?: string;
315
+ titleBorder?: string;
316
+ titleColor?: string;
317
+ gridColor?: string;
318
+ cardBackground?: string;
319
+ cornerBorder?: string;
320
+ };
321
+ size?: {
322
+ radiusSm?: string;
323
+ radiusMd?: string;
324
+ radiusLg?: string;
325
+ textSm?: string;
326
+ text2xl?: string;
327
+ text4xl?: string;
328
+ text6xl?: string;
329
+ };
330
+ font?: {
331
+ defaultFamily?: string;
332
+ monoFamily?: string;
333
+ };
334
+ disableTitleBorder?: boolean;
335
+ disableCornerDecorations?: boolean;
336
+ disableBackgroundGrid?: boolean;
337
+ };
338
+ } | undefined;
339
+ hooks?: {
340
+ before?: import("better-auth/api").AuthMiddleware;
341
+ after?: import("better-auth/api").AuthMiddleware;
342
+ } | undefined;
343
+ disabledPaths?: string[] | undefined;
344
+ telemetry?: {
345
+ enabled?: boolean;
346
+ debug?: boolean;
347
+ } | undefined;
348
+ experimental?: {
349
+ joins?: boolean;
350
+ };
351
+ }>;