@better-auth/oauth-provider 1.7.0-beta.2 → 1.7.0-beta.4

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.
@@ -1,7 +1,8 @@
1
1
  import { APIError } from "better-call";
2
+ import { decodeBasicCredentials } from "@better-auth/core/oauth2";
2
3
  import { constantTimeEqual, makeSignature, symmetricDecrypt, symmetricEncrypt } from "better-auth/crypto";
3
4
  import { BetterAuthError } from "@better-auth/core/error";
4
- import { base64, base64Url } from "@better-auth/utils/base64";
5
+ import { base64Url } from "@better-auth/utils/base64";
5
6
  import { createHash } from "@better-auth/utils/hash";
6
7
  //#region src/utils/index.ts
7
8
  var TTLCache = class {
@@ -74,6 +75,47 @@ function resolveSessionAuthTime(value) {
74
75
  if (!nested || typeof nested !== "object") return;
75
76
  return normalizeTimestampValue(nested.createdAt) ?? normalizeTimestampValue(nested.created_at);
76
77
  }
78
+ /**
79
+ * Normalizes OAuth resource values into a non-empty string array.
80
+ */
81
+ function toResourceList(value) {
82
+ if (typeof value === "string") return [value];
83
+ if (!value?.length) return void 0;
84
+ return value;
85
+ }
86
+ /**
87
+ * Normalizes audience values for JWT claims.
88
+ */
89
+ function toAudienceClaim(audience) {
90
+ if (typeof audience === "string") return audience;
91
+ if (!audience?.length) return void 0;
92
+ return audience.length === 1 ? audience.at(0) : audience;
93
+ }
94
+ /**
95
+ * Checks the resource parameter, if provided,
96
+ * and returns either a valid audience or a tagged validation error.
97
+ */
98
+ async function checkResource(ctx, opts, resource, scopes) {
99
+ const normalizedResource = toResourceList(resource);
100
+ const audience = normalizedResource ? [...normalizedResource] : void 0;
101
+ if (audience) {
102
+ const hasOpenId = scopes.includes("openid");
103
+ const baseUrl = ctx.context.baseURL;
104
+ const userInfoEndpoint = `${baseUrl}/oauth2/userinfo`;
105
+ if (hasOpenId && !audience.includes(userInfoEndpoint)) audience.push(userInfoEndpoint);
106
+ const filteredValidAudiences = opts.validAudiences?.filter((aud) => aud.length);
107
+ const validAudiences = new Set(filteredValidAudiences?.length ? filteredValidAudiences : [baseUrl]);
108
+ if (hasOpenId) validAudiences.add(userInfoEndpoint);
109
+ for (const aud of audience) if (!validAudiences.has(aud)) return {
110
+ success: false,
111
+ error: "invalid_resource"
112
+ };
113
+ }
114
+ return {
115
+ success: true,
116
+ audience: toAudienceClaim(audience)
117
+ };
118
+ }
77
119
  const cachedTrustedClients = new TTLCache();
78
120
  async function verifyOAuthQueryParams(oauth_query, secret) {
79
121
  const queryParams = new URLSearchParams(oauth_query);
@@ -228,23 +270,20 @@ async function getStoredToken(storageMethod = "hashed", token, type) {
228
270
  *
229
271
  * @internal
230
272
  */
273
+ const BASIC_SCHEME_PREFIX = /^Basic +/i;
231
274
  function basicToClientCredentials(authorization) {
232
- if (authorization.startsWith("Basic ")) {
233
- const encoded = authorization.replace("Basic ", "");
234
- const decoded = new TextDecoder().decode(base64.decode(encoded));
235
- if (!decoded.includes(":")) throw new APIError("BAD_REQUEST", {
236
- error_description: "invalid authorization header format",
237
- error: "invalid_client"
238
- });
239
- const [id, secret] = decoded.split(":", 2);
240
- if (!id || !secret) throw new APIError("BAD_REQUEST", {
275
+ if (!BASIC_SCHEME_PREFIX.test(authorization)) return;
276
+ try {
277
+ const { clientId, clientSecret } = decodeBasicCredentials(authorization);
278
+ return {
279
+ client_id: clientId,
280
+ client_secret: clientSecret
281
+ };
282
+ } catch {
283
+ throw new APIError("BAD_REQUEST", {
241
284
  error_description: "invalid authorization header format",
242
285
  error: "invalid_client"
243
286
  });
244
- return {
245
- client_id: id,
246
- client_secret: secret
247
- };
248
287
  }
249
288
  }
250
289
  /**
@@ -324,7 +363,7 @@ async function extractClientCredentials(ctx, opts, expectedAudience) {
324
363
  error_description: "client_assertion cannot be combined with client_secret or Basic auth",
325
364
  error: "invalid_client"
326
365
  });
327
- const { verifyClientAssertion: verify } = await import("./client-assertion-CderPEmR.mjs").then((n) => n.t);
366
+ const { verifyClientAssertion: verify } = await import("./client-assertion-DLMKVgoj.mjs").then((n) => n.t);
328
367
  const result = await verify(ctx, opts, body.client_assertion, body.client_assertion_type, body.client_id, expectedAudience);
329
368
  return {
330
369
  method: "private_key_jwt",
@@ -404,20 +443,24 @@ function searchParamsToQuery(params) {
404
443
  }
405
444
  return result;
406
445
  }
407
- /**
408
- * Deletes a prompt value
409
- *
410
- * @param ctx
411
- * @param prompt - the prompt value to delete
412
- */
413
- function deleteFromPrompt(query, prompt) {
414
- const prompts = query.get("prompt")?.split(" ");
446
+ const signedQueryIssuedAtParam = "ba_iat";
447
+ const postLoginClearedParam = "ba_pl";
448
+ function getSignedQueryIssuedAt(oauthQuery) {
449
+ const raw = new URLSearchParams(oauthQuery).get(signedQueryIssuedAtParam);
450
+ if (!raw) return null;
451
+ const issuedAt = Number(raw);
452
+ if (!Number.isFinite(issuedAt) || issuedAt <= 0) return null;
453
+ return new Date(issuedAt);
454
+ }
455
+ function removePromptFromQuery(query, prompt) {
456
+ const nextQuery = new URLSearchParams(query);
457
+ const prompts = nextQuery.get("prompt")?.split(" ");
415
458
  const foundPrompt = prompts?.findIndex((v) => v === prompt) ?? -1;
416
459
  if (foundPrompt >= 0) {
417
460
  prompts?.splice(foundPrompt, 1);
418
- prompts?.length ? query.set("prompt", prompts.join(" ")) : query.delete("prompt");
461
+ prompts?.length ? nextQuery.set("prompt", prompts.join(" ")) : nextQuery.delete("prompt");
419
462
  }
420
- return searchParamsToQuery(query);
463
+ return nextQuery;
421
464
  }
422
465
  var PKCERequirementErrors = /* @__PURE__ */ function(PKCERequirementErrors) {
423
466
  PKCERequirementErrors["PUBLIC_CLIENT"] = "pkce is required for public clients";
@@ -446,4 +489,4 @@ function isPKCERequired(client, requestedScopes) {
446
489
  return false;
447
490
  }
448
491
  //#endregion
449
- export { storeClientSecret as _, getClient as a, validateClientCredentials as b, getStoredToken as c, normalizeTimestampValue as d, parseClientMetadata as f, searchParamsToQuery as g, resolveSubjectIdentifier as h, extractClientCredentials as i, isPKCERequired as l, resolveSessionAuthTime as m, deleteFromPrompt as n, getJwtPlugin as o, parsePrompt as p, destructureCredentials as r, getOAuthProviderPlugin as s, decryptStoredClientSecret as t, mergeDiscoveryMetadata as u, storeToken as v, verifyOAuthQueryParams as x, toClientDiscoveryArray as y };
492
+ export { toAudienceClaim as C, verifyOAuthQueryParams as D, validateClientCredentials as E, storeToken as S, toResourceList as T, resolveSessionAuthTime as _, getClient as a, signedQueryIssuedAtParam as b, getSignedQueryIssuedAt as c, mergeDiscoveryMetadata as d, normalizeTimestampValue as f, removePromptFromQuery as g, postLoginClearedParam as h, extractClientCredentials as i, getStoredToken as l, parsePrompt as m, decryptStoredClientSecret as n, getJwtPlugin as o, parseClientMetadata as p, destructureCredentials as r, getOAuthProviderPlugin as s, checkResource as t, isPKCERequired as u, resolveSubjectIdentifier as v, toClientDiscoveryArray as w, storeClientSecret as x, searchParamsToQuery as y };
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.7.0-beta.2";
3
+ const PACKAGE_VERSION = "1.7.0-beta.4";
4
4
  //#endregion
5
5
  export { PACKAGE_VERSION as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/oauth-provider",
3
- "version": "1.7.0-beta.2",
3
+ "version": "1.7.0-beta.4",
4
4
  "description": "An oauth provider plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -64,15 +64,15 @@
64
64
  "@modelcontextprotocol/sdk": "^1.27.1",
65
65
  "listhen": "^1.9.0",
66
66
  "tsdown": "0.21.1",
67
- "@better-auth/core": "1.7.0-beta.2",
68
- "better-auth": "1.7.0-beta.2"
67
+ "@better-auth/core": "1.7.0-beta.4",
68
+ "better-auth": "1.7.0-beta.4"
69
69
  },
70
70
  "peerDependencies": {
71
- "@better-auth/utils": "0.4.0",
71
+ "@better-auth/utils": "0.4.1",
72
72
  "@better-fetch/fetch": "1.1.21",
73
73
  "better-call": "1.3.5",
74
- "@better-auth/core": "^1.7.0-beta.2",
75
- "better-auth": "^1.7.0-beta.2"
74
+ "@better-auth/core": "^1.7.0-beta.4",
75
+ "better-auth": "^1.7.0-beta.4"
76
76
  },
77
77
  "scripts": {
78
78
  "build": "tsdown",