@better-auth/oauth-provider 1.7.0-beta.5 → 1.7.0-beta.7

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,24 +1,14 @@
1
- import { o as getClient } from "./utils-D2dLqo7f.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs";
2
+ import { a as getClient } from "./utils-Baq6atYN.mjs";
3
+ import { isPublicRoutableHost } from "@better-auth/core/utils/host";
2
4
  import { APIError } from "better-call";
3
5
  import { CLIENT_ASSERTION_TYPE, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS } from "@better-auth/core/oauth2";
4
- import { isPublicRoutableHost } from "@better-auth/core/utils/host";
5
6
  import { base64Url } from "@better-auth/utils/base64";
6
7
  import { createHash } from "@better-auth/utils/hash";
7
8
  import { createLocalJWKSet, decodeJwt, decodeProtectedHeader, jwtVerify } from "jose";
8
- //#region \0rolldown/runtime.js
9
- var __defProp = Object.defineProperty;
10
- var __exportAll = (all, no_symbols) => {
11
- let target = {};
12
- for (var name in all) __defProp(target, name, {
13
- get: all[name],
14
- enumerable: true
15
- });
16
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
17
- return target;
18
- };
19
- //#endregion
20
9
  //#region src/utils/client-assertion.ts
21
10
  var client_assertion_exports = /* @__PURE__ */ __exportAll({
11
+ consumeClientAssertion: () => consumeClientAssertion,
22
12
  isPrivateHostname: () => isPrivateHostname,
23
13
  verifyClientAssertion: () => verifyClientAssertion
24
14
  });
@@ -132,6 +122,84 @@ async function refetchClientJwks(client) {
132
122
  }
133
123
  }
134
124
  /**
125
+ * Enforces the assertion-hygiene claims every client-assertion authentication
126
+ * method must check, independent of how the signature is verified or where the
127
+ * verification keys come from:
128
+ * - `aud` MUST include `expectedAudience` (RFC 7523 §3 rule 3),
129
+ * - `exp` MUST be present, unexpired, and at most `assertionMaxLifetime`
130
+ * seconds away (RFC 7523 §3 rule 4),
131
+ * - `iat`, when present, MUST be within `assertionMaxLifetime`,
132
+ * - `jti` MUST be present and single-use; this consumes a replay tombstone keyed
133
+ * by `` `${namespace}:${jti}` ``, inserted under the adapter's primary key so a
134
+ * replay across workers fails atomically.
135
+ *
136
+ * A custom {@link OAuthClientAuthenticationStrategy} should call this after
137
+ * verifying the assertion signature, so an extension method inherits the same
138
+ * replay, lifetime, and audience guarantees as the built-in `private_key_jwt`
139
+ * path, which calls it too.
140
+ *
141
+ * @param params.namespace Scopes the replay tombstone to the method and client,
142
+ * e.g. `` `${method}:${clientId}` ``, so the same `jti` can recur across
143
+ * distinct methods or clients but never within one.
144
+ */
145
+ async function consumeClientAssertion(ctx, opts, params) {
146
+ const { namespace, payload, expectedAudience } = params;
147
+ if (!(Array.isArray(payload.aud) ? payload.aud : payload.aud != null ? [payload.aud] : []).includes(expectedAudience)) throw new APIError("BAD_REQUEST", {
148
+ error_description: "client assertion aud does not match the endpoint",
149
+ error: "invalid_client"
150
+ });
151
+ const maxLifetime = opts.assertionMaxLifetime ?? 300;
152
+ const now = Math.floor(Date.now() / 1e3);
153
+ if (typeof payload.exp !== "number") throw new APIError("BAD_REQUEST", {
154
+ error_description: "client assertion must include exp claim",
155
+ error: "invalid_client"
156
+ });
157
+ if (payload.exp <= now) throw new APIError("BAD_REQUEST", {
158
+ error_description: "client assertion has expired",
159
+ error: "invalid_client"
160
+ });
161
+ if (payload.exp - now > maxLifetime) throw new APIError("BAD_REQUEST", {
162
+ error_description: `client assertion exp is too far in the future (max ${maxLifetime}s)`,
163
+ error: "invalid_client"
164
+ });
165
+ if (typeof payload.iat === "number" && now - payload.iat > maxLifetime) throw new APIError("BAD_REQUEST", {
166
+ error_description: `client assertion iat is too far in the past (max ${maxLifetime}s)`,
167
+ error: "invalid_client"
168
+ });
169
+ if (typeof payload.jti !== "string" || payload.jti.length === 0) throw new APIError("BAD_REQUEST", {
170
+ error_description: "client assertion must include jti claim",
171
+ error: "invalid_client"
172
+ });
173
+ const jtiDigest = await createHash("SHA-256").digest(new TextEncoder().encode(`${namespace}:${payload.jti}`));
174
+ const jtiId = base64Url.encode(new Uint8Array(jtiDigest).slice(0, 24), { padding: false });
175
+ try {
176
+ await ctx.context.adapter.create({
177
+ model: "oauthClientAssertion",
178
+ data: {
179
+ id: jtiId,
180
+ expiresAt: /* @__PURE__ */ new Date(payload.exp * 1e3)
181
+ },
182
+ forceAllowId: true
183
+ });
184
+ } catch (createErr) {
185
+ let alreadyUsed = false;
186
+ try {
187
+ alreadyUsed = Boolean(await ctx.context.adapter.findOne({
188
+ model: "oauthClientAssertion",
189
+ where: [{
190
+ field: "id",
191
+ value: jtiId
192
+ }]
193
+ }));
194
+ } catch {}
195
+ if (alreadyUsed) throw new APIError("BAD_REQUEST", {
196
+ error_description: "client assertion jti has already been used",
197
+ error: "invalid_client"
198
+ });
199
+ throw createErr;
200
+ }
201
+ }
202
+ /**
135
203
  * Verifies a client assertion JWT for `private_key_jwt` authentication.
136
204
  *
137
205
  * Validates: signature, iss=client_id, sub=client_id, aud=token_endpoint,
@@ -188,7 +256,6 @@ async function verifyClientAssertion(ctx, opts, clientAssertion, clientAssertion
188
256
  });
189
257
  const jwks = await fetchClientJwks(ctx, client);
190
258
  const audience = expectedAudience ?? `${ctx.context.baseURL}/oauth2/token`;
191
- const maxLifetime = opts.assertionMaxLifetime ?? 300;
192
259
  const verifyOpts = {
193
260
  issuer: clientId,
194
261
  subject: clientId,
@@ -218,55 +285,12 @@ async function verifyClientAssertion(ctx, opts, clientAssertion, clientAssertion
218
285
  error: "invalid_client"
219
286
  });
220
287
  }
221
- const now = Math.floor(Date.now() / 1e3);
222
- if (typeof payload.exp !== "number") throw new APIError("BAD_REQUEST", {
223
- error_description: "client assertion must include exp claim",
224
- error: "invalid_client"
288
+ await consumeClientAssertion(ctx, opts, {
289
+ namespace: `private_key_jwt:${clientId}`,
290
+ payload,
291
+ expectedAudience: audience
225
292
  });
226
- if (payload.exp - now > maxLifetime) throw new APIError("BAD_REQUEST", {
227
- error_description: `client assertion exp is too far in the future (max ${maxLifetime}s)`,
228
- error: "invalid_client"
229
- });
230
- if (typeof payload.iat === "number" && now - payload.iat > maxLifetime) throw new APIError("BAD_REQUEST", {
231
- error_description: `client assertion iat is too far in the past (max ${maxLifetime}s)`,
232
- error: "invalid_client"
233
- });
234
- if (!payload.jti) throw new APIError("BAD_REQUEST", {
235
- error_description: "client assertion must include jti claim",
236
- error: "invalid_client"
237
- });
238
- const jtiDigest = await createHash("SHA-256").digest(new TextEncoder().encode(`private_key_jwt:${clientId}:${payload.jti}`));
239
- const jtiId = base64Url.encode(new Uint8Array(jtiDigest).slice(0, 24), { padding: false });
240
- try {
241
- await ctx.context.adapter.create({
242
- model: "oauthClientAssertion",
243
- data: {
244
- id: jtiId,
245
- expiresAt: /* @__PURE__ */ new Date(payload.exp * 1e3)
246
- },
247
- forceAllowId: true
248
- });
249
- } catch (createErr) {
250
- let alreadyUsed = false;
251
- try {
252
- alreadyUsed = Boolean(await ctx.context.adapter.findOne({
253
- model: "oauthClientAssertion",
254
- where: [{
255
- field: "id",
256
- value: jtiId
257
- }]
258
- }));
259
- } catch {}
260
- if (alreadyUsed) throw new APIError("BAD_REQUEST", {
261
- error_description: "client assertion jti has already been used",
262
- error: "invalid_client"
263
- });
264
- throw createErr;
265
- }
266
- return {
267
- clientId,
268
- client
269
- };
293
+ return { clientId };
270
294
  }
271
295
  //#endregion
272
- export { isPrivateHostname as n, client_assertion_exports as t };
296
+ export { consumeClientAssertion as n, isPrivateHostname as r, client_assertion_exports as t };
@@ -1,4 +1,5 @@
1
- import { s as ResourceServerMetadata } from "./oauth-BXrYl5x6.mjs";
1
+ import { c as ResourceServerMetadata } from "./oauth-CPWY2Few.mjs";
2
+ import { ResourceRequestInput, VerifyAccessTokenRequestOptions } from "better-auth/oauth2";
2
3
  import { JWTPayload, JWTVerifyOptions } from "jose";
3
4
  import { BetterAuthOptions } from "better-auth/types";
4
5
 
@@ -22,7 +23,14 @@ declare const oauthProviderResourceClient: <T extends ResourceClientAuth | undef
22
23
  *
23
24
  * The optional auth parameter can fill known values automatically.
24
25
  */
25
- verifyAccessToken: VerifyAccessTokenOutput<T>;
26
+ verifyBearerToken: VerifyAccessTokenOutput<T>;
27
+ /**
28
+ * Performs verification of a protected-resource request. Use this for
29
+ * new resource-server integrations so sender-constrained DPoP access
30
+ * tokens are enforced with the request method, URL, Authorization
31
+ * scheme, DPoP proof, `ath`, and `cnf.jkt` binding.
32
+ */
33
+ verifyAccessTokenRequest: VerifyAccessTokenRequestOutput<T>;
26
34
  /**
27
35
  * An authorization server does not typically publish
28
36
  * the `/.well-known/oauth-protected-resource` themselves.
@@ -65,6 +73,7 @@ interface VerifyAccessTokenRemote {
65
73
  allowMissingAudience?: boolean;
66
74
  }
67
75
  type VerifyAccessTokenOutput<T> = T extends undefined ? (token: string | undefined, opts: VerifyAccessTokenNoAuthOpts) => Promise<JWTPayload> : (token: string | undefined, opts?: VerifyAccessTokenAuthOpts) => Promise<JWTPayload>;
76
+ type VerifyAccessTokenRequestOutput<T> = T extends undefined ? (request: Request | ResourceRequestInput, opts: VerifyAccessTokenRequestNoAuthOpts) => Promise<JWTPayload> : (request: Request | ResourceRequestInput, opts?: VerifyAccessTokenRequestAuthOpts) => Promise<JWTPayload>;
68
77
  type VerifyAccessTokenAuthOpts = {
69
78
  verifyOptions?: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience">>;
70
79
  scopes?: string[];
@@ -72,6 +81,9 @@ type VerifyAccessTokenAuthOpts = {
72
81
  remoteVerify?: VerifyAccessTokenRemote; /** Maps non-url (ie urn, client) resources to resource_metadata */
73
82
  resourceMetadataMappings?: Record<string, string>;
74
83
  };
84
+ type VerifyAccessTokenRequestAuthOpts = VerifyAccessTokenAuthOpts & {
85
+ dpop?: VerifyAccessTokenRequestOptions["dpop"];
86
+ };
75
87
  type VerifyAccessTokenNoAuthOpts = {
76
88
  verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
77
89
  scopes?: string[];
@@ -85,6 +97,9 @@ type VerifyAccessTokenNoAuthOpts = {
85
97
  remoteVerify: VerifyAccessTokenRemote; /** Maps non-url (ie urn, client) resources to resource_metadata */
86
98
  resourceMetadataMappings?: Record<string, string>;
87
99
  };
100
+ type VerifyAccessTokenRequestNoAuthOpts = VerifyAccessTokenNoAuthOpts & {
101
+ dpop?: VerifyAccessTokenRequestOptions["dpop"];
102
+ };
88
103
  type ProtectedResourceMetadataOutput<T> = T extends undefined ? (overrides: ResourceServerMetadata, opts?: {
89
104
  silenceWarnings?: {
90
105
  oidcScopes?: boolean;
@@ -1,10 +1,10 @@
1
- import { t as handleMcpErrors } from "./mcp-CYnz-MXn.mjs";
2
- import { c as getOAuthProviderPlugin, s as getJwtPlugin } from "./utils-D2dLqo7f.mjs";
3
- import { t as PACKAGE_VERSION } from "./version-B1ZiRmxj.mjs";
4
- import { verifyAccessToken } from "better-auth/oauth2";
1
+ import { o as getJwtPlugin, s as getOAuthProviderPlugin } from "./utils-Baq6atYN.mjs";
2
+ import { t as PACKAGE_VERSION } from "./version-DkFgXWfN.mjs";
3
+ import { t as raiseResourceServerChallenge } from "./resource-challenge-B-cqv4ur.mjs";
5
4
  import { APIError } from "better-call";
6
5
  import { logger } from "@better-auth/core/env";
7
6
  import { BetterAuthError } from "@better-auth/core/error";
7
+ import { DPOP_SIGNING_ALGORITHMS, requestToResourceInput, verifyAccessTokenRequest, verifyBearerToken } from "better-auth/oauth2";
8
8
  //#region src/client-resource.ts
9
9
  const oauthProviderResourceClient = (auth) => {
10
10
  let oauthProviderPlugin;
@@ -22,36 +22,55 @@ const oauthProviderResourceClient = (auth) => {
22
22
  return (await getJwtPluginOptions())?.jwt?.issuer ?? authServerBaseUrl;
23
23
  };
24
24
  const authServerBasePath = auth?.options.basePath;
25
+ const resolveVerifyAccessTokenOptions = async (opts) => {
26
+ const jwtPluginOptions = await getJwtPluginOptions();
27
+ const audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;
28
+ const issuer = opts?.verifyOptions?.issuer ?? jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
29
+ if (!audience) throw Error("please define opts.verifyOptions.audience");
30
+ if (!issuer) throw Error("please define opts.verifyOptions.issuer");
31
+ const jwksUrl = opts?.jwksUrl ?? jwtPluginOptions?.jwks?.remoteUrl ?? (authServerBaseUrl ? `${authServerBaseUrl + (authServerBasePath ?? "")}${jwtPluginOptions?.jwks?.jwksPath ?? "/jwks"}` : void 0);
32
+ const introspectUrl = opts?.remoteVerify?.introspectUrl ?? (authServerBaseUrl ? `${authServerBaseUrl}${authServerBasePath ?? ""}/oauth2/introspect` : void 0);
33
+ return {
34
+ ...opts,
35
+ jwksUrl,
36
+ verifyOptions: {
37
+ ...opts?.verifyOptions,
38
+ audience,
39
+ issuer
40
+ },
41
+ remoteVerify: opts?.remoteVerify && introspectUrl ? {
42
+ ...opts.remoteVerify,
43
+ introspectUrl
44
+ } : void 0
45
+ };
46
+ };
47
+ const toResourceRequestInput = (request) => typeof request.headers?.get === "function" ? requestToResourceInput(request) : request;
25
48
  return {
26
49
  id: "oauth-provider-resource-client",
27
50
  version: PACKAGE_VERSION,
28
51
  getActions() {
29
52
  return {
30
- verifyAccessToken: (async (token, opts) => {
31
- const jwtPluginOptions = await getJwtPluginOptions();
32
- const audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;
33
- const issuer = opts?.verifyOptions?.issuer ?? jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
34
- if (!audience) throw Error("please define opts.verifyOptions.audience");
35
- if (!issuer) throw Error("please define opts.verifyOptions.issuer");
36
- const jwksUrl = opts?.jwksUrl ?? jwtPluginOptions?.jwks?.remoteUrl ?? (authServerBaseUrl ? `${authServerBaseUrl + (authServerBasePath ?? "")}${jwtPluginOptions?.jwks?.jwksPath ?? "/jwks"}` : void 0);
37
- const introspectUrl = opts?.remoteVerify?.introspectUrl ?? (authServerBaseUrl ? `${authServerBaseUrl}${authServerBasePath ?? ""}/oauth2/introspect` : void 0);
53
+ verifyBearerToken: (async (token, opts) => {
54
+ const verifyOptions = await resolveVerifyAccessTokenOptions(opts);
38
55
  try {
39
56
  if (!token?.length) throw new APIError("UNAUTHORIZED", { message: "missing authorization header" });
40
- return await verifyAccessToken(token, {
41
- ...opts,
42
- jwksUrl,
43
- verifyOptions: {
44
- ...opts?.verifyOptions,
45
- audience,
46
- issuer
47
- },
48
- remoteVerify: opts?.remoteVerify && introspectUrl ? {
49
- ...opts.remoteVerify,
50
- introspectUrl
51
- } : void 0
57
+ return await verifyBearerToken(token, verifyOptions);
58
+ } catch (error) {
59
+ raiseResourceServerChallenge(error, verifyOptions.verifyOptions.audience, {
60
+ resourceMetadataMappings: opts?.resourceMetadataMappings,
61
+ dpopSigningAlgorithms: DPOP_SIGNING_ALGORITHMS
52
62
  });
63
+ }
64
+ }),
65
+ verifyAccessTokenRequest: (async (request, opts) => {
66
+ const verifyOptions = await resolveVerifyAccessTokenOptions(opts);
67
+ try {
68
+ return await verifyAccessTokenRequest(toResourceRequestInput(request), verifyOptions);
53
69
  } catch (error) {
54
- throw handleMcpErrors(error, audience, { resourceMetadataMappings: opts?.resourceMetadataMappings });
70
+ raiseResourceServerChallenge(error, verifyOptions.verifyOptions.audience, {
71
+ resourceMetadataMappings: opts?.resourceMetadataMappings,
72
+ dpopSigningAlgorithms: opts?.dpop?.signingAlgorithms ?? DPOP_SIGNING_ALGORITHMS
73
+ });
55
74
  }
56
75
  }),
57
76
  getProtectedResourceMetadata: (async (overrides, opts) => {
@@ -78,6 +97,7 @@ const oauthProviderResourceClient = (auth) => {
78
97
  return {
79
98
  resource,
80
99
  authorization_servers: authorizationServer ? [authorizationServer] : void 0,
100
+ dpop_signing_alg_values_supported: [...oauthProviderOptions?.dpop?.signingAlgorithms ?? DPOP_SIGNING_ALGORITHMS],
81
101
  ...overrides
82
102
  };
83
103
  })
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as oauthProvider } from "./oauth-DU6NeviY.mjs";
1
+ import { r as oauthProvider } from "./oauth-CqOygaZd.mjs";
2
2
  import * as _better_fetch_fetch0 from "@better-fetch/fetch";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/client.mjs CHANGED
@@ -1,17 +1,7 @@
1
- import { t as PACKAGE_VERSION } from "./version-B1ZiRmxj.mjs";
1
+ import { t as buildSignedOAuthQuery } from "./signed-query-CFv2jNMT.mjs";
2
+ import { t as PACKAGE_VERSION } from "./version-DkFgXWfN.mjs";
2
3
  import { safeJSONParse } from "@better-auth/core/utils/json";
3
4
  //#region src/client.ts
4
- function parseSignedQuery(search) {
5
- const params = new URLSearchParams(search);
6
- if (params.has("sig")) {
7
- const signedParams = new URLSearchParams();
8
- for (const [key, value] of params.entries()) {
9
- signedParams.append(key, value);
10
- if (key === "sig") break;
11
- }
12
- return signedParams.toString();
13
- }
14
- }
15
5
  const oauthProviderClient = () => {
16
6
  return {
17
7
  id: "oauth-provider-client",
@@ -26,7 +16,7 @@ const oauthProviderClient = () => {
26
16
  if (body?.oauth_query) return;
27
17
  if (typeof window !== "undefined" && window?.location?.search && !(ctx.method === "GET" || ctx.method === "DELETE")) ctx.body = JSON.stringify({
28
18
  ...body,
29
- oauth_query: parseSignedQuery(window.location.search)
19
+ oauth_query: buildSignedOAuthQuery(window.location.search)
30
20
  });
31
21
  } }
32
22
  }],
package/dist/index.d.mts CHANGED
@@ -1,23 +1,37 @@
1
- import { _ as SchemaClient, a as OAuthClient, b as VerificationValue, c as TokenEndpointAuthMethod, d as OAuthAuthorizationQuery, f as OAuthConsent, g as Prompt, h as OAuthRefreshToken, i as GrantType, l as AuthorizePrompt, m as OAuthOptions, n as AuthServerMetadata, o as OIDCMetadata, p as OAuthOpaqueAccessToken, r as BearerMethodsSupported, s as ResourceServerMetadata, t as AuthMethod, u as ClientDiscovery, v as Scope, x as Awaitable, y as StoreTokenType } from "./oauth-BXrYl5x6.mjs";
2
- import { a as OAuthErrorCode, c as OAuthRedirectOnError, i as OAuthEndpointRedirectContext, n as oauthProvider, o as OAuthFieldErrorCode, r as OAuthEndpointErrorResult, s as OAuthFieldErrorCodeMap, t as getOAuthProviderState } from "./oauth-DU6NeviY.mjs";
3
- import { verifyAccessToken } from "better-auth/oauth2";
1
+ import { A as OAuthProviderExtension, B as StoreTokenType, C as OAuthConsent, D as OAuthOpaqueAccessToken, E as OAuthMetadataExtensionInput, F as OAuthTokenResponse, H as ClientRegistrationRequest, I as OAuthUserInfoExtensionInput, L as Prompt, M as OAuthResource, N as OAuthResourceInput, O as OAuthOptions, P as OAuthTokenIssueParams, R as SchemaClient, S as OAuthClientResource, T as OAuthExtensionGrantHandlerInput, U as ResourceUriSchema, V as VerificationValue, _ as OAuthClaimExtensionInput, a as GrantType, b as OAuthClientAuthenticationResult, c as ResourceServerMetadata, d as ActiveAccessTokenPayload, f as AuthorizePrompt, g as OAuthAuthorizationQuery, h as OAuthAuthenticatedClient, i as Confirmation, j as OAuthRefreshToken, k as OAuthProviderApi, l as TokenEndpointAuthMethod, m as InitialAccessTokenAuthorization, n as AuthServerMetadata, o as OAuthClient, p as ClientDiscovery, r as BearerMethodsSupported, s as OIDCMetadata, t as AuthMethod, u as TokenType, v as OAuthClientAuthenticationInput, w as OAuthExtensionGrantHandler, x as OAuthClientAuthenticationStrategy, y as OAuthClientAuthenticationRequest, z as Scope } from "./oauth-CPWY2Few.mjs";
2
+ import { a as OAuthEndpointErrorResult, c as OAuthFieldErrorCode, i as getIssuer, l as OAuthFieldErrorCodeMap, n as getOAuthProviderState, o as OAuthEndpointRedirectContext, r as oauthProvider, s as OAuthErrorCode, t as DEFAULT_OAUTH_SCOPES, u as OAuthRedirectOnError } from "./oauth-CqOygaZd.mjs";
3
+ import { getSessionFromCtx } from "better-auth/api";
4
4
  import { JWSAlgorithms, JwtOptions } from "better-auth/plugins";
5
- import { JWTPayload } from "jose";
6
- import { GenericEndpointContext } from "@better-auth/core";
5
+ import { AuthContext, GenericEndpointContext } from "@better-auth/core";
7
6
  import * as better_auth0 from "better-auth";
8
7
 
9
- //#region src/mcp.d.ts
8
+ //#region src/extensions.d.ts
10
9
  /**
11
- * A request middleware handler that checks and responds with
12
- * a WWW-Authenticate header for unauthenticated responses.
10
+ * Registers an {@link OAuthProviderExtension} with the OAuth Provider plugin
11
+ * from a companion plugin's `init()` hook. An extension can add token grants,
12
+ * assertion-based client authentication methods, additive discovery metadata,
13
+ * access-token / ID-token / UserInfo claims, and client-id discovery, without
14
+ * forking provider core.
13
15
  *
14
- * @external
16
+ * Call this once, at `init()` time. It is idempotent in the same `extension`
17
+ * object, so re-running a plugin's `init()` (for example when one plugin factory
18
+ * result is shared across two `betterAuth()` instances) does not register it
19
+ * twice. It throws if the oauth-provider plugin is not installed, if a grant
20
+ * type or assertion type is not an absolute URI, if a client authentication
21
+ * method reuses a built-in name, or if the extension registers a grant type,
22
+ * auth method, or assertion type that another extension already registered
23
+ * (contributions must be disjoint).
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * init(ctx) {
28
+ * extendOAuthProvider(ctx, {
29
+ * grants: { "urn:example:grant": async ({ provider }) => provider.issueTokens(...) },
30
+ * });
31
+ * }
32
+ * ```
15
33
  */
16
- declare const mcpHandler: (/** Resource is the same url as the audience */
17
-
18
- verifyOptions: Parameters<typeof verifyAccessToken>[1], handler: (req: Request, jwt: JWTPayload) => Awaitable<Response>, opts?: {
19
- /** Maps non-url (ie urn, client) resources to resource_metadata */resourceMetadataMappings: Record<string, string>;
20
- }) => (req: Request) => Promise<Response>;
34
+ declare function extendOAuthProvider(ctx: AuthContext, extension: OAuthProviderExtension): void;
21
35
  //#endregion
22
36
  //#region src/metadata.d.ts
23
37
  declare function authServerMetadata(ctx: GenericEndpointContext, opts?: JwtOptions, overrides?: {
@@ -25,8 +39,12 @@ declare function authServerMetadata(ctx: GenericEndpointContext, opts?: JwtOptio
25
39
  dynamic_client_registration_supported?: boolean;
26
40
  public_client_supported?: boolean;
27
41
  grant_types_supported?: GrantType[];
42
+ token_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
43
+ endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
28
44
  jwt_disabled?: boolean;
45
+ dpop_signing_alg_values_supported?: JWSAlgorithms[];
29
46
  }): AuthServerMetadata;
47
+ declare function oauthAuthorizationServerMetadata(ctx: GenericEndpointContext, opts: OAuthOptions<Scope[]>): AuthServerMetadata;
30
48
  declare function oidcServerMetadata(ctx: GenericEndpointContext, opts: OAuthOptions<Scope[]> & {
31
49
  claims?: string[];
32
50
  }): {
@@ -52,18 +70,20 @@ declare function oidcServerMetadata(ctx: GenericEndpointContext, opts: OAuthOpti
52
70
  op_policy_uri?: string | undefined;
53
71
  op_tos_uri?: string | undefined;
54
72
  revocation_endpoint?: string | undefined;
55
- revocation_endpoint_auth_methods_supported?: AuthMethod[] | undefined;
73
+ revocation_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[] | undefined;
56
74
  revocation_endpoint_auth_signing_alg_values_supported?: better_auth0.PrivateKeyJwtSigningAlgorithm[] | undefined;
57
75
  introspection_endpoint?: string | undefined;
58
- introspection_endpoint_auth_methods_supported?: AuthMethod[] | undefined;
76
+ introspection_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[] | undefined;
59
77
  introspection_endpoint_auth_signing_alg_values_supported?: better_auth0.PrivateKeyJwtSigningAlgorithm[] | undefined;
60
78
  code_challenge_methods_supported: "S256"[];
61
79
  authorization_response_iss_parameter_supported?: boolean | undefined;
62
80
  client_id_metadata_document_supported?: boolean | undefined;
63
81
  backchannel_logout_supported?: boolean | undefined;
64
82
  backchannel_logout_session_supported?: boolean | undefined;
83
+ dpop_signing_alg_values_supported?: JWSAlgorithms[] | undefined;
65
84
  id_token_signing_alg_values_supported: JWSAlgorithms[] | ["HS256"];
66
85
  };
86
+ declare function metadataResponse(body: unknown, extraHeaders?: HeadersInit): Response;
67
87
  /**
68
88
  * Provides an exportable `/.well-known/oauth-authorization-server`.
69
89
  *
@@ -108,4 +128,67 @@ declare function checkOAuthClient(client: OAuthClient, opts: OAuthOptions<Scope[
108
128
  */
109
129
  declare function oauthToSchema(input: OAuthClient): SchemaClient<Scope[]>;
110
130
  //#endregion
111
- export { AuthMethod, AuthServerMetadata, AuthorizePrompt, BearerMethodsSupported, ClientDiscovery, GrantType, OAuthAuthorizationQuery, OAuthClient, OAuthConsent, type OAuthEndpointErrorResult, type OAuthEndpointRedirectContext, type OAuthErrorCode, type OAuthFieldErrorCode, type OAuthFieldErrorCodeMap, OAuthOpaqueAccessToken, OAuthOptions, type OAuthRedirectOnError, OAuthRefreshToken, OIDCMetadata, Prompt, ResourceServerMetadata, SchemaClient, Scope, StoreTokenType, TokenEndpointAuthMethod, VerificationValue, authServerMetadata, checkOAuthClient, getOAuthProviderState, mcpHandler, oauthProvider, oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata, oauthToSchema, oidcServerMetadata };
131
+ //#region src/resource-challenge.d.ts
132
+ /**
133
+ * Raise an OAuth resource-server challenge for a failed access-token request.
134
+ *
135
+ * Missing/invalid bearer credentials are reported with RFC 6750 plus the RFC
136
+ * 9728 `resource_metadata` pointer. DPoP-bound-token failures are reported with
137
+ * RFC 9449's `DPoP` challenge so clients know which proof algorithms to use.
138
+ * Non-URL resources (for example a `urn:` or a client id) resolve their
139
+ * metadata URL through `resourceMetadataMappings`.
140
+ *
141
+ * @internal
142
+ */
143
+ declare function raiseResourceServerChallenge(error: unknown, resource: string | string[], opts?: {
144
+ /** Maps non-URL (urn, client) resources to their resource_metadata URL. */resourceMetadataMappings?: Record<string, string>; /** DPoP JWS algorithms to advertise in RFC 9449 challenges. */
145
+ dpopSigningAlgorithms?: readonly string[]; /** Space-delimited scopes to advertise in RFC 6750 bearer challenges. */
146
+ scope?: string;
147
+ }): never;
148
+ //#endregion
149
+ //#region src/token.d.ts
150
+ /**
151
+ * Returns the OAuth Provider's server-side capability surface bound to `ctx`.
152
+ * The token endpoint passes one (pre-bound to the dispatched grant) to each
153
+ * extension grant handler; a companion plugin's own endpoint calls this directly
154
+ * with its grant type. `grantType` is bound here, not per issuance, so a handler
155
+ * cannot mislabel the grant; omit it for capabilities that do not issue tokens
156
+ * (`getClient`, `validateAccessToken`, `requireActiveAccessToken`), and
157
+ * `issueTokens` then throws.
158
+ */
159
+ declare function getOAuthProviderApi(ctx: GenericEndpointContext, opts: OAuthOptions<Scope[]>, grantType?: GrantType): OAuthProviderApi;
160
+ //#endregion
161
+ //#region src/utils/client-assertion.d.ts
162
+ /**
163
+ * Enforces the assertion-hygiene claims every client-assertion authentication
164
+ * method must check, independent of how the signature is verified or where the
165
+ * verification keys come from:
166
+ * - `aud` MUST include `expectedAudience` (RFC 7523 §3 rule 3),
167
+ * - `exp` MUST be present, unexpired, and at most `assertionMaxLifetime`
168
+ * seconds away (RFC 7523 §3 rule 4),
169
+ * - `iat`, when present, MUST be within `assertionMaxLifetime`,
170
+ * - `jti` MUST be present and single-use; this consumes a replay tombstone keyed
171
+ * by `` `${namespace}:${jti}` ``, inserted under the adapter's primary key so a
172
+ * replay across workers fails atomically.
173
+ *
174
+ * A custom {@link OAuthClientAuthenticationStrategy} should call this after
175
+ * verifying the assertion signature, so an extension method inherits the same
176
+ * replay, lifetime, and audience guarantees as the built-in `private_key_jwt`
177
+ * path, which calls it too.
178
+ *
179
+ * @param params.namespace Scopes the replay tombstone to the method and client,
180
+ * e.g. `` `${method}:${clientId}` ``, so the same `jti` can recur across
181
+ * distinct methods or clients but never within one.
182
+ */
183
+ declare function consumeClientAssertion(ctx: GenericEndpointContext, opts: OAuthOptions<Scope[]>, params: {
184
+ namespace: string;
185
+ payload: {
186
+ aud?: unknown;
187
+ exp?: unknown;
188
+ iat?: unknown;
189
+ jti?: unknown;
190
+ };
191
+ expectedAudience: string;
192
+ }): Promise<void>;
193
+ //#endregion
194
+ export { ActiveAccessTokenPayload, AuthMethod, AuthServerMetadata, AuthorizePrompt, BearerMethodsSupported, ClientDiscovery, ClientRegistrationRequest, Confirmation, DEFAULT_OAUTH_SCOPES, GrantType, InitialAccessTokenAuthorization, OAuthAuthenticatedClient, OAuthAuthorizationQuery, OAuthClaimExtensionInput, type OAuthClient, OAuthClientAuthenticationInput, OAuthClientAuthenticationRequest, OAuthClientAuthenticationResult, OAuthClientAuthenticationStrategy, OAuthClientResource, OAuthConsent, type OAuthEndpointErrorResult, type OAuthEndpointRedirectContext, type OAuthErrorCode, OAuthExtensionGrantHandler, OAuthExtensionGrantHandlerInput, type OAuthFieldErrorCode, type OAuthFieldErrorCodeMap, OAuthMetadataExtensionInput, OAuthOpaqueAccessToken, OAuthOptions, OAuthProviderApi, OAuthProviderExtension, type OAuthRedirectOnError, OAuthRefreshToken, OAuthResource, OAuthResourceInput, OAuthTokenIssueParams, OAuthTokenResponse, OAuthUserInfoExtensionInput, OIDCMetadata, Prompt, type ResourceServerMetadata, ResourceUriSchema, SchemaClient, Scope, StoreTokenType, TokenEndpointAuthMethod, TokenType, VerificationValue, authServerMetadata, checkOAuthClient, consumeClientAssertion, extendOAuthProvider, getIssuer, getOAuthProviderApi, getOAuthProviderState, metadataResponse, oauthAuthorizationServerMetadata, oauthProvider, oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata, oauthToSchema, oidcServerMetadata, raiseResourceServerChallenge };