@better-auth/oauth-provider 1.7.0-rc.1 → 1.7.0-rc.3
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/{client-assertion-D-tAYsKC.mjs → client-assertion-CsbEATZc.mjs} +203 -30
- package/dist/client-resource.d.mts +14 -12
- package/dist/client-resource.mjs +34 -6
- package/dist/client.d.mts +2 -4
- package/dist/client.mjs +2 -2
- package/dist/index.d.mts +71 -35
- package/dist/index.mjs +2409 -688
- package/dist/internal.d.mts +51 -0
- package/dist/internal.mjs +3 -0
- package/dist/{oauth-ScTJEcFV.d.mts → oauth-Bi2PA_d1.d.mts} +198 -93
- package/dist/{oauth-BrNRbP2A.d.mts → oauth-CgWbnA8o.d.mts} +147 -115
- package/dist/register-BotzQoS8.mjs +1557 -0
- package/dist/resource-challenge-CiJTlsEh.mjs +100 -0
- package/dist/{signed-query-Df1MNiSH.mjs → signed-query-BQAwsV_w.mjs} +1 -1
- package/dist/{utils-DO8lmoDw.mjs → utils-GbnW6qPl.mjs} +72 -50
- package/dist/{version--aseHtsu.mjs → version-xoFrTW0m.mjs} +1 -1
- package/package.json +15 -6
- package/dist/introspect-DvHp2a64.mjs +0 -2507
- package/dist/resource-challenge-B-cqv4ur.mjs +0 -63
- package/dist/rolldown-runtime-wcPFST8Q.mjs +0 -13
|
@@ -1,23 +1,121 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as getClient } from "./utils-DO8lmoDw.mjs";
|
|
1
|
+
import { N as getClientDiscoveries, a as getClient } from "./utils-GbnW6qPl.mjs";
|
|
3
2
|
import { isPublicRoutableHost } from "@better-auth/core/utils/host";
|
|
4
3
|
import { APIError } from "better-call";
|
|
5
4
|
import { CLIENT_ASSERTION_TYPE, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS } from "@better-auth/core/oauth2";
|
|
6
5
|
import { base64Url } from "@better-auth/utils/base64";
|
|
7
6
|
import { createHash } from "@better-auth/utils/hash";
|
|
8
7
|
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
|
+
//#region src/client-jwks.ts
|
|
21
|
+
const EC_PRIVATE_KEY_JWT_ALGORITHM_BY_CURVE = {
|
|
22
|
+
"P-256": "ES256",
|
|
23
|
+
"P-384": "ES384",
|
|
24
|
+
"P-521": "ES512"
|
|
25
|
+
};
|
|
26
|
+
const OKP_PRIVATE_KEY_JWT_SIGNING_CURVES = ["Ed25519"];
|
|
27
|
+
const PRIVATE_JWK_MEMBER_NAMES = [
|
|
28
|
+
"d",
|
|
29
|
+
"p",
|
|
30
|
+
"q",
|
|
31
|
+
"dp",
|
|
32
|
+
"dq",
|
|
33
|
+
"qi",
|
|
34
|
+
"oth"
|
|
35
|
+
];
|
|
36
|
+
function isRecord(value) {
|
|
37
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38
|
+
}
|
|
39
|
+
function hasStringMember(key, memberName) {
|
|
40
|
+
return typeof key[memberName] === "string" && key[memberName].length > 0;
|
|
41
|
+
}
|
|
42
|
+
function isSupportedEcSigningCurve(curve) {
|
|
43
|
+
return typeof curve === "string" && Object.prototype.hasOwnProperty.call(EC_PRIVATE_KEY_JWT_ALGORITHM_BY_CURVE, curve);
|
|
44
|
+
}
|
|
45
|
+
function isSupportedOkpSigningCurve(curve) {
|
|
46
|
+
return OKP_PRIVATE_KEY_JWT_SIGNING_CURVES.some((signingCurve) => signingCurve === curve);
|
|
47
|
+
}
|
|
48
|
+
function isSupportedPublicJwk(key) {
|
|
49
|
+
switch (key.kty) {
|
|
50
|
+
case "RSA": return hasStringMember(key, "n") && hasStringMember(key, "e");
|
|
51
|
+
case "EC": return isSupportedEcSigningCurve(key.crv) && hasStringMember(key, "x") && hasStringMember(key, "y");
|
|
52
|
+
case "OKP": return isSupportedOkpSigningCurve(key.crv) && hasStringMember(key, "x");
|
|
53
|
+
default: return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function hasSupportedPrivateKeyJwtAlgorithm(key) {
|
|
57
|
+
if (key.alg === void 0) return true;
|
|
58
|
+
if (typeof key.alg !== "string" || !PRIVATE_KEY_JWT_SIGNING_ALGORITHMS.some((algorithm) => algorithm === key.alg)) return false;
|
|
59
|
+
switch (key.kty) {
|
|
60
|
+
case "RSA": return key.alg.startsWith("RS") || key.alg.startsWith("PS");
|
|
61
|
+
case "EC": return isSupportedEcSigningCurve(key.crv) && EC_PRIVATE_KEY_JWT_ALGORITHM_BY_CURVE[key.crv] === key.alg;
|
|
62
|
+
case "OKP": return isSupportedOkpSigningCurve(key.crv) && key.alg === "EdDSA";
|
|
63
|
+
default: return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validates an OAuth client's public asymmetric JWK set.
|
|
68
|
+
*
|
|
69
|
+
* This boundary accepts only the RFC 7517 `{ keys: [...] }` representation.
|
|
70
|
+
* It performs no I/O and returns the validated set for downstream JOSE
|
|
71
|
+
* verification.
|
|
72
|
+
*
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
function validatePublicClientJwks(input) {
|
|
76
|
+
const keys = isRecord(input) && Array.isArray(input.keys) ? input.keys : void 0;
|
|
77
|
+
if (!keys?.length) return {
|
|
78
|
+
valid: false,
|
|
79
|
+
error: "jwks must be an RFC 7517 JWK Set object with a non-empty keys array"
|
|
80
|
+
};
|
|
81
|
+
for (const key of keys) {
|
|
82
|
+
if (!isRecord(key)) return {
|
|
83
|
+
valid: false,
|
|
84
|
+
error: "jwks keys must be supported public JWKs with required key parameters"
|
|
85
|
+
};
|
|
86
|
+
if (key.kty === "oct" || "k" in key || PRIVATE_JWK_MEMBER_NAMES.some((name) => name in key)) return {
|
|
87
|
+
valid: false,
|
|
88
|
+
error: "jwks must contain only public asymmetric keys"
|
|
89
|
+
};
|
|
90
|
+
if (!isSupportedPublicJwk(key)) return {
|
|
91
|
+
valid: false,
|
|
92
|
+
error: "jwks keys must be supported public JWKs with required key parameters"
|
|
93
|
+
};
|
|
94
|
+
if (!hasSupportedPrivateKeyJwtAlgorithm(key)) return {
|
|
95
|
+
valid: false,
|
|
96
|
+
error: "jwks key alg must be supported for private_key_jwt and compatible with its key type and signing curve"
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
valid: true,
|
|
101
|
+
jwks: { keys }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
9
105
|
//#region src/utils/client-assertion.ts
|
|
10
106
|
var client_assertion_exports = /* @__PURE__ */ __exportAll({
|
|
11
107
|
consumeClientAssertion: () => consumeClientAssertion,
|
|
12
108
|
isPrivateHostname: () => isPrivateHostname,
|
|
13
109
|
verifyClientAssertion: () => verifyClientAssertion
|
|
14
110
|
});
|
|
15
|
-
const
|
|
111
|
+
const jwksCaches = /* @__PURE__ */ new WeakMap();
|
|
16
112
|
const JWKS_CACHE_TTL_MS = 300 * 1e3;
|
|
17
113
|
const JWKS_CACHE_MAX_ENTRIES = 500;
|
|
18
114
|
const JWKS_FETCH_TIMEOUT_MS = 5e3;
|
|
19
|
-
|
|
20
|
-
|
|
115
|
+
const MAX_JWKS_RESPONSE_BYTES = 64 * 1024;
|
|
116
|
+
const JSON_CONTENT_TYPE = /^application\/(?:[-\w.]+\+)?json\s*(?:;|$)/i;
|
|
117
|
+
function setJwksCache(jwksCache, cacheKey, jwks, fetchedAt) {
|
|
118
|
+
jwksCache.set(cacheKey, {
|
|
21
119
|
jwks,
|
|
22
120
|
fetchedAt
|
|
23
121
|
});
|
|
@@ -26,6 +124,16 @@ function setJwksCache(uri, jwks, fetchedAt) {
|
|
|
26
124
|
if (oldest !== void 0) jwksCache.delete(oldest);
|
|
27
125
|
}
|
|
28
126
|
}
|
|
127
|
+
function getJwksCache(opts) {
|
|
128
|
+
const existingCache = jwksCaches.get(opts);
|
|
129
|
+
if (existingCache) return existingCache;
|
|
130
|
+
const cache = /* @__PURE__ */ new Map();
|
|
131
|
+
jwksCaches.set(opts, cache);
|
|
132
|
+
return cache;
|
|
133
|
+
}
|
|
134
|
+
function getJwksCacheKey(client) {
|
|
135
|
+
return `${client.clientDiscoveryId ?? "managed"}:${client.jwksUri ?? ""}`;
|
|
136
|
+
}
|
|
29
137
|
const ALGORITHMS_LIST = [...PRIVATE_KEY_JWT_SIGNING_ALGORITHMS];
|
|
30
138
|
/**
|
|
31
139
|
* SSRF gate for user-supplied server-side fetch targets (`jwks_uri`,
|
|
@@ -49,6 +157,14 @@ function validateJwksUri(ctx, jwksUri, clientIdUrlOrigin) {
|
|
|
49
157
|
error_description: "jwks_uri must use HTTPS",
|
|
50
158
|
error: "invalid_client"
|
|
51
159
|
});
|
|
160
|
+
if (parsed.username || parsed.password) throw new APIError("BAD_REQUEST", {
|
|
161
|
+
error_description: "jwks_uri must not contain credentials",
|
|
162
|
+
error: "invalid_client"
|
|
163
|
+
});
|
|
164
|
+
if (jwksUri.includes("#")) throw new APIError("BAD_REQUEST", {
|
|
165
|
+
error_description: "jwks_uri must not include a fragment component",
|
|
166
|
+
error: "invalid_client"
|
|
167
|
+
});
|
|
52
168
|
if (isPrivateHostname(parsed.hostname)) throw new APIError("BAD_REQUEST", {
|
|
53
169
|
error_description: "jwks_uri must not point to a private or reserved address",
|
|
54
170
|
error: "invalid_client"
|
|
@@ -60,63 +176,120 @@ function validateJwksUri(ctx, jwksUri, clientIdUrlOrigin) {
|
|
|
60
176
|
});
|
|
61
177
|
}
|
|
62
178
|
function urlClientIdOrigin(clientId) {
|
|
63
|
-
if (!clientId.startsWith("https://") && !clientId.startsWith("http://")) return;
|
|
64
179
|
try {
|
|
65
|
-
|
|
180
|
+
const parsed = new URL(clientId);
|
|
181
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return;
|
|
182
|
+
return parsed.origin;
|
|
66
183
|
} catch {
|
|
67
184
|
return;
|
|
68
185
|
}
|
|
69
186
|
}
|
|
70
|
-
async function
|
|
187
|
+
async function readBoundedResponseBody(response) {
|
|
188
|
+
const contentLength = response.headers.get("content-length");
|
|
189
|
+
if (contentLength !== null && Number.isFinite(Number(contentLength)) && Number(contentLength) > MAX_JWKS_RESPONSE_BYTES) {
|
|
190
|
+
await response.body?.cancel();
|
|
191
|
+
throw new Error("JWKS response exceeds 64 KiB");
|
|
192
|
+
}
|
|
193
|
+
if (!response.body) return "";
|
|
194
|
+
const reader = response.body.getReader();
|
|
195
|
+
const chunks = [];
|
|
196
|
+
let totalBytes = 0;
|
|
197
|
+
while (true) {
|
|
198
|
+
const { done, value } = await reader.read();
|
|
199
|
+
if (done) break;
|
|
200
|
+
totalBytes += value.byteLength;
|
|
201
|
+
if (totalBytes > MAX_JWKS_RESPONSE_BYTES) {
|
|
202
|
+
await reader.cancel();
|
|
203
|
+
throw new Error("JWKS response exceeds 64 KiB");
|
|
204
|
+
}
|
|
205
|
+
chunks.push(value);
|
|
206
|
+
}
|
|
207
|
+
const bytes = new Uint8Array(totalBytes);
|
|
208
|
+
let offset = 0;
|
|
209
|
+
for (const chunk of chunks) {
|
|
210
|
+
bytes.set(chunk, offset);
|
|
211
|
+
offset += chunk.byteLength;
|
|
212
|
+
}
|
|
213
|
+
return new TextDecoder().decode(bytes);
|
|
214
|
+
}
|
|
215
|
+
async function fetchJwksFromUri(jwksUri, fetchClientMetadataResource = globalThis.fetch) {
|
|
71
216
|
const controller = new AbortController();
|
|
72
217
|
const timeout = setTimeout(() => controller.abort(), JWKS_FETCH_TIMEOUT_MS);
|
|
73
218
|
try {
|
|
74
|
-
const response = await
|
|
219
|
+
const response = await fetchClientMetadataResource(jwksUri, {
|
|
75
220
|
signal: controller.signal,
|
|
76
221
|
headers: { accept: "application/json" },
|
|
77
222
|
redirect: "error"
|
|
78
223
|
});
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
224
|
+
if (response.redirected) throw new Error("JWKS fetch redirected");
|
|
225
|
+
if (response.status !== 200) throw new Error(`JWKS fetch returned ${response.status}`);
|
|
226
|
+
const contentType = response.headers.get("content-type");
|
|
227
|
+
if (!contentType || !JSON_CONTENT_TYPE.test(contentType)) throw new Error("JWKS response must use a JSON media type");
|
|
228
|
+
const responseBody = await readBoundedResponseBody(response);
|
|
229
|
+
let parsedBody;
|
|
230
|
+
try {
|
|
231
|
+
parsedBody = JSON.parse(responseBody);
|
|
232
|
+
} catch {
|
|
233
|
+
return { valid: false };
|
|
234
|
+
}
|
|
235
|
+
const result = validatePublicClientJwks(parsedBody);
|
|
236
|
+
if (!result.valid) return { valid: false };
|
|
237
|
+
return {
|
|
238
|
+
valid: true,
|
|
239
|
+
jwks: result.jwks
|
|
240
|
+
};
|
|
83
241
|
} finally {
|
|
84
242
|
clearTimeout(timeout);
|
|
85
243
|
}
|
|
86
244
|
}
|
|
87
|
-
|
|
245
|
+
function createClientJwksFetchError() {
|
|
246
|
+
return new APIError("BAD_REQUEST", {
|
|
247
|
+
error_description: "failed to fetch client JWKS",
|
|
248
|
+
error: "invalid_client"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async function fetchClientJwks(ctx, opts, client) {
|
|
88
252
|
if (client.jwks) return JSON.parse(client.jwks);
|
|
89
253
|
if (!client.jwksUri) throw new APIError("BAD_REQUEST", {
|
|
90
254
|
error_description: "client has no JWKS configured",
|
|
91
255
|
error: "invalid_client"
|
|
92
256
|
});
|
|
93
|
-
|
|
257
|
+
const discovery = client.clientDiscoveryId ? getClientDiscoveries(opts).find((candidate) => candidate.id === client.clientDiscoveryId) : void 0;
|
|
258
|
+
if (client.clientDiscoveryId && !discovery?.fetchClientMetadataResource) throw new APIError("BAD_REQUEST", {
|
|
259
|
+
error_description: "client discovery does not provide a metadata resource transport",
|
|
260
|
+
error: "invalid_client"
|
|
261
|
+
});
|
|
262
|
+
validateJwksUri(ctx, client.jwksUri, client.clientDiscoveryId ? urlClientIdOrigin(client.clientId) : void 0);
|
|
94
263
|
const now = Date.now();
|
|
95
|
-
const
|
|
264
|
+
const cacheKey = getJwksCacheKey(client);
|
|
265
|
+
const jwksCache = getJwksCache(opts);
|
|
266
|
+
const cached = jwksCache.get(cacheKey);
|
|
96
267
|
if (cached && now - cached.fetchedAt < JWKS_CACHE_TTL_MS) return cached.jwks;
|
|
268
|
+
let result;
|
|
97
269
|
try {
|
|
98
|
-
|
|
99
|
-
setJwksCache(client.jwksUri, jwks, now);
|
|
100
|
-
return jwks;
|
|
270
|
+
result = await fetchJwksFromUri(client.jwksUri, discovery?.fetchClientMetadataResource);
|
|
101
271
|
} catch {
|
|
102
272
|
const staleLimitMs = JWKS_CACHE_TTL_MS * 2;
|
|
103
273
|
if (cached && now - cached.fetchedAt < staleLimitMs) return cached.jwks;
|
|
104
|
-
throw
|
|
105
|
-
error_description: "failed to fetch client JWKS",
|
|
106
|
-
error: "invalid_client"
|
|
107
|
-
});
|
|
274
|
+
throw createClientJwksFetchError();
|
|
108
275
|
}
|
|
276
|
+
if (!result.valid) throw createClientJwksFetchError();
|
|
277
|
+
setJwksCache(jwksCache, cacheKey, result.jwks, now);
|
|
278
|
+
return result.jwks;
|
|
109
279
|
}
|
|
110
280
|
/**
|
|
111
281
|
* Refetch JWKS from jwks_uri when signature verification fails with cached keys.
|
|
112
282
|
* Handles key rotation: the client may have published a new key that isn't in our cache yet.
|
|
113
283
|
*/
|
|
114
|
-
async function refetchClientJwks(client) {
|
|
284
|
+
async function refetchClientJwks(opts, client) {
|
|
115
285
|
if (!client.jwksUri) return null;
|
|
286
|
+
const discovery = client.clientDiscoveryId ? getClientDiscoveries(opts).find((candidate) => candidate.id === client.clientDiscoveryId) : void 0;
|
|
287
|
+
if (client.clientDiscoveryId && !discovery?.fetchClientMetadataResource) return null;
|
|
116
288
|
try {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
289
|
+
const result = await fetchJwksFromUri(client.jwksUri, discovery?.fetchClientMetadataResource);
|
|
290
|
+
if (!result.valid) return null;
|
|
291
|
+
setJwksCache(getJwksCache(opts), getJwksCacheKey(client), result.jwks, Date.now());
|
|
292
|
+
return result.jwks;
|
|
120
293
|
} catch {
|
|
121
294
|
return null;
|
|
122
295
|
}
|
|
@@ -254,7 +427,7 @@ async function verifyClientAssertion(ctx, opts, clientAssertion, clientAssertion
|
|
|
254
427
|
error_description: "client is not registered for private_key_jwt authentication",
|
|
255
428
|
error: "invalid_client"
|
|
256
429
|
});
|
|
257
|
-
const jwks = await fetchClientJwks(ctx, client);
|
|
430
|
+
const jwks = await fetchClientJwks(ctx, opts, client);
|
|
258
431
|
const audience = expectedAudience ?? `${ctx.context.baseURL}/oauth2/token`;
|
|
259
432
|
const verifyOpts = {
|
|
260
433
|
issuer: clientId,
|
|
@@ -267,7 +440,7 @@ async function verifyClientAssertion(ctx, opts, clientAssertion, clientAssertion
|
|
|
267
440
|
({payload} = await jwtVerify(clientAssertion, createLocalJWKSet(jwks), verifyOpts));
|
|
268
441
|
} catch (verifyErr) {
|
|
269
442
|
if (verifyErr instanceof Error && /no matching key|no applicable key/i.test(verifyErr.message)) {
|
|
270
|
-
const refreshed = await refetchClientJwks(client);
|
|
443
|
+
const refreshed = await refetchClientJwks(opts, client);
|
|
271
444
|
if (refreshed) try {
|
|
272
445
|
({payload} = await jwtVerify(clientAssertion, createLocalJWKSet(refreshed), verifyOpts));
|
|
273
446
|
} catch {
|
|
@@ -293,4 +466,4 @@ async function verifyClientAssertion(ctx, opts, clientAssertion, clientAssertion
|
|
|
293
466
|
return { clientId };
|
|
294
467
|
}
|
|
295
468
|
//#endregion
|
|
296
|
-
export { consumeClientAssertion as n, isPrivateHostname as r, client_assertion_exports as t };
|
|
469
|
+
export { __exportAll as a, validatePublicClientJwks as i, consumeClientAssertion as n, isPrivateHostname as r, client_assertion_exports as t };
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { c as ResourceServerMetadata } from "./oauth-
|
|
1
|
+
import { c as ResourceServerMetadata } from "./oauth-Bi2PA_d1.mjs";
|
|
2
2
|
import { ResourceRequestInput, VerifyAccessTokenRequestOptions } from "better-auth/oauth2";
|
|
3
3
|
import { JWTPayload, JWTVerifyOptions } from "jose";
|
|
4
4
|
import { BetterAuthOptions } from "better-auth/types";
|
|
5
|
-
|
|
6
5
|
//#region src/client-resource.d.ts
|
|
7
6
|
type ResourceClientAuth = {
|
|
8
|
-
options:
|
|
9
|
-
baseURL?: BetterAuthOptions["baseURL"];
|
|
10
|
-
basePath?: BetterAuthOptions["basePath"];
|
|
11
|
-
};
|
|
7
|
+
options: BetterAuthOptions;
|
|
12
8
|
$context: Promise<unknown>;
|
|
13
9
|
};
|
|
14
10
|
declare const oauthProviderResourceClient: <T extends ResourceClientAuth | undefined = undefined>(auth?: T) => {
|
|
@@ -76,9 +72,11 @@ type VerifyAccessTokenOutput<T> = T extends undefined ? (token: string | undefin
|
|
|
76
72
|
type VerifyAccessTokenRequestOutput<T> = T extends undefined ? (request: Request | ResourceRequestInput, opts: VerifyAccessTokenRequestNoAuthOpts) => Promise<JWTPayload> : (request: Request | ResourceRequestInput, opts?: VerifyAccessTokenRequestAuthOpts) => Promise<JWTPayload>;
|
|
77
73
|
type VerifyAccessTokenAuthOpts = {
|
|
78
74
|
verifyOptions?: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience">>;
|
|
79
|
-
|
|
75
|
+
requiredScopes?: readonly string[];
|
|
76
|
+
isScopeSatisfied?: VerifyAccessTokenRequestOptions["isScopeSatisfied"];
|
|
80
77
|
jwksUrl?: string;
|
|
81
|
-
remoteVerify?: VerifyAccessTokenRemote;
|
|
78
|
+
remoteVerify?: VerifyAccessTokenRemote;
|
|
79
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
82
80
|
resourceMetadataMappings?: Record<string, string>;
|
|
83
81
|
};
|
|
84
82
|
type VerifyAccessTokenRequestAuthOpts = VerifyAccessTokenAuthOpts & {
|
|
@@ -86,15 +84,19 @@ type VerifyAccessTokenRequestAuthOpts = VerifyAccessTokenAuthOpts & {
|
|
|
86
84
|
};
|
|
87
85
|
type VerifyAccessTokenNoAuthOpts = {
|
|
88
86
|
verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
|
|
89
|
-
|
|
87
|
+
requiredScopes?: readonly string[];
|
|
88
|
+
isScopeSatisfied?: VerifyAccessTokenRequestOptions["isScopeSatisfied"];
|
|
90
89
|
jwksUrl: string;
|
|
91
|
-
remoteVerify?: VerifyAccessTokenRemote;
|
|
90
|
+
remoteVerify?: VerifyAccessTokenRemote;
|
|
91
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
92
92
|
resourceMetadataMappings?: Record<string, string>;
|
|
93
93
|
} | {
|
|
94
94
|
verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
|
|
95
|
-
|
|
95
|
+
requiredScopes?: readonly string[];
|
|
96
|
+
isScopeSatisfied?: VerifyAccessTokenRequestOptions["isScopeSatisfied"];
|
|
96
97
|
jwksUrl?: string;
|
|
97
|
-
remoteVerify: VerifyAccessTokenRemote;
|
|
98
|
+
remoteVerify: VerifyAccessTokenRemote;
|
|
99
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
98
100
|
resourceMetadataMappings?: Record<string, string>;
|
|
99
101
|
};
|
|
100
102
|
type VerifyAccessTokenRequestNoAuthOpts = VerifyAccessTokenNoAuthOpts & {
|
package/dist/client-resource.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as getJwtPlugin, s as getOAuthProviderPlugin } from "./utils-
|
|
2
|
-
import { t as PACKAGE_VERSION } from "./version
|
|
3
|
-
import { t as
|
|
1
|
+
import { o as getJwtPlugin, s as getOAuthProviderPlugin } from "./utils-GbnW6qPl.mjs";
|
|
2
|
+
import { t as PACKAGE_VERSION } from "./version-xoFrTW0m.mjs";
|
|
3
|
+
import { t as createResourceServerChallenge } from "./resource-challenge-CiJTlsEh.mjs";
|
|
4
4
|
import { APIError } from "better-call";
|
|
5
5
|
import { logger } from "@better-auth/core/env";
|
|
6
6
|
import { BetterAuthError } from "@better-auth/core/error";
|
|
@@ -50,36 +50,64 @@ const oauthProviderResourceClient = (auth) => {
|
|
|
50
50
|
version: PACKAGE_VERSION,
|
|
51
51
|
getActions() {
|
|
52
52
|
return {
|
|
53
|
+
/**
|
|
54
|
+
* Performs verification of an access token for your APIs. Can perform
|
|
55
|
+
* local verification using `jwksUrl` by default. Can also be configured
|
|
56
|
+
* for remote introspection using `remoteVerify` if a confidential client
|
|
57
|
+
* is set up for this API.
|
|
58
|
+
*
|
|
59
|
+
* The optional auth parameter can fill known values automatically.
|
|
60
|
+
*/
|
|
53
61
|
verifyBearerToken: (async (token, opts) => {
|
|
54
62
|
const verifyOptions = await resolveVerifyAccessTokenOptions(opts);
|
|
55
63
|
try {
|
|
56
64
|
if (!token?.length) throw new APIError("UNAUTHORIZED", { message: "missing authorization header" });
|
|
57
65
|
return await verifyBearerToken(token, verifyOptions);
|
|
58
66
|
} catch (error) {
|
|
59
|
-
|
|
67
|
+
const challenge = createResourceServerChallenge(error, verifyOptions.verifyOptions.audience, {
|
|
60
68
|
resourceMetadataMappings: opts?.resourceMetadataMappings,
|
|
61
69
|
dpopSigningAlgorithms: DPOP_SIGNING_ALGORITHMS
|
|
62
70
|
});
|
|
71
|
+
if (challenge) throw challenge;
|
|
72
|
+
throw error;
|
|
63
73
|
}
|
|
64
74
|
}),
|
|
75
|
+
/**
|
|
76
|
+
* Performs verification of a protected-resource request. Use this for
|
|
77
|
+
* new resource-server integrations so sender-constrained DPoP access
|
|
78
|
+
* tokens are enforced with the request method, URL, Authorization
|
|
79
|
+
* scheme, DPoP proof, `ath`, and `cnf.jkt` binding.
|
|
80
|
+
*/
|
|
65
81
|
verifyAccessTokenRequest: (async (request, opts) => {
|
|
66
82
|
const verifyOptions = await resolveVerifyAccessTokenOptions(opts);
|
|
67
83
|
try {
|
|
68
84
|
return await verifyAccessTokenRequest(toResourceRequestInput(request), verifyOptions);
|
|
69
85
|
} catch (error) {
|
|
70
|
-
|
|
86
|
+
const challenge = createResourceServerChallenge(error, verifyOptions.verifyOptions.audience, {
|
|
71
87
|
resourceMetadataMappings: opts?.resourceMetadataMappings,
|
|
72
88
|
dpopSigningAlgorithms: opts?.dpop?.signingAlgorithms ?? DPOP_SIGNING_ALGORITHMS
|
|
73
89
|
});
|
|
90
|
+
if (challenge) throw challenge;
|
|
91
|
+
throw error;
|
|
74
92
|
}
|
|
75
93
|
}),
|
|
94
|
+
/**
|
|
95
|
+
* An authorization server does not typically publish
|
|
96
|
+
* the `/.well-known/oauth-protected-resource` themselves.
|
|
97
|
+
* Thus, we provide a client-only endpoint to help set up
|
|
98
|
+
* your protected resource metadata.
|
|
99
|
+
*
|
|
100
|
+
* The optional auth parameter can fill known values automatically.
|
|
101
|
+
*
|
|
102
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414#section-2
|
|
103
|
+
*/
|
|
76
104
|
getProtectedResourceMetadata: (async (overrides, opts) => {
|
|
77
105
|
const resource = overrides?.resource ?? authServerBaseUrl;
|
|
78
106
|
const oauthProviderOptions = (await getOauthProviderPlugin())?.options;
|
|
79
107
|
if (!resource) throw Error("missing required resource");
|
|
80
108
|
if (oauthProviderOptions?.scopes && opts?.externalScopes && (overrides?.authorization_servers?.length ?? 0) <= 1) throw new BetterAuthError("external scopes should not be provided with one authorization server");
|
|
81
109
|
if (overrides?.scopes_supported) {
|
|
82
|
-
const allValidScopes = new Set([...oauthProviderOptions?.scopes ?? [], ...opts?.externalScopes ?? []]);
|
|
110
|
+
const allValidScopes = /* @__PURE__ */ new Set([...oauthProviderOptions?.scopes ?? [], ...opts?.externalScopes ?? []]);
|
|
83
111
|
for (const sc of overrides.scopes_supported) {
|
|
84
112
|
if (sc === "openid") throw new BetterAuthError("Only the Auth Server should utilize the openid scope");
|
|
85
113
|
if ([
|
package/dist/client.d.mts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { r as oauthProvider } from "./oauth-
|
|
2
|
-
import * as _better_fetch_fetch0 from "@better-fetch/fetch";
|
|
3
|
-
|
|
1
|
+
import { r as oauthProvider } from "./oauth-CgWbnA8o.mjs";
|
|
4
2
|
//#region src/client.d.ts
|
|
5
3
|
declare const oauthProviderClient: () => {
|
|
6
4
|
id: "oauth-provider-client";
|
|
@@ -10,7 +8,7 @@ declare const oauthProviderClient: () => {
|
|
|
10
8
|
name: string;
|
|
11
9
|
description: string;
|
|
12
10
|
hooks: {
|
|
13
|
-
onRequest<T extends Record<string, any>>(ctx:
|
|
11
|
+
onRequest<T extends Record<string, any>>(ctx: import("@better-fetch/fetch").RequestContext<T>): Promise<void>;
|
|
14
12
|
};
|
|
15
13
|
}[];
|
|
16
14
|
$InferServerPlugin: ReturnType<typeof oauthProvider>;
|
package/dist/client.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as buildSignedOAuthQuery } from "./signed-query-
|
|
2
|
-
import { t as PACKAGE_VERSION } from "./version
|
|
1
|
+
import { t as buildSignedOAuthQuery } from "./signed-query-BQAwsV_w.mjs";
|
|
2
|
+
import { t as PACKAGE_VERSION } from "./version-xoFrTW0m.mjs";
|
|
3
3
|
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
4
4
|
//#region src/client.ts
|
|
5
5
|
const oauthProviderClient = () => {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,45 @@
|
|
|
1
|
-
import { A as
|
|
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-
|
|
3
|
-
import {
|
|
1
|
+
import { A as OAuthOpaqueAccessToken, B as Prompt, C as OAuthClientAuthenticationStrategy, D as OAuthExtensionGrantHandler, E as OAuthConsent, F as OAuthResource, G as VerificationValue, H as Scope, I as OAuthResourceInput, J as ResourceUriSchema, K as ClientRegistrationRequest, L as OAuthTokenIssueParams, M as OAuthProviderApi, N as OAuthProviderExtension, O as OAuthExtensionGrantHandlerInput, P as OAuthRefreshToken, R as OAuthTokenResponse, S as OAuthClientAuthenticationResult, T as OAuthClientResource, U as StoreTokenType, V as SchemaClient, W as StoredAuthorizationQuery, Y as oauthClientMetadataSchema, _ as OAuthAuthorizationQuery, a as GrantType, b as OAuthClientAuthenticationInput, c as ResourceServerMetadata, d as ActiveAccessTokenPayload, f as AuthorizePrompt, g as OAuthAuthenticatedClient, h as InitialAccessTokenAuthorization, i as Confirmation, j as OAuthOptions, k as OAuthMetadataExtensionInput, l as TokenEndpointAuthMethod, m as ClientMetadataResourceFetch, n as AuthServerMetadata, o as OAuthClient, p as ClientDiscovery, q as OAuthClientMetadata, r as BearerMethodsSupported, s as OIDCMetadata, t as AuthMethod, u as TokenType, v as OAuthClaimExtensionInput, w as OAuthClientRegistrationResponse, x as OAuthClientAuthenticationRequest, y as OAuthClientAdministrativeResponse, z as OAuthUserInfoExtensionInput } from "./oauth-Bi2PA_d1.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-CgWbnA8o.mjs";
|
|
3
|
+
import { APIError } from "better-call";
|
|
4
4
|
import { JWSAlgorithms, JwtOptions } from "better-auth/plugins";
|
|
5
|
+
import { BetterAuthPlugin } from "better-auth/types";
|
|
5
6
|
import { AuthContext, GenericEndpointContext } from "@better-auth/core";
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
//#region src/device-code.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* RFC 8628 device authorization grant type. A registered OAuth client polls the
|
|
10
|
+
* token endpoint with this `grant_type` to exchange an approved device code for
|
|
11
|
+
* a first-class OAuth token set.
|
|
12
|
+
*/
|
|
13
|
+
declare const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
14
|
+
/**
|
|
15
|
+
* Bridges the {@link https://datatracker.ietf.org/doc/html/rfc8628 RFC 8628}
|
|
16
|
+
* device authorization grant into the OAuth Provider. Pair it with the
|
|
17
|
+
* `device-authorization` plugin (which owns the `/device/code` request endpoint,
|
|
18
|
+
* the user verification flow, and the `deviceCode` table) and the
|
|
19
|
+
* `oauthProvider` plugin: this registers a `device_code` token grant on
|
|
20
|
+
* `/oauth2/token` that issues real OAuth tokens for a registered OAuth client,
|
|
21
|
+
* and advertises `device_authorization_endpoint` in discovery metadata.
|
|
22
|
+
*
|
|
23
|
+
* First-party device login (the device-authorization plugin's own
|
|
24
|
+
* `/device/token`, which mints a Better Auth session token) keeps working
|
|
25
|
+
* unchanged. To stop a registered OAuth client's device code from being redeemed
|
|
26
|
+
* there for a session token, a `before` hook rejects `/device/token` requests
|
|
27
|
+
* whose `client_id` resolves to a registered OAuth client, directing them to
|
|
28
|
+
* `/oauth2/token`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const auth = betterAuth({
|
|
33
|
+
* plugins: [
|
|
34
|
+
* deviceAuthorization(),
|
|
35
|
+
* oauthProvider({ ... }),
|
|
36
|
+
* deviceCodeGrant(),
|
|
37
|
+
* ],
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
declare function deviceCodeGrant(): BetterAuthPlugin;
|
|
42
|
+
//#endregion
|
|
8
43
|
//#region src/extensions.d.ts
|
|
9
44
|
/**
|
|
10
45
|
* Registers an {@link OAuthProviderExtension} with the OAuth Provider plugin
|
|
@@ -19,8 +54,8 @@ import * as better_auth0 from "better-auth";
|
|
|
19
54
|
* twice. It throws if the oauth-provider plugin is not installed, if a grant
|
|
20
55
|
* type or assertion type is not an absolute URI, if a client authentication
|
|
21
56
|
* method reuses a built-in name, or if the extension registers a grant type,
|
|
22
|
-
* auth method,
|
|
23
|
-
* (contributions must be disjoint).
|
|
57
|
+
* auth method, assertion type, or client discovery identifier that another
|
|
58
|
+
* extension already registered (contributions must be disjoint).
|
|
24
59
|
*
|
|
25
60
|
* @example
|
|
26
61
|
* ```ts
|
|
@@ -67,17 +102,17 @@ declare function oidcServerMetadata(ctx: GenericEndpointContext, opts: OAuthOpti
|
|
|
67
102
|
response_modes_supported: "query"[];
|
|
68
103
|
grant_types_supported: GrantType[];
|
|
69
104
|
token_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[] | undefined;
|
|
70
|
-
token_endpoint_auth_signing_alg_values_supported?:
|
|
105
|
+
token_endpoint_auth_signing_alg_values_supported?: import("better-auth").PrivateKeyJwtSigningAlgorithm[] | undefined;
|
|
71
106
|
service_documentation?: string | undefined;
|
|
72
107
|
ui_locales_supported?: string[] | undefined;
|
|
73
108
|
op_policy_uri?: string | undefined;
|
|
74
109
|
op_tos_uri?: string | undefined;
|
|
75
110
|
revocation_endpoint?: string | undefined;
|
|
76
111
|
revocation_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[] | undefined;
|
|
77
|
-
revocation_endpoint_auth_signing_alg_values_supported?:
|
|
112
|
+
revocation_endpoint_auth_signing_alg_values_supported?: import("better-auth").PrivateKeyJwtSigningAlgorithm[] | undefined;
|
|
78
113
|
introspection_endpoint?: string | undefined;
|
|
79
114
|
introspection_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[] | undefined;
|
|
80
|
-
introspection_endpoint_auth_signing_alg_values_supported?:
|
|
115
|
+
introspection_endpoint_auth_signing_alg_values_supported?: import("better-auth").PrivateKeyJwtSigningAlgorithm[] | undefined;
|
|
81
116
|
code_challenge_methods_supported: "S256"[];
|
|
82
117
|
authorization_response_iss_parameter_supported?: boolean | undefined;
|
|
83
118
|
client_id_metadata_document_supported?: boolean | undefined;
|
|
@@ -118,36 +153,37 @@ declare const oauthProviderOpenIdConfigMetadata: <Auth extends {
|
|
|
118
153
|
headers?: HeadersInit;
|
|
119
154
|
}) => (request: Request) => Promise<Response>;
|
|
120
155
|
//#endregion
|
|
121
|
-
//#region src/register.d.ts
|
|
122
|
-
declare function checkOAuthClient(client: OAuthClient, opts: OAuthOptions<Scope[]>, settings?: {
|
|
123
|
-
isRegister?: boolean;
|
|
124
|
-
ctx?: GenericEndpointContext;
|
|
125
|
-
}): Promise<void>;
|
|
126
|
-
/**
|
|
127
|
-
* Converts an OAuth 2.0 Dynamic Client Schema to a Database Schema
|
|
128
|
-
*
|
|
129
|
-
* @param input
|
|
130
|
-
* @returns
|
|
131
|
-
*/
|
|
132
|
-
declare function oauthToSchema(input: OAuthClient): SchemaClient<Scope[]>;
|
|
133
|
-
//#endregion
|
|
134
156
|
//#region src/resource-challenge.d.ts
|
|
135
157
|
/**
|
|
136
|
-
*
|
|
158
|
+
* Create an OAuth resource-server challenge for a failed access-token request.
|
|
137
159
|
*
|
|
138
160
|
* Missing/invalid bearer credentials are reported with RFC 6750 plus the RFC
|
|
139
|
-
* 9728 `resource_metadata` pointer.
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
161
|
+
* 9728 `resource_metadata` pointer. Insufficient-scope failures (built with
|
|
162
|
+
* `createInsufficientScopeError`) are reported with RFC 6750 §3.1's
|
|
163
|
+
* `insufficient_scope` challenge on a 403 naming the scopes the token lacks, so
|
|
164
|
+
* clients can step up their authorization. DPoP-bound-token failures are
|
|
165
|
+
* reported with RFC 9449's `DPoP` challenge so clients know which proof
|
|
166
|
+
* algorithms to use. Non-URL resources (for example a `urn:` or a client id)
|
|
167
|
+
* resolve their metadata URL through `resourceMetadataMappings`.
|
|
143
168
|
*
|
|
144
|
-
*
|
|
169
|
+
* Every other error returns `undefined`, including a plain `FORBIDDEN`: a
|
|
170
|
+
* permission denial that re-authorizing cannot fix must not be answered with a
|
|
171
|
+
* challenge that sends the user through consent for scopes they already hold.
|
|
172
|
+
*
|
|
173
|
+
* @external
|
|
145
174
|
*/
|
|
146
|
-
declare function
|
|
147
|
-
/** Maps non-URL (urn, client) resources to their resource_metadata URL. */
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
175
|
+
declare function createResourceServerChallenge(error: unknown, resource: string | string[], opts?: {
|
|
176
|
+
/** Maps non-URL (urn, client) resources to their resource_metadata URL. */
|
|
177
|
+
resourceMetadataMappings?: Record<string, string>;
|
|
178
|
+
/** DPoP JWS algorithms to advertise in RFC 9449 challenges. */
|
|
179
|
+
dpopSigningAlgorithms?: readonly string[];
|
|
180
|
+
/**
|
|
181
|
+
* Scopes to advertise in RFC 6750 bearer challenges,
|
|
182
|
+
* hinting what an unauthenticated client should request. An
|
|
183
|
+
* insufficient-scope failure advertises the scopes it names instead.
|
|
184
|
+
*/
|
|
185
|
+
challengeScopes?: readonly string[];
|
|
186
|
+
}): APIError | undefined;
|
|
151
187
|
//#endregion
|
|
152
188
|
//#region src/token.d.ts
|
|
153
189
|
/**
|
|
@@ -194,4 +230,4 @@ declare function consumeClientAssertion(ctx: GenericEndpointContext, opts: OAuth
|
|
|
194
230
|
expectedAudience: string;
|
|
195
231
|
}): Promise<void>;
|
|
196
232
|
//#endregion
|
|
197
|
-
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, StoredAuthorizationQuery, TokenEndpointAuthMethod, TokenType, VerificationValue, authServerMetadata,
|
|
233
|
+
export { type ActiveAccessTokenPayload, type AuthMethod, type AuthServerMetadata, type AuthorizePrompt, type BearerMethodsSupported, type ClientDiscovery, type ClientMetadataResourceFetch, type ClientRegistrationRequest, type Confirmation, DEFAULT_OAUTH_SCOPES, DEVICE_CODE_GRANT_TYPE, type GrantType, type InitialAccessTokenAuthorization, type OAuthAuthenticatedClient, type OAuthAuthorizationQuery, type OAuthClaimExtensionInput, type OAuthClient, type OAuthClientAdministrativeResponse, type OAuthClientAuthenticationInput, type OAuthClientAuthenticationRequest, type OAuthClientAuthenticationResult, type OAuthClientAuthenticationStrategy, type OAuthClientMetadata, type OAuthClientRegistrationResponse, type OAuthClientResource, type OAuthConsent, type OAuthEndpointErrorResult, type OAuthEndpointRedirectContext, type OAuthErrorCode, type OAuthExtensionGrantHandler, type OAuthExtensionGrantHandlerInput, type OAuthFieldErrorCode, type OAuthFieldErrorCodeMap, type OAuthMetadataExtensionInput, type OAuthOpaqueAccessToken, type OAuthOptions, type OAuthProviderApi, type OAuthProviderExtension, type OAuthRedirectOnError, type OAuthRefreshToken, type OAuthResource, type OAuthResourceInput, type OAuthTokenIssueParams, type OAuthTokenResponse, type OAuthUserInfoExtensionInput, type OIDCMetadata, type Prompt, type ResourceServerMetadata, ResourceUriSchema, type SchemaClient, type Scope, type StoreTokenType, type StoredAuthorizationQuery, type TokenEndpointAuthMethod, type TokenType, type VerificationValue, authServerMetadata, consumeClientAssertion, createResourceServerChallenge, deviceCodeGrant, extendOAuthProvider, getIssuer, getOAuthProviderApi, getOAuthProviderState, metadataResponse, oauthAuthorizationServerMetadata, oauthClientMetadataSchema, oauthProvider, oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata, oidcServerMetadata };
|