@better-auth/electron 1.7.0-beta.3 → 1.7.0-beta.5

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.
@@ -35,13 +35,6 @@ interface ElectronOptions extends ElectronSharedOptions {
35
35
  * @default "better-auth"
36
36
  */
37
37
  cookiePrefix?: string | undefined;
38
- /**
39
- * Override the origin for Electron API routes.
40
- * Enable this if you're facing cors origin issues with Electron API routes.
41
- *
42
- * @default false
43
- */
44
- disableOriginOverride?: boolean | undefined;
45
38
  }
46
39
  //#endregion
47
40
  //#region src/preload.d.ts
@@ -248,6 +241,7 @@ declare const requestAuthOptionsSchema: z.ZodObject<{
248
241
  disableRedirect: z.ZodOptional<z.ZodBoolean>;
249
242
  scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
250
243
  requestSignUp: z.ZodOptional<z.ZodBoolean>;
244
+ additionalParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
251
245
  additionalData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
252
246
  }, z.core.$strip>;
253
247
  type ElectronRequestAuthOptions = z.infer<typeof requestAuthOptionsSchema>;
@@ -323,11 +317,6 @@ declare const electronClient: <O extends ElectronClientOptions>(options: O) => {
323
317
  mode?: RequestMode | undefined;
324
318
  cache?: RequestCache | undefined;
325
319
  credentials?: RequestCredentials | undefined;
326
- headers?: (HeadersInit & (HeadersInit | {
327
- accept: "application/json" | "text/plain" | "application/octet-stream";
328
- "content-type": "application/json" | "text/plain" | "application/x-www-form-urlencoded" | "multipart/form-data" | "application/octet-stream";
329
- authorization: "Bearer" | "Basic";
330
- })) | undefined;
331
320
  integrity?: string | undefined;
332
321
  keepalive?: boolean | undefined;
333
322
  method?: string | undefined;
@@ -361,6 +350,12 @@ declare const electronClient: <O extends ElectronClientOptions>(options: O) => {
361
350
  prefix: string | (() => string | undefined) | undefined;
362
351
  value: string | (() => string | undefined) | undefined;
363
352
  }) | undefined;
353
+ headers?: {} | {
354
+ [x: string]: string | undefined;
355
+ accept?: ((string & {}) | "application/json" | "text/plain" | "application/octet-stream") | undefined;
356
+ "content-type"?: ((string & {}) | "application/x-www-form-urlencoded" | "application/json" | "text/plain" | "multipart/form-data" | "application/octet-stream") | undefined;
357
+ authorization?: ((string & {}) | `Bearer ${string}` | `Basic ${string}`) | undefined;
358
+ } | undefined;
364
359
  body?: any;
365
360
  query?: any;
366
361
  params?: any;
@@ -378,11 +373,6 @@ declare const electronClient: <O extends ElectronClientOptions>(options: O) => {
378
373
  mode?: RequestMode | undefined;
379
374
  cache?: RequestCache | undefined;
380
375
  credentials?: RequestCredentials | undefined;
381
- headers?: (HeadersInit & (HeadersInit | {
382
- accept: "application/json" | "text/plain" | "application/octet-stream";
383
- "content-type": "application/json" | "text/plain" | "application/x-www-form-urlencoded" | "multipart/form-data" | "application/octet-stream";
384
- authorization: "Bearer" | "Basic";
385
- })) | undefined;
386
376
  integrity?: string | undefined;
387
377
  keepalive?: boolean | undefined;
388
378
  method?: string | undefined;
@@ -416,6 +406,12 @@ declare const electronClient: <O extends ElectronClientOptions>(options: O) => {
416
406
  prefix: string | (() => string | undefined) | undefined;
417
407
  value: string | (() => string | undefined) | undefined;
418
408
  }) | undefined;
409
+ headers?: {} | {
410
+ [x: string]: string | undefined;
411
+ accept?: ((string & {}) | "application/json" | "text/plain" | "application/octet-stream") | undefined;
412
+ "content-type"?: ((string & {}) | "application/x-www-form-urlencoded" | "application/json" | "text/plain" | "multipart/form-data" | "application/octet-stream") | undefined;
413
+ authorization?: ((string & {}) | `Bearer ${string}` | `Basic ${string}`) | undefined;
414
+ } | undefined;
419
415
  body?: any;
420
416
  query?: any;
421
417
  params?: any;
package/dist/client.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as setupRenderer, a as authenticate, c as ElectronClientOptions, d as Storage, f as FetchUserImageResult, g as SetupRendererConfig, h as ExposedBridges, i as ElectronRequestAuthOptions, l as ElectronProxyClientOptions, m as normalizeUserOutput, n as handleDeepLink, o as kElectron, p as fetchUserImage, r as ElectronAuthenticateOptions, s as requestAuth, t as electronClient, u as ElectronSharedClientOptions, y as ElectronSharedOptions } from "./client-D6xRwPM0.mjs";
1
+ import { _ as setupRenderer, a as authenticate, c as ElectronClientOptions, d as Storage, f as FetchUserImageResult, g as SetupRendererConfig, h as ExposedBridges, i as ElectronRequestAuthOptions, l as ElectronProxyClientOptions, m as normalizeUserOutput, n as handleDeepLink, o as kElectron, p as fetchUserImage, r as ElectronAuthenticateOptions, s as requestAuth, t as electronClient, u as ElectronSharedClientOptions, y as ElectronSharedOptions } from "./client-D5QKMJbp.mjs";
2
2
  export { ElectronAuthenticateOptions, ElectronClientOptions, ElectronProxyClientOptions, ElectronRequestAuthOptions, ElectronSharedClientOptions, ElectronSharedOptions, ExposedBridges, FetchUserImageResult, SetupRendererConfig, Storage, authenticate, electronClient, fetchUserImage, handleDeepLink, kElectron, normalizeUserOutput, requestAuth, setupRenderer };
package/dist/client.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import { t as PACKAGE_VERSION } from "./version-CLqkeI3u.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-DzWb5tB_.mjs";
2
2
  import { n as isProcessType, r as parseProtocolScheme, t as getChannelPrefixWithDelimiter } from "./utils-DxDKRT6e.mjs";
3
3
  import { BetterAuthError } from "@better-auth/core/error";
4
4
  import { base64, base64Url } from "@better-auth/utils/base64";
5
5
  import { APIError as APIError$1, getBaseURL, isDevelopment, isTest, safeJSONParse } from "better-auth";
6
6
  import { generateRandomString } from "better-auth/crypto";
7
7
  import * as z from "zod";
8
- import { Buffer } from "node:buffer";
9
- import { createHash } from "@better-auth/utils/hash";
10
8
  import { signInSocial } from "better-auth/api";
11
- import { parseSetCookieHeader } from "better-auth/cookies";
9
+ import { cookieNameRegex, parseSetCookieHeader } from "better-auth/cookies";
10
+ import { generateCodeChallenge } from "better-auth/oauth2";
11
+ import { Buffer } from "node:buffer";
12
12
  import electron, { shell } from "electron";
13
13
  import { isDevelopment as isDevelopment$1 } from "@better-auth/core/env";
14
14
  import { isPublicRoutableHost } from "@better-auth/core/utils/host";
@@ -150,8 +150,8 @@ async function requestAuth(clientOptions, options, cfg) {
150
150
  if (!isProcessType("browser")) throw new BetterAuthError("`requestAuth` can only be called in the main process");
151
151
  const { randomBytes } = await import("node:crypto");
152
152
  const state = generateRandomString(16, "A-Z", "a-z", "0-9");
153
- const codeVerifier = base64Url.encode(randomBytes(32));
154
- const codeChallenge = base64Url.encode(await createHash("SHA-256").digest(codeVerifier));
153
+ const codeVerifier = base64Url.encode(randomBytes(32), { padding: false });
154
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
155
155
  (globalThis[kElectron] ??= /* @__PURE__ */ new Map()).set(state, codeVerifier);
156
156
  let url = null;
157
157
  if (cfg?.provider) {
@@ -168,7 +168,6 @@ async function requestAuth(clientOptions, options, cfg) {
168
168
  } else url = new URL(options.signInURL);
169
169
  url.searchParams.set("client_id", options.clientID || "electron");
170
170
  url.searchParams.set("code_challenge", codeChallenge);
171
- url.searchParams.set("code_challenge_method", "S256");
172
171
  url.searchParams.set("state", state);
173
172
  await shell.openExternal(url.toString(), { activate: true });
174
173
  }
@@ -474,10 +473,13 @@ function getCookie(cookie) {
474
473
  try {
475
474
  parsed = JSON.parse(cookie);
476
475
  } catch (_e) {}
477
- return Object.entries(parsed).reduce((acc, [key, value]) => {
478
- if (value.expires && new Date(value.expires) < /* @__PURE__ */ new Date()) return acc;
479
- return `${acc}; ${key}=${value.value}`;
480
- }, "");
476
+ const pairs = [];
477
+ for (const [key, value] of Object.entries(parsed)) {
478
+ if (value.expires && new Date(value.expires) < /* @__PURE__ */ new Date()) continue;
479
+ if (!cookieNameRegex.test(key)) continue;
480
+ pairs.push(`${key}=${encodeURIComponent(value.value)}`);
481
+ }
482
+ return pairs.join("; ");
481
483
  }
482
484
  /**
483
485
  * Compare if session cookies have actually changed by comparing their values.
@@ -589,10 +591,10 @@ const electronClient = (options) => {
589
591
  options ||= {};
590
592
  options.credentials = "omit";
591
593
  options.headers = {
594
+ origin: `${scheme}:/`,
592
595
  ...options.headers,
593
596
  cookie,
594
597
  "user-agent": app.userAgentFallback,
595
- "electron-origin": `${scheme}:/`,
596
598
  "x-skip-oauth-proxy": "true"
597
599
  };
598
600
  if (url.endsWith("/sign-out")) {
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { f as FetchUserImageResult, m as normalizeUserOutput, p as fetchUserImage, v as ElectronOptions, y as ElectronSharedOptions } from "./client-D6xRwPM0.mjs";
1
+ import { f as FetchUserImageResult, m as normalizeUserOutput, p as fetchUserImage, v as ElectronOptions, y as ElectronSharedOptions } from "./client-D5QKMJbp.mjs";
2
2
  import * as better_auth0 from "better-auth";
3
3
  import * as z from "zod";
4
4
  import * as _better_auth_core0 from "@better-auth/core";
@@ -16,9 +16,6 @@ declare module "@better-auth/core" {
16
16
  declare const electron: (options?: ElectronOptions | undefined) => {
17
17
  id: "electron";
18
18
  version: string;
19
- onRequest(request: Request, _ctx: better_auth0.AuthContext): Promise<{
20
- request: Request;
21
- } | undefined>;
22
19
  hooks: {
23
20
  after: ({
24
21
  matcher: (ctx: HookEndpointContext) => boolean;
@@ -102,7 +99,7 @@ declare const electron: (options?: ElectronOptions | undefined) => {
102
99
  image?: string | null | undefined;
103
100
  } & Record<string, any>;
104
101
  } | null) => void;
105
- socialProviders: better_auth0.OAuthProvider[];
102
+ socialProviders: better_auth0.UpstreamProvider[];
106
103
  authCookies: better_auth0.BetterAuthCookies;
107
104
  logger: ReturnType<typeof better_auth0.createLogger>;
108
105
  rateLimit: {
@@ -205,7 +202,6 @@ declare const electron: (options?: ElectronOptions | undefined) => {
205
202
  provider: z.ZodString;
206
203
  state: z.ZodString;
207
204
  code_challenge: z.ZodString;
208
- code_challenge_method: z.ZodOptional<z.ZodString>;
209
205
  }, z.core.$strip>;
210
206
  metadata: {
211
207
  scope: "http";
@@ -255,7 +251,6 @@ declare const electron: (options?: ElectronOptions | undefined) => {
255
251
  client_id: z.ZodString;
256
252
  state: z.ZodString;
257
253
  code_challenge: z.ZodString;
258
- code_challenge_method: z.ZodOptional<z.ZodString>;
259
254
  }, z.core.$strip>;
260
255
  body: z.ZodObject<{
261
256
  callbackURL: z.ZodOptional<z.ZodString>;
@@ -325,7 +320,6 @@ declare const electron: (options?: ElectronOptions | undefined) => {
325
320
  codeExpiresIn: number;
326
321
  redirectCookieExpiresIn: number;
327
322
  cookiePrefix: string;
328
- disableOriginOverride?: boolean | undefined;
329
323
  clientID: string;
330
324
  };
331
325
  $ERROR_CODES: {
package/dist/index.mjs CHANGED
@@ -1,18 +1,16 @@
1
- import { t as PACKAGE_VERSION } from "./version-CLqkeI3u.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-DzWb5tB_.mjs";
2
2
  import { createAuthMiddleware } from "@better-auth/core/api";
3
3
  import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
4
4
  import { base64Url } from "@better-auth/utils/base64";
5
5
  import { defineErrorCodes, safeJSONParse } from "better-auth";
6
6
  import { generateRandomString } from "better-auth/crypto";
7
7
  import * as z from "zod";
8
- import { Buffer } from "node:buffer";
9
- import { timingSafeEqual } from "node:crypto";
10
8
  import { safeJSONParse as safeJSONParse$1 } from "@better-auth/core/utils/json";
11
- import { createHash } from "@better-auth/utils/hash";
12
9
  import { betterFetch } from "@better-fetch/fetch";
13
10
  import { createAuthEndpoint, sessionMiddleware } from "better-auth/api";
14
11
  import { setSessionCookie } from "better-auth/cookies";
15
12
  import { parseUserOutput } from "better-auth/db";
13
+ import { generateCodeChallenge } from "better-auth/oauth2";
16
14
  //#region src/error-codes.ts
17
15
  const ELECTRON_ERROR_CODES = defineErrorCodes({
18
16
  INVALID_CLIENT_ID: "Invalid client ID",
@@ -61,11 +59,7 @@ const electronToken = (_opts) => createAuthEndpoint("/electron/token", {
61
59
  if (!tokenRecord) throw APIError.from("INTERNAL_SERVER_ERROR", ELECTRON_ERROR_CODES.INVALID_TOKEN);
62
60
  if (tokenRecord.state !== ctx.body.state) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.STATE_MISMATCH);
63
61
  if (!tokenRecord.codeChallenge) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.MISSING_CODE_CHALLENGE);
64
- if (tokenRecord.codeChallengeMethod === "s256") {
65
- const codeChallenge = Buffer.from(base64Url.decode(tokenRecord.codeChallenge));
66
- const codeVerifier = Buffer.from(await createHash("SHA-256").digest(ctx.body.code_verifier));
67
- if (codeChallenge.length !== codeVerifier.length || !timingSafeEqual(codeChallenge, codeVerifier)) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.INVALID_CODE_VERIFIER);
68
- } else if (tokenRecord.codeChallenge !== ctx.body.code_verifier) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.INVALID_CODE_VERIFIER);
62
+ if (await generateCodeChallenge(ctx.body.code_verifier) !== tokenRecord.codeChallenge) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.INVALID_CODE_VERIFIER);
69
63
  await ctx.context.internalAdapter.deleteVerificationByIdentifier(`electron:${ctx.body.token}`);
70
64
  const user = await ctx.context.internalAdapter.findUserById(tokenRecord.userId);
71
65
  if (!user) throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.USER_NOT_FOUND);
@@ -83,8 +77,7 @@ const electronToken = (_opts) => createAuthEndpoint("/electron/token", {
83
77
  const electronInitOAuthProxyQuerySchema = z.object({
84
78
  provider: z.string().nonempty(),
85
79
  state: z.string(),
86
- code_challenge: z.string(),
87
- code_challenge_method: z.string().optional()
80
+ code_challenge: z.string()
88
81
  });
89
82
  const electronInitOAuthProxy = (opts) => createAuthEndpoint("/electron/init-oauth-proxy", {
90
83
  method: "GET",
@@ -122,7 +115,6 @@ const electronInitOAuthProxy = (opts) => createAuthEndpoint("/electron/init-oaut
122
115
  const searchParams = new URLSearchParams();
123
116
  searchParams.set("client_id", opts.clientID || "electron");
124
117
  searchParams.set("code_challenge", ctx.query.code_challenge);
125
- searchParams.set("code_challenge_method", ctx.query.code_challenge_method || "plain");
126
118
  searchParams.set("state", ctx.query.state);
127
119
  const res = await betterFetch(`/sign-in/social?${searchParams.toString()}`, {
128
120
  baseURL: ctx.context.baseURL,
@@ -145,8 +137,7 @@ const electronInitOAuthProxy = (opts) => createAuthEndpoint("/electron/init-oaut
145
137
  const electronTransferUserQuerySchema = z.object({
146
138
  client_id: z.string(),
147
139
  state: z.string(),
148
- code_challenge: z.string(),
149
- code_challenge_method: z.string().optional()
140
+ code_challenge: z.string()
150
141
  });
151
142
  const electronTransferUserBodySchema = z.object({ callbackURL: z.string().optional() });
152
143
  const electronTransferUser = (_opts, { handleTransfer }) => createAuthEndpoint("/electron/transfer-user", {
@@ -201,7 +192,7 @@ const electron = (options) => {
201
192
  return !!(ctx.path?.startsWith("/sign-in") || ctx.path?.startsWith("/sign-up") || ctx.path?.startsWith("/callback") || ctx.path?.startsWith("/magic-link/verify") || ctx.path?.startsWith("/email-otp/verify-email") || ctx.path?.startsWith("/verify-email") || ctx.path?.startsWith("/one-tap/callback") || ctx.path?.startsWith("/passkey/verify-authentication") || ctx.path?.startsWith("/phone-number/verify"));
202
193
  };
203
194
  const handleTransfer = async (ctx, payload) => {
204
- const { client_id, state, code_challenge, code_challenge_method = "plain" } = payload;
195
+ const { client_id, state, code_challenge } = payload;
205
196
  const userId = ctx.context.session?.user.id || ctx.context.newSession?.user.id;
206
197
  if (!userId || client_id !== opts.clientID) return null;
207
198
  if (!state) throw APIError.from("BAD_REQUEST", ELECTRON_ERROR_CODES.MISSING_STATE);
@@ -215,7 +206,6 @@ const electron = (options) => {
215
206
  value: JSON.stringify({
216
207
  userId,
217
208
  codeChallenge: code_challenge,
218
- codeChallengeMethod: code_challenge_method.toLowerCase(),
219
209
  state
220
210
  }),
221
211
  expiresAt
@@ -234,14 +224,6 @@ const electron = (options) => {
234
224
  return {
235
225
  id: "electron",
236
226
  version: PACKAGE_VERSION,
237
- async onRequest(request, _ctx) {
238
- if (opts.disableOriginOverride || request.headers.get("origin")) return;
239
- const electronOrigin = request.headers.get("electron-origin");
240
- if (!electronOrigin) return;
241
- const req = request.clone();
242
- req.headers.set("origin", electronOrigin);
243
- return { request: req };
244
- },
245
227
  hooks: { after: [{
246
228
  matcher: (ctx) => !hookMatcher(ctx),
247
229
  handler: createAuthMiddleware(async (ctx) => {
@@ -256,7 +238,6 @@ const electron = (options) => {
256
238
  const querySchema = z.object({
257
239
  client_id: z.string(),
258
240
  code_challenge: z.string().nonempty(),
259
- code_challenge_method: z.string().optional().default("plain"),
260
241
  state: z.string().nonempty()
261
242
  });
262
243
  const cookie = ctx.context.createAuthCookie("transfer_token", { maxAge: opts.codeExpiresIn });