better-auth 1.4.8-beta.1 → 1.4.8-beta.2
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/dist/api/index.d.mts +393 -393
- package/dist/api/middlewares/origin-check.d.mts +3 -3
- package/dist/api/routes/account.d.mts +11 -11
- package/dist/api/routes/callback.d.mts +2 -2
- package/dist/api/routes/email-verification.d.mts +4 -4
- package/dist/api/routes/error.d.mts +2 -2
- package/dist/api/routes/ok.d.mts +2 -2
- package/dist/api/routes/reset-password.d.mts +5 -5
- package/dist/api/routes/session.d.mts +14 -14
- package/dist/api/routes/sign-in.d.mts +3 -3
- package/dist/api/routes/sign-out.d.mts +2 -2
- package/dist/api/routes/sign-up.d.mts +2 -2
- package/dist/api/routes/update-user.d.mts +13 -13
- package/dist/client/lynx/index.d.mts +15 -15
- package/dist/client/react/index.d.mts +13 -13
- package/dist/client/solid/index.d.mts +13 -13
- package/dist/client/svelte/index.d.mts +13 -13
- package/dist/client/vue/index.d.mts +15 -15
- package/dist/db/field.d.mts +6 -6
- package/dist/integrations/next-js.d.mts +4 -4
- package/dist/integrations/svelte-kit.d.mts +2 -2
- package/dist/integrations/tanstack-start.d.mts +4 -4
- package/dist/plugins/anonymous/index.d.mts +6 -5
- package/dist/plugins/anonymous/index.mjs +1 -0
- package/dist/plugins/anonymous/index.mjs.map +1 -1
- package/dist/plugins/api-key/index.d.mts +18 -18
- package/dist/plugins/bearer/index.d.mts +8 -7
- package/dist/plugins/bearer/index.mjs +2 -1
- package/dist/plugins/bearer/index.mjs.map +1 -1
- package/dist/plugins/captcha/index.d.mts +3 -2
- package/dist/plugins/captcha/index.mjs +2 -1
- package/dist/plugins/captcha/index.mjs.map +1 -1
- package/dist/plugins/custom-session/index.d.mts +6 -5
- package/dist/plugins/custom-session/index.mjs +2 -1
- package/dist/plugins/custom-session/index.mjs.map +1 -1
- package/dist/plugins/device-authorization/index.d.mts +35 -8
- package/dist/plugins/device-authorization/index.mjs +2 -1
- package/dist/plugins/device-authorization/index.mjs.map +1 -1
- package/dist/plugins/email-otp/index.d.mts +49 -48
- package/dist/plugins/email-otp/index.mjs +2 -1
- package/dist/plugins/email-otp/index.mjs.map +1 -1
- package/dist/plugins/generic-oauth/index.d.mts +1 -0
- package/dist/plugins/generic-oauth/index.mjs +1 -0
- package/dist/plugins/generic-oauth/index.mjs.map +1 -1
- package/dist/plugins/haveibeenpwned/index.d.mts +4 -3
- package/dist/plugins/haveibeenpwned/index.mjs +1 -0
- package/dist/plugins/haveibeenpwned/index.mjs.map +1 -1
- package/dist/plugins/index.d.mts +4 -3
- package/dist/plugins/jwt/index.d.mts +9 -9
- package/dist/plugins/last-login-method/index.d.mts +3 -2
- package/dist/plugins/last-login-method/index.mjs +2 -1
- package/dist/plugins/last-login-method/index.mjs.map +1 -1
- package/dist/plugins/magic-link/index.d.mts +5 -4
- package/dist/plugins/magic-link/index.mjs +2 -1
- package/dist/plugins/magic-link/index.mjs.map +1 -1
- package/dist/plugins/mcp/index.d.mts +11 -10
- package/dist/plugins/mcp/index.mjs +2 -1
- package/dist/plugins/mcp/index.mjs.map +1 -1
- package/dist/plugins/multi-session/index.d.mts +10 -9
- package/dist/plugins/multi-session/index.mjs +1 -0
- package/dist/plugins/multi-session/index.mjs.map +1 -1
- package/dist/plugins/oauth-proxy/index.d.mts +8 -8
- package/dist/plugins/oidc-provider/index.d.mts +13 -13
- package/dist/plugins/one-tap/index.d.mts +4 -3
- package/dist/plugins/one-tap/index.mjs +2 -1
- package/dist/plugins/one-tap/index.mjs.map +1 -1
- package/dist/plugins/one-time-token/index.d.mts +6 -5
- package/dist/plugins/one-time-token/index.mjs +2 -1
- package/dist/plugins/one-time-token/index.mjs.map +1 -1
- package/dist/plugins/open-api/index.d.mts +4 -3
- package/dist/plugins/open-api/index.mjs +2 -1
- package/dist/plugins/open-api/index.mjs.map +1 -1
- package/dist/plugins/organization/organization.d.mts +4 -4
- package/dist/plugins/organization/organization.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-access-control.d.mts +22 -22
- package/dist/plugins/organization/routes/crud-invites.d.mts +58 -58
- package/dist/plugins/organization/routes/crud-members.d.mts +62 -62
- package/dist/plugins/organization/routes/crud-org.d.mts +51 -51
- package/dist/plugins/organization/routes/crud-team.d.mts +76 -76
- package/dist/plugins/phone-number/index.d.mts +10 -9
- package/dist/plugins/phone-number/index.mjs +1 -0
- package/dist/plugins/phone-number/index.mjs.map +1 -1
- package/dist/plugins/siwe/index.d.mts +4 -3
- package/dist/plugins/siwe/index.mjs +2 -1
- package/dist/plugins/siwe/index.mjs.map +1 -1
- package/dist/plugins/two-factor/backup-codes/index.d.mts +5 -5
- package/dist/plugins/two-factor/index.d.mts +18 -18
- package/dist/plugins/two-factor/otp/index.d.mts +3 -3
- package/dist/plugins/two-factor/totp/index.d.mts +5 -5
- package/dist/plugins/username/index.d.mts +10 -9
- package/dist/plugins/username/index.mjs +1 -0
- package/dist/plugins/username/index.mjs.map +1 -1
- package/dist/test-utils/test-instance.d.mts +271 -271
- package/dist/utils/time.d.mts +29 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["verifyHandlers.cloudflareTurnstile","verifyHandlers.googleRecaptcha","verifyHandlers.hCaptcha","verifyHandlers.captchaFox"],"sources":["../../../src/plugins/captcha/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { getIp } from \"../../utils/get-request-ip\";\nimport { middlewareResponse } from \"../../utils/middleware-response\";\nimport { defaultEndpoints, Providers, siteVerifyMap } from \"./constants\";\nimport { EXTERNAL_ERROR_CODES, INTERNAL_ERROR_CODES } from \"./error-codes\";\nimport type { CaptchaOptions } from \"./types\";\nimport * as verifyHandlers from \"./verify-handlers\";\n\nexport const captcha = (options: CaptchaOptions) =>\n\t({\n\t\tid: \"captcha\",\n\t\tonRequest: async (request, ctx) => {\n\t\t\ttry {\n\t\t\t\tconst endpoints = options.endpoints?.length\n\t\t\t\t\t? options.endpoints\n\t\t\t\t\t: defaultEndpoints;\n\n\t\t\t\tif (!endpoints.some((endpoint) => request.url.includes(endpoint)))\n\t\t\t\t\treturn undefined;\n\n\t\t\t\tif (!options.secretKey) {\n\t\t\t\t\tthrow new Error(INTERNAL_ERROR_CODES.MISSING_SECRET_KEY);\n\t\t\t\t}\n\n\t\t\t\tconst captchaResponse = request.headers.get(\"x-captcha-response\");\n\t\t\t\tconst remoteUserIP = getIp(request, ctx.options) ?? undefined;\n\n\t\t\t\tif (!captchaResponse) {\n\t\t\t\t\treturn middlewareResponse({\n\t\t\t\t\t\tmessage: EXTERNAL_ERROR_CODES.MISSING_RESPONSE,\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst siteVerifyURL =\n\t\t\t\t\toptions.siteVerifyURLOverride || siteVerifyMap[options.provider];\n\n\t\t\t\tconst handlerParams = {\n\t\t\t\t\tsiteVerifyURL,\n\t\t\t\t\tcaptchaResponse,\n\t\t\t\t\tsecretKey: options.secretKey,\n\t\t\t\t\tremoteIP: remoteUserIP,\n\t\t\t\t};\n\n\t\t\t\tif (options.provider === Providers.CLOUDFLARE_TURNSTILE) {\n\t\t\t\t\treturn await verifyHandlers.cloudflareTurnstile(handlerParams);\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.GOOGLE_RECAPTCHA) {\n\t\t\t\t\treturn await verifyHandlers.googleRecaptcha({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tminScore: options.minScore,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.HCAPTCHA) {\n\t\t\t\t\treturn await verifyHandlers.hCaptcha({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tsiteKey: options.siteKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.CAPTCHAFOX) {\n\t\t\t\t\treturn await verifyHandlers.captchaFox({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tsiteKey: options.siteKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (_error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\t_error instanceof Error ? _error.message : undefined;\n\n\t\t\t\tctx.logger.error(errorMessage ?? \"Unknown error\", {\n\t\t\t\t\tendpoint: request.url,\n\t\t\t\t\tmessage: _error,\n\t\t\t\t});\n\n\t\t\t\treturn middlewareResponse({\n\t\t\t\t\tmessage: EXTERNAL_ERROR_CODES.UNKNOWN_ERROR,\n\t\t\t\t\tstatus: 500,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t}) satisfies BetterAuthPlugin;\n"],"mappings":";;;;;;;;;;;AAQA,MAAa,WAAW,aACtB;CACA,IAAI;CACJ,WAAW,OAAO,SAAS,QAAQ;AAClC,MAAI;AAKH,OAAI,EAJc,QAAQ,WAAW,SAClC,QAAQ,YACR,kBAEY,MAAM,aAAa,QAAQ,IAAI,SAAS,SAAS,CAAC,CAChE,QAAO;AAER,OAAI,CAAC,QAAQ,UACZ,OAAM,IAAI,MAAM,qBAAqB,mBAAmB;GAGzD,MAAM,kBAAkB,QAAQ,QAAQ,IAAI,qBAAqB;GACjE,MAAM,eAAe,MAAM,SAAS,IAAI,QAAQ,IAAI;AAEpD,OAAI,CAAC,gBACJ,QAAO,mBAAmB;IACzB,SAAS,qBAAqB;IAC9B,QAAQ;IACR,CAAC;GAMH,MAAM,gBAAgB;IACrB,eAHA,QAAQ,yBAAyB,cAAc,QAAQ;IAIvD;IACA,WAAW,QAAQ;IACnB,UAAU;IACV;AAED,OAAI,QAAQ,aAAa,UAAU,qBAClC,QAAO,MAAMA,oBAAmC,cAAc;AAG/D,OAAI,QAAQ,aAAa,UAAU,iBAClC,QAAO,MAAMC,gBAA+B;IAC3C,GAAG;IACH,UAAU,QAAQ;IAClB,CAAC;AAGH,OAAI,QAAQ,aAAa,UAAU,SAClC,QAAO,MAAMC,SAAwB;IACpC,GAAG;IACH,SAAS,QAAQ;IACjB,CAAC;AAGH,OAAI,QAAQ,aAAa,UAAU,WAClC,QAAO,MAAMC,WAA0B;IACtC,GAAG;IACH,SAAS,QAAQ;IACjB,CAAC;WAEK,QAAQ;GAChB,MAAM,eACL,kBAAkB,QAAQ,OAAO,UAAU;AAE5C,OAAI,OAAO,MAAM,gBAAgB,iBAAiB;IACjD,UAAU,QAAQ;IAClB,SAAS;IACT,CAAC;AAEF,UAAO,mBAAmB;IACzB,SAAS,qBAAqB;IAC9B,QAAQ;IACR,CAAC;;;CAGJ"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["verifyHandlers.cloudflareTurnstile","verifyHandlers.googleRecaptcha","verifyHandlers.hCaptcha","verifyHandlers.captchaFox"],"sources":["../../../src/plugins/captcha/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { getIp } from \"../../utils/get-request-ip\";\nimport { middlewareResponse } from \"../../utils/middleware-response\";\nimport { defaultEndpoints, Providers, siteVerifyMap } from \"./constants\";\nimport { EXTERNAL_ERROR_CODES, INTERNAL_ERROR_CODES } from \"./error-codes\";\nimport type { CaptchaOptions } from \"./types\";\nimport * as verifyHandlers from \"./verify-handlers\";\n\nexport const captcha = (options: CaptchaOptions) =>\n\t({\n\t\tid: \"captcha\",\n\t\tonRequest: async (request, ctx) => {\n\t\t\ttry {\n\t\t\t\tconst endpoints = options.endpoints?.length\n\t\t\t\t\t? options.endpoints\n\t\t\t\t\t: defaultEndpoints;\n\n\t\t\t\tif (!endpoints.some((endpoint) => request.url.includes(endpoint)))\n\t\t\t\t\treturn undefined;\n\n\t\t\t\tif (!options.secretKey) {\n\t\t\t\t\tthrow new Error(INTERNAL_ERROR_CODES.MISSING_SECRET_KEY);\n\t\t\t\t}\n\n\t\t\t\tconst captchaResponse = request.headers.get(\"x-captcha-response\");\n\t\t\t\tconst remoteUserIP = getIp(request, ctx.options) ?? undefined;\n\n\t\t\t\tif (!captchaResponse) {\n\t\t\t\t\treturn middlewareResponse({\n\t\t\t\t\t\tmessage: EXTERNAL_ERROR_CODES.MISSING_RESPONSE,\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst siteVerifyURL =\n\t\t\t\t\toptions.siteVerifyURLOverride || siteVerifyMap[options.provider];\n\n\t\t\t\tconst handlerParams = {\n\t\t\t\t\tsiteVerifyURL,\n\t\t\t\t\tcaptchaResponse,\n\t\t\t\t\tsecretKey: options.secretKey,\n\t\t\t\t\tremoteIP: remoteUserIP,\n\t\t\t\t};\n\n\t\t\t\tif (options.provider === Providers.CLOUDFLARE_TURNSTILE) {\n\t\t\t\t\treturn await verifyHandlers.cloudflareTurnstile(handlerParams);\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.GOOGLE_RECAPTCHA) {\n\t\t\t\t\treturn await verifyHandlers.googleRecaptcha({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tminScore: options.minScore,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.HCAPTCHA) {\n\t\t\t\t\treturn await verifyHandlers.hCaptcha({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tsiteKey: options.siteKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (options.provider === Providers.CAPTCHAFOX) {\n\t\t\t\t\treturn await verifyHandlers.captchaFox({\n\t\t\t\t\t\t...handlerParams,\n\t\t\t\t\t\tsiteKey: options.siteKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (_error) {\n\t\t\t\tconst errorMessage =\n\t\t\t\t\t_error instanceof Error ? _error.message : undefined;\n\n\t\t\t\tctx.logger.error(errorMessage ?? \"Unknown error\", {\n\t\t\t\t\tendpoint: request.url,\n\t\t\t\t\tmessage: _error,\n\t\t\t\t});\n\n\t\t\t\treturn middlewareResponse({\n\t\t\t\t\tmessage: EXTERNAL_ERROR_CODES.UNKNOWN_ERROR,\n\t\t\t\t\tstatus: 500,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\toptions,\n\t}) satisfies BetterAuthPlugin;\n"],"mappings":";;;;;;;;;;;AAQA,MAAa,WAAW,aACtB;CACA,IAAI;CACJ,WAAW,OAAO,SAAS,QAAQ;AAClC,MAAI;AAKH,OAAI,EAJc,QAAQ,WAAW,SAClC,QAAQ,YACR,kBAEY,MAAM,aAAa,QAAQ,IAAI,SAAS,SAAS,CAAC,CAChE,QAAO;AAER,OAAI,CAAC,QAAQ,UACZ,OAAM,IAAI,MAAM,qBAAqB,mBAAmB;GAGzD,MAAM,kBAAkB,QAAQ,QAAQ,IAAI,qBAAqB;GACjE,MAAM,eAAe,MAAM,SAAS,IAAI,QAAQ,IAAI;AAEpD,OAAI,CAAC,gBACJ,QAAO,mBAAmB;IACzB,SAAS,qBAAqB;IAC9B,QAAQ;IACR,CAAC;GAMH,MAAM,gBAAgB;IACrB,eAHA,QAAQ,yBAAyB,cAAc,QAAQ;IAIvD;IACA,WAAW,QAAQ;IACnB,UAAU;IACV;AAED,OAAI,QAAQ,aAAa,UAAU,qBAClC,QAAO,MAAMA,oBAAmC,cAAc;AAG/D,OAAI,QAAQ,aAAa,UAAU,iBAClC,QAAO,MAAMC,gBAA+B;IAC3C,GAAG;IACH,UAAU,QAAQ;IAClB,CAAC;AAGH,OAAI,QAAQ,aAAa,UAAU,SAClC,QAAO,MAAMC,SAAwB;IACpC,GAAG;IACH,SAAS,QAAQ;IACjB,CAAC;AAGH,OAAI,QAAQ,aAAa,UAAU,WAClC,QAAO,MAAMC,WAA0B;IACtC,GAAG;IACH,SAAS,QAAQ;IACjB,CAAC;WAEK,QAAQ;GAChB,MAAM,eACL,kBAAkB,QAAQ,OAAO,UAAU;AAE5C,OAAI,OAAO,MAAM,gBAAgB,iBAAiB;IACjD,UAAU,QAAQ;IAClB,SAAS;IACT,CAAC;AAEF,UAAO,mBAAmB;IACzB,SAAS,qBAAqB;IAC9B,QAAQ;IACR,CAAC;;;CAGJ;CACA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { InferSession, InferUser } from "../../types/models.mjs";
|
|
2
2
|
import "../../types/index.mjs";
|
|
3
|
-
import * as
|
|
3
|
+
import * as _better_auth_core7 from "@better-auth/core";
|
|
4
4
|
import { BetterAuthOptions, GenericEndpointContext } from "@better-auth/core";
|
|
5
5
|
import * as z from "zod";
|
|
6
|
-
import * as
|
|
6
|
+
import * as better_call144 from "better-call";
|
|
7
7
|
|
|
8
8
|
//#region src/plugins/custom-session/index.d.ts
|
|
9
9
|
type CustomSessionPluginOptions = {
|
|
@@ -20,12 +20,12 @@ declare const customSession: <Returns extends Record<string, any>, O extends Bet
|
|
|
20
20
|
id: "custom-session";
|
|
21
21
|
hooks: {
|
|
22
22
|
after: {
|
|
23
|
-
matcher: (ctx:
|
|
24
|
-
handler: (inputContext:
|
|
23
|
+
matcher: (ctx: _better_auth_core7.HookEndpointContext) => boolean;
|
|
24
|
+
handler: (inputContext: better_call144.MiddlewareInputContext<better_call144.MiddlewareOptions>) => Promise<Awaited<Returns>[] | undefined>;
|
|
25
25
|
}[];
|
|
26
26
|
};
|
|
27
27
|
endpoints: {
|
|
28
|
-
getSession:
|
|
28
|
+
getSession: better_call144.StrictEndpoint<"/get-session", {
|
|
29
29
|
method: "GET";
|
|
30
30
|
query: z.ZodOptional<z.ZodObject<{
|
|
31
31
|
disableCookieCache: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodPipe<z.ZodString, z.ZodTransform<boolean, string>>]>>;
|
|
@@ -59,6 +59,7 @@ declare const customSession: <Returns extends Record<string, any>, O extends Bet
|
|
|
59
59
|
$Infer: {
|
|
60
60
|
Session: Awaited<ReturnType<typeof fn>>;
|
|
61
61
|
};
|
|
62
|
+
options: CustomSessionPluginOptions | undefined;
|
|
62
63
|
};
|
|
63
64
|
//#endregion
|
|
64
65
|
export { CustomSessionPluginOptions, customSession };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/custom-session/index.ts"],"sourcesContent":["import type {\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport {\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n} from \"@better-auth/core/api\";\nimport * as z from \"zod\";\nimport { getSession } from \"../../api\";\nimport type { InferSession, InferUser } from \"../../types\";\nimport { getEndpointResponse } from \"../../utils/plugin-helper\";\n\nconst getSessionQuerySchema = z.optional(\n\tz.object({\n\t\t/**\n\t\t * If cookie cache is enabled, it will disable the cache\n\t\t * and fetch the session from the database\n\t\t */\n\t\tdisableCookieCache: z\n\t\t\t.boolean()\n\t\t\t.meta({\n\t\t\t\tdescription: \"Disable cookie cache and fetch session from database\",\n\t\t\t})\n\t\t\t.or(z.string().transform((v) => v === \"true\"))\n\t\t\t.optional(),\n\t\tdisableRefresh: z\n\t\t\t.boolean()\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Disable session refresh. Useful for checking session status, without updating the session\",\n\t\t\t})\n\t\t\t.optional(),\n\t}),\n);\n\nexport type CustomSessionPluginOptions = {\n\t/**\n\t * This option is used to determine if the list-device-sessions endpoint should be mutated to the custom session data.\n\t * @default false\n\t */\n\tshouldMutateListDeviceSessionsEndpoint?: boolean | undefined;\n};\n\nexport const customSession = <\n\tReturns extends Record<string, any>,\n\tO extends BetterAuthOptions = BetterAuthOptions,\n>(\n\tfn: (\n\t\tsession: {\n\t\t\tuser: InferUser<O>;\n\t\t\tsession: InferSession<O>;\n\t\t},\n\t\tctx: GenericEndpointContext,\n\t) => Promise<Returns>,\n\toptions?: O | undefined,\n\tpluginOptions?: CustomSessionPluginOptions | undefined,\n) => {\n\treturn {\n\t\tid: \"custom-session\",\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher: (ctx) =>\n\t\t\t\t\t\tctx.path === \"/multi-session/list-device-sessions\" &&\n\t\t\t\t\t\t(pluginOptions?.shouldMutateListDeviceSessionsEndpoint ?? false),\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst response = await getEndpointResponse<[]>(ctx);\n\t\t\t\t\t\tif (!response) return;\n\t\t\t\t\t\tconst newResponse = await Promise.all(\n\t\t\t\t\t\t\tresponse.map(async (v) => await fn(v, ctx)),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn ctx.json(newResponse);\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tendpoints: {\n\t\t\tgetSession: createAuthEndpoint(\n\t\t\t\t\"/get-session\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: getSessionQuerySchema,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tCUSTOM_SESSION: true,\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\tdescription: \"Get custom session data\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t},\n\t\t\t\tasync (ctx): Promise<Returns | null> => {\n\t\t\t\t\tconst session = await getSession()({\n\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\tasResponse: false,\n\t\t\t\t\t\theaders: ctx.headers,\n\t\t\t\t\t\treturnHeaders: true,\n\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t});\n\t\t\t\t\tif (!session?.response) {\n\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t}\n\t\t\t\t\tconst fnResult = await fn(session.response as any, ctx);\n\n\t\t\t\t\tconst setCookie = session.headers.get(\"set-cookie\");\n\t\t\t\t\tif (setCookie) {\n\t\t\t\t\t\tctx.setHeader(\"set-cookie\", setCookie);\n\t\t\t\t\t\tsession.headers.delete(\"set-cookie\");\n\t\t\t\t\t}\n\n\t\t\t\t\tsession.headers.forEach((value, key) => {\n\t\t\t\t\t\tctx.setHeader(key, value);\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json(fnResult);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\t$Infer: {\n\t\t\tSession: {} as Awaited<ReturnType<typeof fn>>,\n\t\t},\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAcA,MAAM,wBAAwB,EAAE,SAC/B,EAAE,OAAO;CAKR,oBAAoB,EAClB,SAAS,CACT,KAAK,EACL,aAAa,wDACb,CAAC,CACD,GAAG,EAAE,QAAQ,CAAC,WAAW,MAAM,MAAM,OAAO,CAAC,CAC7C,UAAU;CACZ,gBAAgB,EACd,SAAS,CACT,KAAK,EACL,aACC,6FACD,CAAC,CACD,UAAU;CACZ,CAAC,CACF;AAUD,MAAa,iBAIZ,IAOA,SACA,kBACI;AACJ,QAAO;EACN,IAAI;EACJ,OAAO,EACN,OAAO,CACN;GACC,UAAU,QACT,IAAI,SAAS,0CACZ,eAAe,0CAA0C;GAC3D,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,WAAW,MAAM,oBAAwB,IAAI;AACnD,QAAI,CAAC,SAAU;IACf,MAAM,cAAc,MAAM,QAAQ,IACjC,SAAS,IAAI,OAAO,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,CAC3C;AACD,WAAO,IAAI,KAAK,YAAY;KAC3B;GACF,CACD,EACD;EACD,WAAW,EACV,YAAY,mBACX,gBACA;GACC,QAAQ;GACR,OAAO;GACP,UAAU;IACT,gBAAgB;IAChB,SAAS;KACR,aAAa;KACb,WAAW,EACV,OAAO;MACN,aAAa;MACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;OACP,MAAM;OACN,UAAU;OACV,OAAO,EACN,MAAM,gCACN;OACD,EACD,EACD;MACD,EACD;KACD;IACD;GACD,gBAAgB;GAChB,EACD,OAAO,QAAiC;GACvC,MAAM,UAAU,MAAM,YAAY,CAAC;IAClC,GAAG;IACH,YAAY;IACZ,SAAS,IAAI;IACb,eAAe;IACf,CAAC,CAAC,OAAO,MAAM;AACf,WAAO;KACN;AACF,OAAI,CAAC,SAAS,SACb,QAAO,IAAI,KAAK,KAAK;GAEtB,MAAM,WAAW,MAAM,GAAG,QAAQ,UAAiB,IAAI;GAEvD,MAAM,YAAY,QAAQ,QAAQ,IAAI,aAAa;AACnD,OAAI,WAAW;AACd,QAAI,UAAU,cAAc,UAAU;AACtC,YAAQ,QAAQ,OAAO,aAAa;;AAGrC,WAAQ,QAAQ,SAAS,OAAO,QAAQ;AACvC,QAAI,UAAU,KAAK,MAAM;KACxB;AACF,UAAO,IAAI,KAAK,SAAS;IAE1B,EACD;EACD,QAAQ,EACP,SAAS,EAAE,EACX;EACD"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/custom-session/index.ts"],"sourcesContent":["import type {\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport {\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n} from \"@better-auth/core/api\";\nimport * as z from \"zod\";\nimport { getSession } from \"../../api\";\nimport type { InferSession, InferUser } from \"../../types\";\nimport { getEndpointResponse } from \"../../utils/plugin-helper\";\n\nconst getSessionQuerySchema = z.optional(\n\tz.object({\n\t\t/**\n\t\t * If cookie cache is enabled, it will disable the cache\n\t\t * and fetch the session from the database\n\t\t */\n\t\tdisableCookieCache: z\n\t\t\t.boolean()\n\t\t\t.meta({\n\t\t\t\tdescription: \"Disable cookie cache and fetch session from database\",\n\t\t\t})\n\t\t\t.or(z.string().transform((v) => v === \"true\"))\n\t\t\t.optional(),\n\t\tdisableRefresh: z\n\t\t\t.boolean()\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Disable session refresh. Useful for checking session status, without updating the session\",\n\t\t\t})\n\t\t\t.optional(),\n\t}),\n);\n\nexport type CustomSessionPluginOptions = {\n\t/**\n\t * This option is used to determine if the list-device-sessions endpoint should be mutated to the custom session data.\n\t * @default false\n\t */\n\tshouldMutateListDeviceSessionsEndpoint?: boolean | undefined;\n};\n\nexport const customSession = <\n\tReturns extends Record<string, any>,\n\tO extends BetterAuthOptions = BetterAuthOptions,\n>(\n\tfn: (\n\t\tsession: {\n\t\t\tuser: InferUser<O>;\n\t\t\tsession: InferSession<O>;\n\t\t},\n\t\tctx: GenericEndpointContext,\n\t) => Promise<Returns>,\n\toptions?: O | undefined,\n\tpluginOptions?: CustomSessionPluginOptions | undefined,\n) => {\n\treturn {\n\t\tid: \"custom-session\",\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher: (ctx) =>\n\t\t\t\t\t\tctx.path === \"/multi-session/list-device-sessions\" &&\n\t\t\t\t\t\t(pluginOptions?.shouldMutateListDeviceSessionsEndpoint ?? false),\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst response = await getEndpointResponse<[]>(ctx);\n\t\t\t\t\t\tif (!response) return;\n\t\t\t\t\t\tconst newResponse = await Promise.all(\n\t\t\t\t\t\t\tresponse.map(async (v) => await fn(v, ctx)),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn ctx.json(newResponse);\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tendpoints: {\n\t\t\tgetSession: createAuthEndpoint(\n\t\t\t\t\"/get-session\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: getSessionQuerySchema,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tCUSTOM_SESSION: true,\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\tdescription: \"Get custom session data\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t},\n\t\t\t\tasync (ctx): Promise<Returns | null> => {\n\t\t\t\t\tconst session = await getSession()({\n\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\tasResponse: false,\n\t\t\t\t\t\theaders: ctx.headers,\n\t\t\t\t\t\treturnHeaders: true,\n\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t});\n\t\t\t\t\tif (!session?.response) {\n\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t}\n\t\t\t\t\tconst fnResult = await fn(session.response as any, ctx);\n\n\t\t\t\t\tconst setCookie = session.headers.get(\"set-cookie\");\n\t\t\t\t\tif (setCookie) {\n\t\t\t\t\t\tctx.setHeader(\"set-cookie\", setCookie);\n\t\t\t\t\t\tsession.headers.delete(\"set-cookie\");\n\t\t\t\t\t}\n\n\t\t\t\t\tsession.headers.forEach((value, key) => {\n\t\t\t\t\t\tctx.setHeader(key, value);\n\t\t\t\t\t});\n\t\t\t\t\treturn ctx.json(fnResult);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\t$Infer: {\n\t\t\tSession: {} as Awaited<ReturnType<typeof fn>>,\n\t\t},\n\t\toptions: pluginOptions,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAcA,MAAM,wBAAwB,EAAE,SAC/B,EAAE,OAAO;CAKR,oBAAoB,EAClB,SAAS,CACT,KAAK,EACL,aAAa,wDACb,CAAC,CACD,GAAG,EAAE,QAAQ,CAAC,WAAW,MAAM,MAAM,OAAO,CAAC,CAC7C,UAAU;CACZ,gBAAgB,EACd,SAAS,CACT,KAAK,EACL,aACC,6FACD,CAAC,CACD,UAAU;CACZ,CAAC,CACF;AAUD,MAAa,iBAIZ,IAOA,SACA,kBACI;AACJ,QAAO;EACN,IAAI;EACJ,OAAO,EACN,OAAO,CACN;GACC,UAAU,QACT,IAAI,SAAS,0CACZ,eAAe,0CAA0C;GAC3D,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,WAAW,MAAM,oBAAwB,IAAI;AACnD,QAAI,CAAC,SAAU;IACf,MAAM,cAAc,MAAM,QAAQ,IACjC,SAAS,IAAI,OAAO,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,CAC3C;AACD,WAAO,IAAI,KAAK,YAAY;KAC3B;GACF,CACD,EACD;EACD,WAAW,EACV,YAAY,mBACX,gBACA;GACC,QAAQ;GACR,OAAO;GACP,UAAU;IACT,gBAAgB;IAChB,SAAS;KACR,aAAa;KACb,WAAW,EACV,OAAO;MACN,aAAa;MACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;OACP,MAAM;OACN,UAAU;OACV,OAAO,EACN,MAAM,gCACN;OACD,EACD,EACD;MACD,EACD;KACD;IACD;GACD,gBAAgB;GAChB,EACD,OAAO,QAAiC;GACvC,MAAM,UAAU,MAAM,YAAY,CAAC;IAClC,GAAG;IACH,YAAY;IACZ,SAAS,IAAI;IACb,eAAe;IACf,CAAC,CAAC,OAAO,MAAM;AACf,WAAO;KACN;AACF,OAAI,CAAC,SAAS,SACb,QAAO,IAAI,KAAK,KAAK;GAEtB,MAAM,WAAW,MAAM,GAAG,QAAQ,UAAiB,IAAI;GAEvD,MAAM,YAAY,QAAQ,QAAQ,IAAI,aAAa;AACnD,OAAI,WAAW;AACd,QAAI,UAAU,cAAc,UAAU;AACtC,YAAQ,QAAQ,OAAO,aAAa;;AAGrC,WAAQ,QAAQ,SAAS,OAAO,QAAQ;AACvC,QAAI,UAAU,KAAK,MAAM;KACxB;AACF,UAAO,IAAI,KAAK,SAAS;IAE1B,EACD;EACD,QAAQ,EACP,SAAS,EAAE,EACX;EACD,SAAS;EACT"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { TimeString } from "../../utils/time.mjs";
|
|
1
|
+
import { TimeString, ms, sec } from "../../utils/time.mjs";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
import * as
|
|
3
|
+
import * as better_call147 from "better-call";
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/device-authorization/index.d.ts
|
|
6
6
|
declare const deviceAuthorizationOptionsSchema: z.ZodObject<{
|
|
@@ -91,7 +91,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
91
91
|
};
|
|
92
92
|
};
|
|
93
93
|
endpoints: {
|
|
94
|
-
deviceCode:
|
|
94
|
+
deviceCode: better_call147.StrictEndpoint<"/device/code", {
|
|
95
95
|
method: "POST";
|
|
96
96
|
body: z.ZodObject<{
|
|
97
97
|
client_id: z.ZodString;
|
|
@@ -176,7 +176,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
176
176
|
expires_in: number;
|
|
177
177
|
interval: number;
|
|
178
178
|
}>;
|
|
179
|
-
deviceToken:
|
|
179
|
+
deviceToken: better_call147.StrictEndpoint<"/device/token", {
|
|
180
180
|
method: "POST";
|
|
181
181
|
body: z.ZodObject<{
|
|
182
182
|
grant_type: z.ZodLiteral<"urn:ietf:params:oauth:grant-type:device_code">;
|
|
@@ -244,7 +244,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
244
244
|
expires_in: number;
|
|
245
245
|
scope: string;
|
|
246
246
|
}>;
|
|
247
|
-
deviceVerify:
|
|
247
|
+
deviceVerify: better_call147.StrictEndpoint<"/device", {
|
|
248
248
|
method: "GET";
|
|
249
249
|
query: z.ZodObject<{
|
|
250
250
|
user_code: z.ZodString;
|
|
@@ -287,7 +287,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
287
287
|
user_code: string;
|
|
288
288
|
status: string;
|
|
289
289
|
}>;
|
|
290
|
-
deviceApprove:
|
|
290
|
+
deviceApprove: better_call147.StrictEndpoint<"/device/approve", {
|
|
291
291
|
method: "POST";
|
|
292
292
|
body: z.ZodObject<{
|
|
293
293
|
userCode: z.ZodString;
|
|
@@ -326,7 +326,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
326
326
|
}, {
|
|
327
327
|
success: boolean;
|
|
328
328
|
}>;
|
|
329
|
-
deviceDeny:
|
|
329
|
+
deviceDeny: better_call147.StrictEndpoint<"/device/deny", {
|
|
330
330
|
method: "POST";
|
|
331
331
|
body: z.ZodObject<{
|
|
332
332
|
userCode: z.ZodString;
|
|
@@ -378,7 +378,34 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
378
378
|
readonly INVALID_DEVICE_CODE_STATUS: "Invalid device code status";
|
|
379
379
|
readonly AUTHENTICATION_REQUIRED: "Authentication required";
|
|
380
380
|
};
|
|
381
|
+
options: Partial<{
|
|
382
|
+
expiresIn: TimeString;
|
|
383
|
+
interval: TimeString;
|
|
384
|
+
deviceCodeLength: number;
|
|
385
|
+
userCodeLength: number;
|
|
386
|
+
schema: {
|
|
387
|
+
deviceCode?: {
|
|
388
|
+
modelName?: string | undefined;
|
|
389
|
+
fields?: {
|
|
390
|
+
deviceCode?: string | undefined;
|
|
391
|
+
userCode?: string | undefined;
|
|
392
|
+
userId?: string | undefined;
|
|
393
|
+
expiresAt?: string | undefined;
|
|
394
|
+
status?: string | undefined;
|
|
395
|
+
lastPolledAt?: string | undefined;
|
|
396
|
+
pollingInterval?: string | undefined;
|
|
397
|
+
clientId?: string | undefined;
|
|
398
|
+
scope?: string | undefined;
|
|
399
|
+
} | undefined;
|
|
400
|
+
} | undefined;
|
|
401
|
+
};
|
|
402
|
+
generateDeviceCode?: (() => string | Promise<string>) | undefined;
|
|
403
|
+
generateUserCode?: (() => string | Promise<string>) | undefined;
|
|
404
|
+
validateClient?: ((clientId: string) => boolean | Promise<boolean>) | undefined;
|
|
405
|
+
onDeviceAuthRequest?: ((clientId: string, scope: string | undefined) => void | Promise<void>) | undefined;
|
|
406
|
+
verificationUri?: string | undefined;
|
|
407
|
+
}>;
|
|
381
408
|
};
|
|
382
409
|
//#endregion
|
|
383
|
-
export { DeviceAuthorizationOptions, deviceAuthorization, deviceAuthorizationOptionsSchema };
|
|
410
|
+
export { DeviceAuthorizationOptions, TimeString, deviceAuthorization, deviceAuthorizationOptionsSchema, ms, sec };
|
|
384
411
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/device-authorization/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport * as z from \"zod\";\nimport { mergeSchema } from \"../../db\";\nimport type { InferOptionSchema } from \"../../types/plugins\";\nimport type { TimeString } from \"../../utils/time\";\nimport { ms } from \"../../utils/time\";\nimport { DEVICE_AUTHORIZATION_ERROR_CODES } from \"./error-codes\";\nimport {\n\tdeviceApprove,\n\tdeviceCode,\n\tdeviceDeny,\n\tdeviceToken,\n\tdeviceVerify,\n} from \"./routes\";\nimport { schema } from \"./schema\";\n\nconst timeStringSchema = z.custom<TimeString>(\n\t(val) => {\n\t\tif (typeof val !== \"string\") return false;\n\t\ttry {\n\t\t\tms(val as TimeString);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\t{\n\t\tmessage:\n\t\t\t\"Invalid time string format. Use formats like '30m', '5s', '1h', etc.\",\n\t},\n);\n\nexport const deviceAuthorizationOptionsSchema = z.object({\n\texpiresIn: timeStringSchema\n\t\t.default(\"30m\")\n\t\t.describe(\n\t\t\t\"Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tinterval: timeStringSchema\n\t\t.default(\"5s\")\n\t\t.describe(\n\t\t\t\"Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tdeviceCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(40)\n\t\t.describe(\n\t\t\t\"Length of the device code to be generated. Default is 40 characters.\",\n\t\t),\n\tuserCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(8)\n\t\t.describe(\n\t\t\t\"Length of the user code to be generated. Default is 8 characters.\",\n\t\t),\n\tgenerateDeviceCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateDeviceCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a device code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tgenerateUserCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateUserCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a user code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tvalidateClient: z\n\t\t.custom<(clientId: string) => boolean | Promise<boolean>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"validateClient must be a function that returns a boolean or a promise that resolves to a boolean.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to validate the client ID. If not provided, no validation will be performed.\",\n\t\t),\n\tonDeviceAuthRequest: z\n\t\t.custom<\n\t\t\t(clientId: string, scope: string | undefined) => void | Promise<void>\n\t\t>((val) => typeof val === \"function\", {\n\t\t\tmessage:\n\t\t\t\t\"onDeviceAuthRequest must be a function that returns void or a promise that resolves to void.\",\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to handle device authorization requests. If not provided, no additional actions will be taken.\",\n\t\t),\n\tverificationUri: z\n\t\t.string()\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device.\",\n\t\t),\n\tschema: z.custom<InferOptionSchema<typeof schema>>(() => true),\n});\n\nexport type DeviceAuthorizationOptions = z.infer<\n\ttypeof deviceAuthorizationOptionsSchema\n>;\n\nexport const deviceAuthorization = (\n\toptions: Partial<DeviceAuthorizationOptions> = {},\n) => {\n\tconst opts = deviceAuthorizationOptionsSchema.parse(options);\n\n\treturn {\n\t\tid: \"device-authorization\",\n\t\tschema: mergeSchema(schema, options?.schema),\n\t\tendpoints: {\n\t\t\tdeviceCode: deviceCode(opts),\n\t\t\tdeviceToken: deviceToken(opts),\n\t\t\tdeviceVerify,\n\t\t\tdeviceApprove,\n\t\t\tdeviceDeny,\n\t\t},\n\t\t$ERROR_CODES: DEVICE_AUTHORIZATION_ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;;;AAgBA,MAAM,mBAAmB,EAAE,QACzB,QAAQ;AACR,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;AACH,KAAG,IAAkB;AACrB,SAAO;SACA;AACP,SAAO;;GAGT,EACC,SACC,wEACD,CACD;AAED,MAAa,mCAAmC,EAAE,OAAO;CACxD,WAAW,iBACT,QAAQ,MAAM,CACd,SACA,0FACA;CACF,UAAU,iBACR,QAAQ,KAAK,CACb,SACA,qFACA;CACF,kBAAkB,EAChB,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,GAAG,CACX,SACA,uEACA;CACF,gBAAgB,EACd,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,EAAE,CACV,SACA,oEACA;CACF,oBAAoB,EAClB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,uGACD,CACD,CACA,UAAU,CACV,SACA,uGACA;CACF,kBAAkB,EAChB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,qGACA;CACF,gBAAgB,EACd,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,wFACA;CACF,qBAAqB,EACnB,QAEE,QAAQ,OAAO,QAAQ,YAAY,EACrC,SACC,gGACD,CAAC,CACD,UAAU,CACV,SACA,0GACA;CACF,iBAAiB,EACf,QAAQ,CACR,UAAU,CACV,SACA,kPACA;CACF,QAAQ,EAAE,aAA+C,KAAK;CAC9D,CAAC;AAMF,MAAa,uBACZ,UAA+C,EAAE,KAC7C;CACJ,MAAM,OAAO,iCAAiC,MAAM,QAAQ;AAE5D,QAAO;EACN,IAAI;EACJ,QAAQ,YAAY,QAAQ,SAAS,OAAO;EAC5C,WAAW;GACV,YAAY,WAAW,KAAK;GAC5B,aAAa,YAAY,KAAK;GAC9B;GACA;GACA;GACA;EACD,cAAc;EACd"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/device-authorization/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport * as z from \"zod\";\nimport { mergeSchema } from \"../../db\";\nimport type { InferOptionSchema } from \"../../types/plugins\";\nimport type { TimeString } from \"../../utils/time\";\nimport { ms } from \"../../utils/time\";\nimport { DEVICE_AUTHORIZATION_ERROR_CODES } from \"./error-codes\";\nimport {\n\tdeviceApprove,\n\tdeviceCode,\n\tdeviceDeny,\n\tdeviceToken,\n\tdeviceVerify,\n} from \"./routes\";\nimport { schema } from \"./schema\";\n\nconst timeStringSchema = z.custom<TimeString>(\n\t(val) => {\n\t\tif (typeof val !== \"string\") return false;\n\t\ttry {\n\t\t\tms(val as TimeString);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\t{\n\t\tmessage:\n\t\t\t\"Invalid time string format. Use formats like '30m', '5s', '1h', etc.\",\n\t},\n);\n\nexport const deviceAuthorizationOptionsSchema = z.object({\n\texpiresIn: timeStringSchema\n\t\t.default(\"30m\")\n\t\t.describe(\n\t\t\t\"Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tinterval: timeStringSchema\n\t\t.default(\"5s\")\n\t\t.describe(\n\t\t\t\"Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tdeviceCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(40)\n\t\t.describe(\n\t\t\t\"Length of the device code to be generated. Default is 40 characters.\",\n\t\t),\n\tuserCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(8)\n\t\t.describe(\n\t\t\t\"Length of the user code to be generated. Default is 8 characters.\",\n\t\t),\n\tgenerateDeviceCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateDeviceCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a device code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tgenerateUserCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateUserCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a user code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tvalidateClient: z\n\t\t.custom<(clientId: string) => boolean | Promise<boolean>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"validateClient must be a function that returns a boolean or a promise that resolves to a boolean.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to validate the client ID. If not provided, no validation will be performed.\",\n\t\t),\n\tonDeviceAuthRequest: z\n\t\t.custom<\n\t\t\t(clientId: string, scope: string | undefined) => void | Promise<void>\n\t\t>((val) => typeof val === \"function\", {\n\t\t\tmessage:\n\t\t\t\t\"onDeviceAuthRequest must be a function that returns void or a promise that resolves to void.\",\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to handle device authorization requests. If not provided, no additional actions will be taken.\",\n\t\t),\n\tverificationUri: z\n\t\t.string()\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device.\",\n\t\t),\n\tschema: z.custom<InferOptionSchema<typeof schema>>(() => true),\n});\n\nexport type DeviceAuthorizationOptions = z.infer<\n\ttypeof deviceAuthorizationOptionsSchema\n>;\n\nexport const deviceAuthorization = (\n\toptions: Partial<DeviceAuthorizationOptions> = {},\n) => {\n\tconst opts = deviceAuthorizationOptionsSchema.parse(options);\n\n\treturn {\n\t\tid: \"device-authorization\",\n\t\tschema: mergeSchema(schema, options?.schema),\n\t\tendpoints: {\n\t\t\tdeviceCode: deviceCode(opts),\n\t\t\tdeviceToken: deviceToken(opts),\n\t\t\tdeviceVerify,\n\t\t\tdeviceApprove,\n\t\t\tdeviceDeny,\n\t\t},\n\t\t$ERROR_CODES: DEVICE_AUTHORIZATION_ERROR_CODES,\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport type * from \"../../utils/time\";\n"],"mappings":";;;;;;;;;AAgBA,MAAM,mBAAmB,EAAE,QACzB,QAAQ;AACR,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;AACH,KAAG,IAAkB;AACrB,SAAO;SACA;AACP,SAAO;;GAGT,EACC,SACC,wEACD,CACD;AAED,MAAa,mCAAmC,EAAE,OAAO;CACxD,WAAW,iBACT,QAAQ,MAAM,CACd,SACA,0FACA;CACF,UAAU,iBACR,QAAQ,KAAK,CACb,SACA,qFACA;CACF,kBAAkB,EAChB,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,GAAG,CACX,SACA,uEACA;CACF,gBAAgB,EACd,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,EAAE,CACV,SACA,oEACA;CACF,oBAAoB,EAClB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,uGACD,CACD,CACA,UAAU,CACV,SACA,uGACA;CACF,kBAAkB,EAChB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,qGACA;CACF,gBAAgB,EACd,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,wFACA;CACF,qBAAqB,EACnB,QAEE,QAAQ,OAAO,QAAQ,YAAY,EACrC,SACC,gGACD,CAAC,CACD,UAAU,CACV,SACA,0GACA;CACF,iBAAiB,EACf,QAAQ,CACR,UAAU,CACV,SACA,kPACA;CACF,QAAQ,EAAE,aAA+C,KAAK;CAC9D,CAAC;AAMF,MAAa,uBACZ,UAA+C,EAAE,KAC7C;CACJ,MAAM,OAAO,iCAAiC,MAAM,QAAQ;AAE5D,QAAO;EACN,IAAI;EACJ,QAAQ,YAAY,QAAQ,SAAS,OAAO;EAC5C,WAAW;GACV,YAAY,WAAW,KAAK;GAC5B,aAAa,YAAY,KAAK;GAC9B;GACA;GACA;GACA;EACD,cAAc;EACd;EACA"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { EmailOTPOptions } from "./types.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _better_auth_core0 from "@better-auth/core";
|
|
3
3
|
import * as _better_auth_core_db0 from "@better-auth/core/db";
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
4
|
+
import * as zod0 from "zod";
|
|
5
|
+
import * as better_call0 from "better-call";
|
|
6
|
+
import * as zod_v4_core0 from "zod/v4/core";
|
|
7
7
|
|
|
8
8
|
//#region src/plugins/email-otp/index.d.ts
|
|
9
9
|
declare const emailOTP: (options: EmailOTPOptions) => {
|
|
10
10
|
id: "email-otp";
|
|
11
|
-
init(ctx:
|
|
11
|
+
init(ctx: _better_auth_core0.AuthContext): {
|
|
12
12
|
options: {
|
|
13
13
|
emailVerification: {
|
|
14
14
|
sendVerificationEmail(data: {
|
|
@@ -20,16 +20,16 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
20
20
|
};
|
|
21
21
|
} | undefined;
|
|
22
22
|
endpoints: {
|
|
23
|
-
sendVerificationOTP:
|
|
23
|
+
sendVerificationOTP: better_call0.StrictEndpoint<"/email-otp/send-verification-otp", {
|
|
24
24
|
method: "POST";
|
|
25
|
-
body:
|
|
26
|
-
email:
|
|
27
|
-
type:
|
|
25
|
+
body: zod0.ZodObject<{
|
|
26
|
+
email: zod0.ZodString;
|
|
27
|
+
type: zod0.ZodEnum<{
|
|
28
28
|
"sign-in": "sign-in";
|
|
29
29
|
"email-verification": "email-verification";
|
|
30
30
|
"forget-password": "forget-password";
|
|
31
31
|
}>;
|
|
32
|
-
},
|
|
32
|
+
}, zod_v4_core0.$strip>;
|
|
33
33
|
metadata: {
|
|
34
34
|
openapi: {
|
|
35
35
|
operationId: string;
|
|
@@ -56,16 +56,16 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
56
56
|
}, {
|
|
57
57
|
success: boolean;
|
|
58
58
|
}>;
|
|
59
|
-
createVerificationOTP:
|
|
59
|
+
createVerificationOTP: better_call0.StrictEndpoint<string, {
|
|
60
60
|
method: "POST";
|
|
61
|
-
body:
|
|
62
|
-
email:
|
|
63
|
-
type:
|
|
61
|
+
body: zod0.ZodObject<{
|
|
62
|
+
email: zod0.ZodString;
|
|
63
|
+
type: zod0.ZodEnum<{
|
|
64
64
|
"sign-in": "sign-in";
|
|
65
65
|
"email-verification": "email-verification";
|
|
66
66
|
"forget-password": "forget-password";
|
|
67
67
|
}>;
|
|
68
|
-
},
|
|
68
|
+
}, zod_v4_core0.$strip>;
|
|
69
69
|
metadata: {
|
|
70
70
|
openapi: {
|
|
71
71
|
operationId: string;
|
|
@@ -85,16 +85,16 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
85
85
|
};
|
|
86
86
|
};
|
|
87
87
|
}, string>;
|
|
88
|
-
getVerificationOTP:
|
|
88
|
+
getVerificationOTP: better_call0.StrictEndpoint<string, {
|
|
89
89
|
method: "GET";
|
|
90
|
-
query:
|
|
91
|
-
email:
|
|
92
|
-
type:
|
|
90
|
+
query: zod0.ZodObject<{
|
|
91
|
+
email: zod0.ZodString;
|
|
92
|
+
type: zod0.ZodEnum<{
|
|
93
93
|
"sign-in": "sign-in";
|
|
94
94
|
"email-verification": "email-verification";
|
|
95
95
|
"forget-password": "forget-password";
|
|
96
96
|
}>;
|
|
97
|
-
},
|
|
97
|
+
}, zod_v4_core0.$strip>;
|
|
98
98
|
metadata: {
|
|
99
99
|
openapi: {
|
|
100
100
|
operationId: string;
|
|
@@ -126,17 +126,17 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
126
126
|
} | {
|
|
127
127
|
otp: string;
|
|
128
128
|
}>;
|
|
129
|
-
checkVerificationOTP:
|
|
129
|
+
checkVerificationOTP: better_call0.StrictEndpoint<"/email-otp/check-verification-otp", {
|
|
130
130
|
method: "POST";
|
|
131
|
-
body:
|
|
132
|
-
email:
|
|
133
|
-
type:
|
|
131
|
+
body: zod0.ZodObject<{
|
|
132
|
+
email: zod0.ZodString;
|
|
133
|
+
type: zod0.ZodEnum<{
|
|
134
134
|
"sign-in": "sign-in";
|
|
135
135
|
"email-verification": "email-verification";
|
|
136
136
|
"forget-password": "forget-password";
|
|
137
137
|
}>;
|
|
138
|
-
otp:
|
|
139
|
-
},
|
|
138
|
+
otp: zod0.ZodString;
|
|
139
|
+
}, zod_v4_core0.$strip>;
|
|
140
140
|
metadata: {
|
|
141
141
|
openapi: {
|
|
142
142
|
operationId: string;
|
|
@@ -163,12 +163,12 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
163
163
|
}, {
|
|
164
164
|
success: boolean;
|
|
165
165
|
}>;
|
|
166
|
-
verifyEmailOTP:
|
|
166
|
+
verifyEmailOTP: better_call0.StrictEndpoint<"/email-otp/verify-email", {
|
|
167
167
|
method: "POST";
|
|
168
|
-
body:
|
|
169
|
-
email:
|
|
170
|
-
otp:
|
|
171
|
-
},
|
|
168
|
+
body: zod0.ZodObject<{
|
|
169
|
+
email: zod0.ZodString;
|
|
170
|
+
otp: zod0.ZodString;
|
|
171
|
+
}, zod_v4_core0.$strip>;
|
|
172
172
|
metadata: {
|
|
173
173
|
openapi: {
|
|
174
174
|
description: string;
|
|
@@ -227,12 +227,12 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
227
227
|
updatedAt: Date;
|
|
228
228
|
};
|
|
229
229
|
}>;
|
|
230
|
-
signInEmailOTP:
|
|
230
|
+
signInEmailOTP: better_call0.StrictEndpoint<"/sign-in/email-otp", {
|
|
231
231
|
method: "POST";
|
|
232
|
-
body:
|
|
233
|
-
email:
|
|
234
|
-
otp:
|
|
235
|
-
},
|
|
232
|
+
body: zod0.ZodObject<{
|
|
233
|
+
email: zod0.ZodString;
|
|
234
|
+
otp: zod0.ZodString;
|
|
235
|
+
}, zod_v4_core0.$strip>;
|
|
236
236
|
metadata: {
|
|
237
237
|
openapi: {
|
|
238
238
|
operationId: string;
|
|
@@ -273,11 +273,11 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
273
273
|
updatedAt: Date;
|
|
274
274
|
};
|
|
275
275
|
}>;
|
|
276
|
-
forgetPasswordEmailOTP:
|
|
276
|
+
forgetPasswordEmailOTP: better_call0.StrictEndpoint<"/forget-password/email-otp", {
|
|
277
277
|
method: "POST";
|
|
278
|
-
body:
|
|
279
|
-
email:
|
|
280
|
-
},
|
|
278
|
+
body: zod0.ZodObject<{
|
|
279
|
+
email: zod0.ZodString;
|
|
280
|
+
}, zod_v4_core0.$strip>;
|
|
281
281
|
metadata: {
|
|
282
282
|
openapi: {
|
|
283
283
|
operationId: string;
|
|
@@ -305,13 +305,13 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
305
305
|
}, {
|
|
306
306
|
success: boolean;
|
|
307
307
|
}>;
|
|
308
|
-
resetPasswordEmailOTP:
|
|
308
|
+
resetPasswordEmailOTP: better_call0.StrictEndpoint<"/email-otp/reset-password", {
|
|
309
309
|
method: "POST";
|
|
310
|
-
body:
|
|
311
|
-
email:
|
|
312
|
-
otp:
|
|
313
|
-
password:
|
|
314
|
-
},
|
|
310
|
+
body: zod0.ZodObject<{
|
|
311
|
+
email: zod0.ZodString;
|
|
312
|
+
otp: zod0.ZodString;
|
|
313
|
+
password: zod0.ZodString;
|
|
314
|
+
}, zod_v4_core0.$strip>;
|
|
315
315
|
metadata: {
|
|
316
316
|
openapi: {
|
|
317
317
|
operationId: string;
|
|
@@ -341,8 +341,8 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
341
341
|
};
|
|
342
342
|
hooks: {
|
|
343
343
|
after: {
|
|
344
|
-
matcher(context:
|
|
345
|
-
handler: (inputContext:
|
|
344
|
+
matcher(context: _better_auth_core0.HookEndpointContext): boolean;
|
|
345
|
+
handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>;
|
|
346
346
|
}[];
|
|
347
347
|
};
|
|
348
348
|
$ERROR_CODES: {
|
|
@@ -367,6 +367,7 @@ declare const emailOTP: (options: EmailOTPOptions) => {
|
|
|
367
367
|
window: number;
|
|
368
368
|
max: number;
|
|
369
369
|
})[];
|
|
370
|
+
options: EmailOTPOptions;
|
|
370
371
|
};
|
|
371
372
|
//#endregion
|
|
372
373
|
export { type EmailOTPOptions, emailOTP };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/email-otp/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { generateRandomString } from \"../../crypto\";\nimport { getDate } from \"../../utils/date\";\nimport { getEndpointResponse } from \"../../utils/plugin-helper\";\nimport { storeOTP } from \"./otp-token\";\nimport {\n\tcheckVerificationOTP,\n\tcreateVerificationOTP,\n\tERROR_CODES,\n\tforgetPasswordEmailOTP,\n\tgetVerificationOTP,\n\tresetPasswordEmailOTP,\n\tsendVerificationOTP,\n\tsignInEmailOTP,\n\tverifyEmailOTP,\n} from \"./routes\";\nimport type { EmailOTPOptions } from \"./types\";\n\nexport type { EmailOTPOptions } from \"./types\";\n\nconst defaultOTPGenerator = (options: EmailOTPOptions) =>\n\tgenerateRandomString(options.otpLength ?? 6, \"0-9\");\n\nexport const emailOTP = (options: EmailOTPOptions) => {\n\tconst opts = {\n\t\texpiresIn: 5 * 60,\n\t\tgenerateOTP: () => defaultOTPGenerator(options),\n\t\tstoreOTP: \"plain\",\n\t\t...options,\n\t} satisfies EmailOTPOptions;\n\n\tconst sendVerificationOTPAction = sendVerificationOTP(opts);\n\n\treturn {\n\t\tid: \"email-otp\",\n\t\tinit(ctx) {\n\t\t\tif (!opts.overrideDefaultEmailVerification) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\temailVerification: {\n\t\t\t\t\t\tasync sendVerificationEmail(data, request) {\n\t\t\t\t\t\t\tawait sendVerificationOTPAction({\n\t\t\t\t\t\t\t\t//@ts-expect-error - we need to pass the context\n\t\t\t\t\t\t\t\tcontext: ctx,\n\t\t\t\t\t\t\t\trequest: request,\n\t\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\t\temail: data.user.email,\n\t\t\t\t\t\t\t\t\ttype: \"email-verification\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tendpoints: {\n\t\t\tsendVerificationOTP: sendVerificationOTPAction,\n\t\t\tcreateVerificationOTP: createVerificationOTP(opts),\n\t\t\tgetVerificationOTP: getVerificationOTP(opts),\n\t\t\tcheckVerificationOTP: checkVerificationOTP(opts),\n\t\t\tverifyEmailOTP: verifyEmailOTP(opts),\n\t\t\tsignInEmailOTP: signInEmailOTP(opts),\n\t\t\tforgetPasswordEmailOTP: forgetPasswordEmailOTP(opts),\n\t\t\tresetPasswordEmailOTP: resetPasswordEmailOTP(opts),\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher(context) {\n\t\t\t\t\t\treturn !!(\n\t\t\t\t\t\t\tcontext.path?.startsWith(\"/sign-up\") &&\n\t\t\t\t\t\t\topts.sendVerificationOnSignUp &&\n\t\t\t\t\t\t\t!opts.overrideDefaultEmailVerification\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst response = await getEndpointResponse<{\n\t\t\t\t\t\t\tuser: { email: string };\n\t\t\t\t\t\t}>(ctx);\n\t\t\t\t\t\tconst email = response?.user.email;\n\t\t\t\t\t\tif (email) {\n\t\t\t\t\t\t\tconst otp =\n\t\t\t\t\t\t\t\topts.generateOTP({ email, type: ctx.body.type }, ctx) ||\n\t\t\t\t\t\t\t\tdefaultOTPGenerator(opts);\n\t\t\t\t\t\t\tlet storedOTP = await storeOTP(ctx, opts, otp);\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\t\t\tvalue: `${storedOTP}:0`,\n\t\t\t\t\t\t\t\tidentifier: `email-verification-otp-${email}`,\n\t\t\t\t\t\t\t\texpiresAt: getDate(opts.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tawait options.sendVerificationOTP(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\t\t\totp,\n\t\t\t\t\t\t\t\t\ttype: \"email-verification\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t$ERROR_CODES: ERROR_CODES,\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/send-verification-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/check-verification-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/verify-email\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/sign-in/email-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;;;AAqBA,MAAM,uBAAuB,YAC5B,qBAAqB,QAAQ,aAAa,GAAG,MAAM;AAEpD,MAAa,YAAY,YAA6B;CACrD,MAAM,OAAO;EACZ,WAAW;EACX,mBAAmB,oBAAoB,QAAQ;EAC/C,UAAU;EACV,GAAG;EACH;CAED,MAAM,4BAA4B,oBAAoB,KAAK;AAE3D,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,OAAI,CAAC,KAAK,iCACT;AAED,UAAO,EACN,SAAS,EACR,mBAAmB,EAClB,MAAM,sBAAsB,MAAM,SAAS;AAC1C,UAAM,0BAA0B;KAE/B,SAAS;KACA;KACT,MAAM;MACL,OAAO,KAAK,KAAK;MACjB,MAAM;MACN;KACD;KACA,CAAC;MAEH,EACD,EACD;;EAEF,WAAW;GACV,qBAAqB;GACrB,uBAAuB,sBAAsB,KAAK;GAClD,oBAAoB,mBAAmB,KAAK;GAC5C,sBAAsB,qBAAqB,KAAK;GAChD,gBAAgB,eAAe,KAAK;GACpC,gBAAgB,eAAe,KAAK;GACpC,wBAAwB,uBAAuB,KAAK;GACpD,uBAAuB,sBAAsB,KAAK;GAClD;EACD,OAAO,EACN,OAAO,CACN;GACC,QAAQ,SAAS;AAChB,WAAO,CAAC,EACP,QAAQ,MAAM,WAAW,WAAW,IACpC,KAAK,4BACL,CAAC,KAAK;;GAGR,SAAS,qBAAqB,OAAO,QAAQ;IAI5C,MAAM,SAHW,MAAM,oBAEpB,IAAI,GACiB,KAAK;AAC7B,QAAI,OAAO;KACV,MAAM,MACL,KAAK,YAAY;MAAE;MAAO,MAAM,IAAI,KAAK;MAAM,EAAE,IAAI,IACrD,oBAAoB,KAAK;KAC1B,IAAI,YAAY,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9C,WAAM,IAAI,QAAQ,gBAAgB,wBAAwB;MACzD,OAAO,GAAG,UAAU;MACpB,YAAY,0BAA0B;MACtC,WAAW,QAAQ,KAAK,WAAW,MAAM;MACzC,CAAC;AACF,WAAM,QAAQ,oBACb;MACC;MACA;MACA,MAAM;MACN,EACD,IACA;;KAED;GACF,CACD,EACD;EACD,cAAc;EACd,WAAW;GACV;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;EACD"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/email-otp/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { generateRandomString } from \"../../crypto\";\nimport { getDate } from \"../../utils/date\";\nimport { getEndpointResponse } from \"../../utils/plugin-helper\";\nimport { storeOTP } from \"./otp-token\";\nimport {\n\tcheckVerificationOTP,\n\tcreateVerificationOTP,\n\tERROR_CODES,\n\tforgetPasswordEmailOTP,\n\tgetVerificationOTP,\n\tresetPasswordEmailOTP,\n\tsendVerificationOTP,\n\tsignInEmailOTP,\n\tverifyEmailOTP,\n} from \"./routes\";\nimport type { EmailOTPOptions } from \"./types\";\n\nexport type { EmailOTPOptions } from \"./types\";\n\nconst defaultOTPGenerator = (options: EmailOTPOptions) =>\n\tgenerateRandomString(options.otpLength ?? 6, \"0-9\");\n\nexport const emailOTP = (options: EmailOTPOptions) => {\n\tconst opts = {\n\t\texpiresIn: 5 * 60,\n\t\tgenerateOTP: () => defaultOTPGenerator(options),\n\t\tstoreOTP: \"plain\",\n\t\t...options,\n\t} satisfies EmailOTPOptions;\n\n\tconst sendVerificationOTPAction = sendVerificationOTP(opts);\n\n\treturn {\n\t\tid: \"email-otp\",\n\t\tinit(ctx) {\n\t\t\tif (!opts.overrideDefaultEmailVerification) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\temailVerification: {\n\t\t\t\t\t\tasync sendVerificationEmail(data, request) {\n\t\t\t\t\t\t\tawait sendVerificationOTPAction({\n\t\t\t\t\t\t\t\t//@ts-expect-error - we need to pass the context\n\t\t\t\t\t\t\t\tcontext: ctx,\n\t\t\t\t\t\t\t\trequest: request,\n\t\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\t\temail: data.user.email,\n\t\t\t\t\t\t\t\t\ttype: \"email-verification\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tendpoints: {\n\t\t\tsendVerificationOTP: sendVerificationOTPAction,\n\t\t\tcreateVerificationOTP: createVerificationOTP(opts),\n\t\t\tgetVerificationOTP: getVerificationOTP(opts),\n\t\t\tcheckVerificationOTP: checkVerificationOTP(opts),\n\t\t\tverifyEmailOTP: verifyEmailOTP(opts),\n\t\t\tsignInEmailOTP: signInEmailOTP(opts),\n\t\t\tforgetPasswordEmailOTP: forgetPasswordEmailOTP(opts),\n\t\t\tresetPasswordEmailOTP: resetPasswordEmailOTP(opts),\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher(context) {\n\t\t\t\t\t\treturn !!(\n\t\t\t\t\t\t\tcontext.path?.startsWith(\"/sign-up\") &&\n\t\t\t\t\t\t\topts.sendVerificationOnSignUp &&\n\t\t\t\t\t\t\t!opts.overrideDefaultEmailVerification\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst response = await getEndpointResponse<{\n\t\t\t\t\t\t\tuser: { email: string };\n\t\t\t\t\t\t}>(ctx);\n\t\t\t\t\t\tconst email = response?.user.email;\n\t\t\t\t\t\tif (email) {\n\t\t\t\t\t\t\tconst otp =\n\t\t\t\t\t\t\t\topts.generateOTP({ email, type: ctx.body.type }, ctx) ||\n\t\t\t\t\t\t\t\tdefaultOTPGenerator(opts);\n\t\t\t\t\t\t\tlet storedOTP = await storeOTP(ctx, opts, otp);\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\t\t\tvalue: `${storedOTP}:0`,\n\t\t\t\t\t\t\t\tidentifier: `email-verification-otp-${email}`,\n\t\t\t\t\t\t\t\texpiresAt: getDate(opts.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tawait options.sendVerificationOTP(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\t\t\totp,\n\t\t\t\t\t\t\t\t\ttype: \"email-verification\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t$ERROR_CODES: ERROR_CODES,\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/send-verification-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/check-verification-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/email-otp/verify-email\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn path === \"/sign-in/email-otp\";\n\t\t\t\t},\n\t\t\t\twindow: 60,\n\t\t\t\tmax: 3,\n\t\t\t},\n\t\t],\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;;;AAqBA,MAAM,uBAAuB,YAC5B,qBAAqB,QAAQ,aAAa,GAAG,MAAM;AAEpD,MAAa,YAAY,YAA6B;CACrD,MAAM,OAAO;EACZ,WAAW;EACX,mBAAmB,oBAAoB,QAAQ;EAC/C,UAAU;EACV,GAAG;EACH;CAED,MAAM,4BAA4B,oBAAoB,KAAK;AAE3D,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,OAAI,CAAC,KAAK,iCACT;AAED,UAAO,EACN,SAAS,EACR,mBAAmB,EAClB,MAAM,sBAAsB,MAAM,SAAS;AAC1C,UAAM,0BAA0B;KAE/B,SAAS;KACA;KACT,MAAM;MACL,OAAO,KAAK,KAAK;MACjB,MAAM;MACN;KACD;KACA,CAAC;MAEH,EACD,EACD;;EAEF,WAAW;GACV,qBAAqB;GACrB,uBAAuB,sBAAsB,KAAK;GAClD,oBAAoB,mBAAmB,KAAK;GAC5C,sBAAsB,qBAAqB,KAAK;GAChD,gBAAgB,eAAe,KAAK;GACpC,gBAAgB,eAAe,KAAK;GACpC,wBAAwB,uBAAuB,KAAK;GACpD,uBAAuB,sBAAsB,KAAK;GAClD;EACD,OAAO,EACN,OAAO,CACN;GACC,QAAQ,SAAS;AAChB,WAAO,CAAC,EACP,QAAQ,MAAM,WAAW,WAAW,IACpC,KAAK,4BACL,CAAC,KAAK;;GAGR,SAAS,qBAAqB,OAAO,QAAQ;IAI5C,MAAM,SAHW,MAAM,oBAEpB,IAAI,GACiB,KAAK;AAC7B,QAAI,OAAO;KACV,MAAM,MACL,KAAK,YAAY;MAAE;MAAO,MAAM,IAAI,KAAK;MAAM,EAAE,IAAI,IACrD,oBAAoB,KAAK;KAC1B,IAAI,YAAY,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9C,WAAM,IAAI,QAAQ,gBAAgB,wBAAwB;MACzD,OAAO,GAAG,UAAU;MACpB,YAAY,0BAA0B;MACtC,WAAW,QAAQ,KAAK,WAAW,MAAM;MACzC,CAAC;AACF,WAAM,QAAQ,oBACb;MACC;MACA;MACA,MAAM;MACN,EACD,IACA;;KAED;GACF,CACD,EACD;EACD,cAAc;EACd,WAAW;GACV;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;IACC,YAAY,MAAM;AACjB,YAAO,SAAS;;IAEjB,QAAQ;IACR,KAAK;IACL;GACD;EACD;EACA"}
|
|
@@ -175,6 +175,7 @@ declare const genericOAuth: (options: GenericOAuthOptions) => {
|
|
|
175
175
|
redirect: boolean;
|
|
176
176
|
}>;
|
|
177
177
|
};
|
|
178
|
+
options: GenericOAuthOptions;
|
|
178
179
|
$ERROR_CODES: {
|
|
179
180
|
readonly INVALID_OAUTH_CONFIGURATION: "Invalid OAuth configuration";
|
|
180
181
|
readonly TOKEN_URL_NOT_FOUND: "Invalid OAuth configuration. Token URL not found.";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/generic-oauth/index.ts"],"sourcesContent":["import type { AuthContext, BetterAuthPlugin } from \"@better-auth/core\";\nimport type { OAuth2Tokens, OAuthProvider } from \"@better-auth/core/oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"@better-auth/core/oauth2\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"better-call\";\nimport { GENERIC_OAUTH_ERROR_CODES } from \"./error-codes\";\nimport {\n\tgetUserInfo,\n\toAuth2Callback,\n\toAuth2LinkAccount,\n\tsignInWithOAuth2,\n} from \"./routes\";\nimport type { GenericOAuthConfig, GenericOAuthOptions } from \"./types\";\n\nexport * from \"./providers\";\nexport type { GenericOAuthConfig, GenericOAuthOptions } from \"./types\";\n\n/**\n * Base type for OAuth provider options.\n * Extracts common fields from GenericOAuthConfig and makes clientSecret required.\n */\nexport type BaseOAuthProviderOptions = Omit<\n\tPick<\n\t\tGenericOAuthConfig,\n\t\t| \"clientId\"\n\t\t| \"clientSecret\"\n\t\t| \"scopes\"\n\t\t| \"redirectURI\"\n\t\t| \"pkce\"\n\t\t| \"disableImplicitSignUp\"\n\t\t| \"disableSignUp\"\n\t\t| \"overrideUserInfo\"\n\t>,\n\t\"clientSecret\"\n> & {\n\t/** OAuth client secret (required for provider options) */\n\tclientSecret: string;\n};\n\n/**\n * A generic OAuth plugin that can be used to add OAuth support to any provider\n */\nexport const genericOAuth = (options: GenericOAuthOptions) => {\n\treturn {\n\t\tid: \"generic-oauth\",\n\t\tinit: (ctx: AuthContext) => {\n\t\t\tconst genericProviders = options.config.map((c) => {\n\t\t\t\tlet finalUserInfoUrl = c.userInfoUrl;\n\t\t\t\treturn {\n\t\t\t\t\tid: c.providerId,\n\t\t\t\t\tname: c.providerId,\n\t\t\t\t\tasync createAuthorizationURL(data: {\n\t\t\t\t\t\tstate: string;\n\t\t\t\t\t\tcodeVerifier: string;\n\t\t\t\t\t\tscopes?: string[] | undefined;\n\t\t\t\t\t\tredirectURI: string;\n\t\t\t\t\t\tdisplay?: string | undefined;\n\t\t\t\t\t\tloginHint?: string | undefined;\n\t\t\t\t\t}) {\n\t\t\t\t\t\tlet finalAuthUrl = c.authorizationUrl;\n\t\t\t\t\t\tif (!finalAuthUrl && c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\tauthorization_endpoint: string;\n\t\t\t\t\t\t\t\tuserinfo_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalAuthUrl = discovery.data.authorization_endpoint;\n\t\t\t\t\t\t\t\tfinalUserInfoUrl =\n\t\t\t\t\t\t\t\t\tfinalUserInfoUrl ?? discovery.data.userinfo_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalAuthUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn createAuthorizationURL({\n\t\t\t\t\t\t\tid: c.providerId,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t\tredirectURI: c.redirectURI,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tauthorizationEndpoint: finalAuthUrl,\n\t\t\t\t\t\t\tstate: data.state,\n\t\t\t\t\t\t\tcodeVerifier: c.pkce ? data.codeVerifier : undefined,\n\t\t\t\t\t\t\tscopes: c.scopes || [],\n\t\t\t\t\t\t\tredirectURI: `${ctx.baseURL}/oauth2/callback/${c.providerId}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync validateAuthorizationCode(data: {\n\t\t\t\t\t\tcode: string;\n\t\t\t\t\t\tredirectURI: string;\n\t\t\t\t\t\tcodeVerifier?: string | undefined;\n\t\t\t\t\t\tdeviceId?: string | undefined;\n\t\t\t\t\t}) {\n\t\t\t\t\t\t// Use custom getToken if provided\n\t\t\t\t\t\tif (c.getToken) {\n\t\t\t\t\t\t\treturn c.getToken(data);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Standard token exchange flow\n\t\t\t\t\t\tlet finalTokenUrl = c.tokenUrl;\n\t\t\t\t\t\tif (c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t\t\tuserinfo_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t\t\tfinalUserInfoUrl = discovery.data.userinfo_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalTokenUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn validateAuthorizationCode({\n\t\t\t\t\t\t\theaders: c.authorizationHeaders,\n\t\t\t\t\t\t\tcode: data.code,\n\t\t\t\t\t\t\tcodeVerifier: data.codeVerifier,\n\t\t\t\t\t\t\tredirectURI: data.redirectURI,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t\tredirectURI: c.redirectURI,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttokenEndpoint: finalTokenUrl,\n\t\t\t\t\t\t\tauthentication: c.authentication,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync refreshAccessToken(\n\t\t\t\t\t\trefreshToken: string,\n\t\t\t\t\t): Promise<OAuth2Tokens> {\n\t\t\t\t\t\tlet finalTokenUrl = c.tokenUrl;\n\t\t\t\t\t\tif (c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalTokenUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tauthentication: c.authentication,\n\t\t\t\t\t\t\ttokenEndpoint: finalTokenUrl,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync getUserInfo(tokens: OAuth2Tokens) {\n\t\t\t\t\t\tconst userInfo = c.getUserInfo\n\t\t\t\t\t\t\t? await c.getUserInfo(tokens)\n\t\t\t\t\t\t\t: await getUserInfo(tokens, finalUserInfoUrl);\n\t\t\t\t\t\tif (!userInfo) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst userMap = await c.mapProfileToUser?.(userInfo);\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: userInfo?.id,\n\t\t\t\t\t\t\t\temail: userInfo?.email,\n\t\t\t\t\t\t\t\temailVerified: userInfo?.emailVerified,\n\t\t\t\t\t\t\t\timage: userInfo?.image,\n\t\t\t\t\t\t\t\tname: userInfo?.name,\n\t\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdata: userInfo,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t\toptions: {\n\t\t\t\t\t\toverrideUserInfoOnSignIn: c.overrideUserInfo,\n\t\t\t\t\t},\n\t\t\t\t} as OAuthProvider;\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tsocialProviders: genericProviders.concat(ctx.socialProviders),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tendpoints: {\n\t\t\tsignInWithOAuth2: signInWithOAuth2(options),\n\t\t\toAuth2Callback: oAuth2Callback(options),\n\t\t\toAuth2LinkAccount: oAuth2LinkAccount(options),\n\t\t},\n\t\t$ERROR_CODES: GENERIC_OAUTH_ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/generic-oauth/index.ts"],"sourcesContent":["import type { AuthContext, BetterAuthPlugin } from \"@better-auth/core\";\nimport type { OAuth2Tokens, OAuthProvider } from \"@better-auth/core/oauth2\";\nimport {\n\tcreateAuthorizationURL,\n\trefreshAccessToken,\n\tvalidateAuthorizationCode,\n} from \"@better-auth/core/oauth2\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"better-call\";\nimport { GENERIC_OAUTH_ERROR_CODES } from \"./error-codes\";\nimport {\n\tgetUserInfo,\n\toAuth2Callback,\n\toAuth2LinkAccount,\n\tsignInWithOAuth2,\n} from \"./routes\";\nimport type { GenericOAuthConfig, GenericOAuthOptions } from \"./types\";\n\nexport * from \"./providers\";\nexport type { GenericOAuthConfig, GenericOAuthOptions } from \"./types\";\n\n/**\n * Base type for OAuth provider options.\n * Extracts common fields from GenericOAuthConfig and makes clientSecret required.\n */\nexport type BaseOAuthProviderOptions = Omit<\n\tPick<\n\t\tGenericOAuthConfig,\n\t\t| \"clientId\"\n\t\t| \"clientSecret\"\n\t\t| \"scopes\"\n\t\t| \"redirectURI\"\n\t\t| \"pkce\"\n\t\t| \"disableImplicitSignUp\"\n\t\t| \"disableSignUp\"\n\t\t| \"overrideUserInfo\"\n\t>,\n\t\"clientSecret\"\n> & {\n\t/** OAuth client secret (required for provider options) */\n\tclientSecret: string;\n};\n\n/**\n * A generic OAuth plugin that can be used to add OAuth support to any provider\n */\nexport const genericOAuth = (options: GenericOAuthOptions) => {\n\treturn {\n\t\tid: \"generic-oauth\",\n\t\tinit: (ctx: AuthContext) => {\n\t\t\tconst genericProviders = options.config.map((c) => {\n\t\t\t\tlet finalUserInfoUrl = c.userInfoUrl;\n\t\t\t\treturn {\n\t\t\t\t\tid: c.providerId,\n\t\t\t\t\tname: c.providerId,\n\t\t\t\t\tasync createAuthorizationURL(data: {\n\t\t\t\t\t\tstate: string;\n\t\t\t\t\t\tcodeVerifier: string;\n\t\t\t\t\t\tscopes?: string[] | undefined;\n\t\t\t\t\t\tredirectURI: string;\n\t\t\t\t\t\tdisplay?: string | undefined;\n\t\t\t\t\t\tloginHint?: string | undefined;\n\t\t\t\t\t}) {\n\t\t\t\t\t\tlet finalAuthUrl = c.authorizationUrl;\n\t\t\t\t\t\tif (!finalAuthUrl && c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\tauthorization_endpoint: string;\n\t\t\t\t\t\t\t\tuserinfo_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalAuthUrl = discovery.data.authorization_endpoint;\n\t\t\t\t\t\t\t\tfinalUserInfoUrl =\n\t\t\t\t\t\t\t\t\tfinalUserInfoUrl ?? discovery.data.userinfo_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalAuthUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.INVALID_OAUTH_CONFIGURATION,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn createAuthorizationURL({\n\t\t\t\t\t\t\tid: c.providerId,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t\tredirectURI: c.redirectURI,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tauthorizationEndpoint: finalAuthUrl,\n\t\t\t\t\t\t\tstate: data.state,\n\t\t\t\t\t\t\tcodeVerifier: c.pkce ? data.codeVerifier : undefined,\n\t\t\t\t\t\t\tscopes: c.scopes || [],\n\t\t\t\t\t\t\tredirectURI: `${ctx.baseURL}/oauth2/callback/${c.providerId}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync validateAuthorizationCode(data: {\n\t\t\t\t\t\tcode: string;\n\t\t\t\t\t\tredirectURI: string;\n\t\t\t\t\t\tcodeVerifier?: string | undefined;\n\t\t\t\t\t\tdeviceId?: string | undefined;\n\t\t\t\t\t}) {\n\t\t\t\t\t\t// Use custom getToken if provided\n\t\t\t\t\t\tif (c.getToken) {\n\t\t\t\t\t\t\treturn c.getToken(data);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Standard token exchange flow\n\t\t\t\t\t\tlet finalTokenUrl = c.tokenUrl;\n\t\t\t\t\t\tif (c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t\t\tuserinfo_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t\t\tfinalUserInfoUrl = discovery.data.userinfo_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalTokenUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn validateAuthorizationCode({\n\t\t\t\t\t\t\theaders: c.authorizationHeaders,\n\t\t\t\t\t\t\tcode: data.code,\n\t\t\t\t\t\t\tcodeVerifier: data.codeVerifier,\n\t\t\t\t\t\t\tredirectURI: data.redirectURI,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t\tredirectURI: c.redirectURI,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttokenEndpoint: finalTokenUrl,\n\t\t\t\t\t\t\tauthentication: c.authentication,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync refreshAccessToken(\n\t\t\t\t\t\trefreshToken: string,\n\t\t\t\t\t): Promise<OAuth2Tokens> {\n\t\t\t\t\t\tlet finalTokenUrl = c.tokenUrl;\n\t\t\t\t\t\tif (c.discoveryUrl) {\n\t\t\t\t\t\t\tconst discovery = await betterFetch<{\n\t\t\t\t\t\t\t\ttoken_endpoint: string;\n\t\t\t\t\t\t\t}>(c.discoveryUrl, {\n\t\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t\t\theaders: c.discoveryHeaders,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (discovery.data) {\n\t\t\t\t\t\t\t\tfinalTokenUrl = discovery.data.token_endpoint;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!finalTokenUrl) {\n\t\t\t\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\t\tmessage: GENERIC_OAUTH_ERROR_CODES.TOKEN_URL_NOT_FOUND,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn refreshAccessToken({\n\t\t\t\t\t\t\trefreshToken,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclientId: c.clientId,\n\t\t\t\t\t\t\t\tclientSecret: c.clientSecret,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tauthentication: c.authentication,\n\t\t\t\t\t\t\ttokenEndpoint: finalTokenUrl,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\tasync getUserInfo(tokens: OAuth2Tokens) {\n\t\t\t\t\t\tconst userInfo = c.getUserInfo\n\t\t\t\t\t\t\t? await c.getUserInfo(tokens)\n\t\t\t\t\t\t\t: await getUserInfo(tokens, finalUserInfoUrl);\n\t\t\t\t\t\tif (!userInfo) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst userMap = await c.mapProfileToUser?.(userInfo);\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\tid: userInfo?.id,\n\t\t\t\t\t\t\t\temail: userInfo?.email,\n\t\t\t\t\t\t\t\temailVerified: userInfo?.emailVerified,\n\t\t\t\t\t\t\t\timage: userInfo?.image,\n\t\t\t\t\t\t\t\tname: userInfo?.name,\n\t\t\t\t\t\t\t\t...userMap,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdata: userInfo,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t\toptions: {\n\t\t\t\t\t\toverrideUserInfoOnSignIn: c.overrideUserInfo,\n\t\t\t\t\t},\n\t\t\t\t} as OAuthProvider;\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tsocialProviders: genericProviders.concat(ctx.socialProviders),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tendpoints: {\n\t\t\tsignInWithOAuth2: signInWithOAuth2(options),\n\t\t\toAuth2Callback: oAuth2Callback(options),\n\t\t\toAuth2LinkAccount: oAuth2LinkAccount(options),\n\t\t},\n\t\toptions,\n\t\t$ERROR_CODES: GENERIC_OAUTH_ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _better_auth_core11 from "@better-auth/core";
|
|
2
2
|
|
|
3
3
|
//#region src/plugins/haveibeenpwned/index.d.ts
|
|
4
4
|
interface HaveIBeenPwnedOptions {
|
|
@@ -12,7 +12,7 @@ interface HaveIBeenPwnedOptions {
|
|
|
12
12
|
}
|
|
13
13
|
declare const haveIBeenPwned: (options?: HaveIBeenPwnedOptions | undefined) => {
|
|
14
14
|
id: "haveIBeenPwned";
|
|
15
|
-
init(ctx:
|
|
15
|
+
init(ctx: _better_auth_core11.AuthContext): {
|
|
16
16
|
context: {
|
|
17
17
|
password: {
|
|
18
18
|
hash(password: string): Promise<string>;
|
|
@@ -24,10 +24,11 @@ declare const haveIBeenPwned: (options?: HaveIBeenPwnedOptions | undefined) => {
|
|
|
24
24
|
minPasswordLength: number;
|
|
25
25
|
maxPasswordLength: number;
|
|
26
26
|
};
|
|
27
|
-
checkPassword: (userId: string, ctx:
|
|
27
|
+
checkPassword: (userId: string, ctx: _better_auth_core11.GenericEndpointContext<_better_auth_core11.BetterAuthOptions>) => Promise<boolean>;
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
|
+
options: HaveIBeenPwnedOptions | undefined;
|
|
31
32
|
$ERROR_CODES: {
|
|
32
33
|
readonly PASSWORD_COMPROMISED: "The password you entered has been compromised. Please choose a different password.";
|
|
33
34
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/haveibeenpwned/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { getCurrentAuthContext } from \"@better-auth/core/context\";\nimport { defineErrorCodes } from \"@better-auth/core/utils\";\nimport { createHash } from \"@better-auth/utils/hash\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"../../api\";\n\nconst ERROR_CODES = defineErrorCodes({\n\tPASSWORD_COMPROMISED:\n\t\t\"The password you entered has been compromised. Please choose a different password.\",\n});\n\nasync function checkPasswordCompromise(\n\tpassword: string,\n\tcustomMessage?: string | undefined,\n) {\n\tif (!password) return;\n\n\tconst sha1Hash = (\n\t\tawait createHash(\"SHA-1\", \"hex\").digest(password)\n\t).toUpperCase();\n\tconst prefix = sha1Hash.substring(0, 5);\n\tconst suffix = sha1Hash.substring(5);\n\ttry {\n\t\tconst { data, error } = await betterFetch<string>(\n\t\t\t`https://api.pwnedpasswords.com/range/${prefix}`,\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\t\"Add-Padding\": \"true\",\n\t\t\t\t\t\"User-Agent\": \"BetterAuth Password Checker\",\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: `Failed to check password. Status: ${error.status}`,\n\t\t\t});\n\t\t}\n\t\tconst lines = data.split(\"\\n\");\n\t\tconst found = lines.some(\n\t\t\t(line) => line.split(\":\")[0]!.toUpperCase() === suffix.toUpperCase(),\n\t\t);\n\n\t\tif (found) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: customMessage || ERROR_CODES.PASSWORD_COMPROMISED,\n\t\t\t\tcode: \"PASSWORD_COMPROMISED\",\n\t\t\t});\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof APIError) throw error;\n\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\tmessage: \"Failed to check password. Please try again later.\",\n\t\t});\n\t}\n}\n\nexport interface HaveIBeenPwnedOptions {\n\tcustomPasswordCompromisedMessage?: string | undefined;\n\t/**\n\t * Paths to check for password\n\t *\n\t * @default [\"/sign-up/email\", \"/change-password\", \"/reset-password\"]\n\t */\n\tpaths?: string[];\n}\n\nexport const haveIBeenPwned = (options?: HaveIBeenPwnedOptions | undefined) => {\n\tconst paths = options?.paths || [\n\t\t\"/sign-up/email\",\n\t\t\"/change-password\",\n\t\t\"/reset-password\",\n\t];\n\n\treturn {\n\t\tid: \"haveIBeenPwned\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tpassword: {\n\t\t\t\t\t\t...ctx.password,\n\t\t\t\t\t\tasync hash(password) {\n\t\t\t\t\t\t\tconst c = await getCurrentAuthContext();\n\t\t\t\t\t\t\tif (!c.path || !paths.includes(c.path)) {\n\t\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tawait checkPasswordCompromise(\n\t\t\t\t\t\t\t\tpassword,\n\t\t\t\t\t\t\t\toptions?.customPasswordCompromisedMessage,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t$ERROR_CODES: ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc,iBAAiB,EACpC,sBACC,sFACD,CAAC;AAEF,eAAe,wBACd,UACA,eACC;AACD,KAAI,CAAC,SAAU;CAEf,MAAM,YACL,MAAM,WAAW,SAAS,MAAM,CAAC,OAAO,SAAS,EAChD,aAAa;CACf,MAAM,SAAS,SAAS,UAAU,GAAG,EAAE;CACvC,MAAM,SAAS,SAAS,UAAU,EAAE;AACpC,KAAI;EACH,MAAM,EAAE,MAAM,UAAU,MAAM,YAC7B,wCAAwC,UACxC,EACC,SAAS;GACR,eAAe;GACf,cAAc;GACd,EACD,CACD;AAED,MAAI,MACH,OAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qCAAqC,MAAM,UACpD,CAAC;AAOH,MALc,KAAK,MAAM,KAAK,CACV,MAClB,SAAS,KAAK,MAAM,IAAI,CAAC,GAAI,aAAa,KAAK,OAAO,aAAa,CACpE,CAGA,OAAM,IAAI,SAAS,eAAe;GACjC,SAAS,iBAAiB,YAAY;GACtC,MAAM;GACN,CAAC;UAEK,OAAO;AACf,MAAI,iBAAiB,SAAU,OAAM;AACrC,QAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qDACT,CAAC;;;AAcJ,MAAa,kBAAkB,YAAgD;CAC9E,MAAM,QAAQ,SAAS,SAAS;EAC/B;EACA;EACA;EACA;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,UAAU;IACT,GAAG,IAAI;IACP,MAAM,KAAK,UAAU;KACpB,MAAM,IAAI,MAAM,uBAAuB;AACvC,SAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,SAAS,EAAE,KAAK,CACrC,QAAO,IAAI,SAAS,KAAK,SAAS;AAEnC,WAAM,wBACL,UACA,SAAS,iCACT;AACD,YAAO,IAAI,SAAS,KAAK,SAAS;;IAEnC,EACD,EACD;;EAEF,cAAc;EACd"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/haveibeenpwned/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { getCurrentAuthContext } from \"@better-auth/core/context\";\nimport { defineErrorCodes } from \"@better-auth/core/utils\";\nimport { createHash } from \"@better-auth/utils/hash\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"../../api\";\n\nconst ERROR_CODES = defineErrorCodes({\n\tPASSWORD_COMPROMISED:\n\t\t\"The password you entered has been compromised. Please choose a different password.\",\n});\n\nasync function checkPasswordCompromise(\n\tpassword: string,\n\tcustomMessage?: string | undefined,\n) {\n\tif (!password) return;\n\n\tconst sha1Hash = (\n\t\tawait createHash(\"SHA-1\", \"hex\").digest(password)\n\t).toUpperCase();\n\tconst prefix = sha1Hash.substring(0, 5);\n\tconst suffix = sha1Hash.substring(5);\n\ttry {\n\t\tconst { data, error } = await betterFetch<string>(\n\t\t\t`https://api.pwnedpasswords.com/range/${prefix}`,\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\t\"Add-Padding\": \"true\",\n\t\t\t\t\t\"User-Agent\": \"BetterAuth Password Checker\",\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: `Failed to check password. Status: ${error.status}`,\n\t\t\t});\n\t\t}\n\t\tconst lines = data.split(\"\\n\");\n\t\tconst found = lines.some(\n\t\t\t(line) => line.split(\":\")[0]!.toUpperCase() === suffix.toUpperCase(),\n\t\t);\n\n\t\tif (found) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: customMessage || ERROR_CODES.PASSWORD_COMPROMISED,\n\t\t\t\tcode: \"PASSWORD_COMPROMISED\",\n\t\t\t});\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof APIError) throw error;\n\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\tmessage: \"Failed to check password. Please try again later.\",\n\t\t});\n\t}\n}\n\nexport interface HaveIBeenPwnedOptions {\n\tcustomPasswordCompromisedMessage?: string | undefined;\n\t/**\n\t * Paths to check for password\n\t *\n\t * @default [\"/sign-up/email\", \"/change-password\", \"/reset-password\"]\n\t */\n\tpaths?: string[];\n}\n\nexport const haveIBeenPwned = (options?: HaveIBeenPwnedOptions | undefined) => {\n\tconst paths = options?.paths || [\n\t\t\"/sign-up/email\",\n\t\t\"/change-password\",\n\t\t\"/reset-password\",\n\t];\n\n\treturn {\n\t\tid: \"haveIBeenPwned\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tpassword: {\n\t\t\t\t\t\t...ctx.password,\n\t\t\t\t\t\tasync hash(password) {\n\t\t\t\t\t\t\tconst c = await getCurrentAuthContext();\n\t\t\t\t\t\t\tif (!c.path || !paths.includes(c.path)) {\n\t\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tawait checkPasswordCompromise(\n\t\t\t\t\t\t\t\tpassword,\n\t\t\t\t\t\t\t\toptions?.customPasswordCompromisedMessage,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\toptions,\n\t\t$ERROR_CODES: ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc,iBAAiB,EACpC,sBACC,sFACD,CAAC;AAEF,eAAe,wBACd,UACA,eACC;AACD,KAAI,CAAC,SAAU;CAEf,MAAM,YACL,MAAM,WAAW,SAAS,MAAM,CAAC,OAAO,SAAS,EAChD,aAAa;CACf,MAAM,SAAS,SAAS,UAAU,GAAG,EAAE;CACvC,MAAM,SAAS,SAAS,UAAU,EAAE;AACpC,KAAI;EACH,MAAM,EAAE,MAAM,UAAU,MAAM,YAC7B,wCAAwC,UACxC,EACC,SAAS;GACR,eAAe;GACf,cAAc;GACd,EACD,CACD;AAED,MAAI,MACH,OAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qCAAqC,MAAM,UACpD,CAAC;AAOH,MALc,KAAK,MAAM,KAAK,CACV,MAClB,SAAS,KAAK,MAAM,IAAI,CAAC,GAAI,aAAa,KAAK,OAAO,aAAa,CACpE,CAGA,OAAM,IAAI,SAAS,eAAe;GACjC,SAAS,iBAAiB,YAAY;GACtC,MAAM;GACN,CAAC;UAEK,OAAO;AACf,MAAI,iBAAiB,SAAU,OAAM;AACrC,QAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qDACT,CAAC;;;AAcJ,MAAa,kBAAkB,YAAgD;CAC9E,MAAM,QAAQ,SAAS,SAAS;EAC/B;EACA;EACA;EACA;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,UAAU;IACT,GAAG,IAAI;IACP,MAAM,KAAK,UAAU;KACpB,MAAM,IAAI,MAAM,uBAAuB;AACvC,SAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,SAAS,EAAE,KAAK,CACrC,QAAO,IAAI,SAAS,KAAK,SAAS;AAEnC,WAAM,wBACL,UACA,SAAS,iCACT;AACD,YAAO,IAAI,SAAS,KAAK,SAAS;;IAEnC,EACD,EACD;;EAEF;EACA,cAAc;EACd"}
|