@atlasauth/backend 0.14.1 → 0.16.0
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/CHANGELOG.md +42 -0
- package/dist/access-control.d.ts +53 -0
- package/dist/access-control.js +46 -0
- package/dist/access-control.js.map +1 -0
- package/dist/algs.d.ts +7 -0
- package/dist/algs.js +11 -0
- package/dist/algs.js.map +1 -0
- package/dist/botid.d.ts +70 -0
- package/dist/botid.js +88 -0
- package/dist/botid.js.map +1 -0
- package/dist/client/action-gallery.d.ts +215 -0
- package/dist/client/action-gallery.js +66 -0
- package/dist/client/action-gallery.js.map +1 -0
- package/dist/client/actions.d.ts +21 -0
- package/dist/client/actions.js.map +1 -1
- package/dist/client/api-keys.d.ts +49 -4
- package/dist/client/api-keys.js +6 -2
- package/dist/client/api-keys.js.map +1 -1
- package/dist/client/app-roles.d.ts +76 -0
- package/dist/client/app-roles.js +39 -0
- package/dist/client/app-roles.js.map +1 -0
- package/dist/client/attack-protection.d.ts +33 -1
- package/dist/client/attack-protection.js.map +1 -1
- package/dist/client/billing-plans.d.ts +93 -0
- package/dist/client/billing-plans.js +31 -0
- package/dist/client/billing-plans.js.map +1 -1
- package/dist/client/custom-oauth-providers.d.ts +243 -0
- package/dist/client/custom-oauth-providers.js +60 -0
- package/dist/client/custom-oauth-providers.js.map +1 -0
- package/dist/client/email-templates.d.ts +1 -1
- package/dist/client/email-templates.js.map +1 -1
- package/dist/client/index.d.ts +157 -3
- package/dist/client/index.js +11 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/instance-security.d.ts +104 -0
- package/dist/client/instance-security.js +28 -0
- package/dist/client/instance-security.js.map +1 -1
- package/dist/client/notifications.d.ts +1 -1
- package/dist/client/notifications.js.map +1 -1
- package/dist/client/oauth-clients.d.ts +84 -2
- package/dist/client/oauth-clients.js +13 -0
- package/dist/client/oauth-clients.js.map +1 -1
- package/dist/client/referrals.d.ts +1 -1
- package/dist/client/resource-servers.d.ts +34 -5
- package/dist/client/resource-servers.js.map +1 -1
- package/dist/client/risk-based-mfa.d.ts +3 -0
- package/dist/client/risk-based-mfa.js.map +1 -1
- package/dist/client/scim-tokens.d.ts +18 -0
- package/dist/client/scim-tokens.js +4 -0
- package/dist/client/scim-tokens.js.map +1 -1
- package/dist/client/sessions.d.ts +16 -0
- package/dist/client/sessions.js +15 -0
- package/dist/client/sessions.js.map +1 -1
- package/dist/client/sso-connections.d.ts +105 -0
- package/dist/client/sso-connections.js +29 -0
- package/dist/client/sso-connections.js.map +1 -1
- package/dist/client/users.d.ts +40 -4
- package/dist/client/users.js +8 -3
- package/dist/client/users.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/logout-token.d.ts +1 -1
- package/dist/logout-token.js +3 -2
- package/dist/logout-token.js.map +1 -1
- package/dist/oauth-resource.d.ts +225 -0
- package/dist/oauth-resource.js +469 -0
- package/dist/oauth-resource.js.map +1 -0
- package/dist/oidc.d.ts +1 -1
- package/dist/oidc.js +5 -3
- package/dist/oidc.js.map +1 -1
- package/dist/referral-test-calls.d.ts +7 -7
- package/dist/referral-test-calls.js +2 -2
- package/dist/testing.d.ts +6 -4
- package/dist/testing.js +7 -6
- package/dist/testing.js.map +1 -1
- package/dist/verify.d.ts +11 -0
- package/dist/verify.js +15 -1
- package/dist/verify.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DPOP_PROOF_MAX_AGE_SECONDS = exports.ACCESS_TOKEN_CLOCK_SKEW_SECONDS = void 0;
|
|
4
|
+
exports.memoryDpopNonceSource = memoryDpopNonceSource;
|
|
5
|
+
exports.hmacDpopNonceSource = hmacDpopNonceSource;
|
|
6
|
+
exports.memoryDpopReplayStore = memoryDpopReplayStore;
|
|
7
|
+
exports.createIntrospector = createIntrospector;
|
|
8
|
+
exports.buildWwwAuthenticate = buildWwwAuthenticate;
|
|
9
|
+
exports.createAccessTokenVerifier = createAccessTokenVerifier;
|
|
10
|
+
exports.verifyAccessToken = verifyAccessToken;
|
|
11
|
+
exports.protectedResourceMetadata = protectedResourceMetadata;
|
|
12
|
+
exports.protectedResourceMetadataPath = protectedResourceMetadataPath;
|
|
13
|
+
const jose_1 = require("jose");
|
|
14
|
+
const jwks_cache_1 = require("./jwks-cache");
|
|
15
|
+
const algs_1 = require("./algs");
|
|
16
|
+
/**
|
|
17
|
+
* Protecting YOUR API — or your own MCP server — with access tokens Atlas
|
|
18
|
+
* issues to OAuth clients (authorization code, device, client credentials,
|
|
19
|
+
* token exchange). Atlas is the authorization server; your API is the
|
|
20
|
+
* resource server. This module:
|
|
21
|
+
* - verifies the access token locally against the instance JWKS (cached;
|
|
22
|
+
* no call to Atlas on the hot path): signature, `iss`, `exp`/`nbf`, that it
|
|
23
|
+
* IS an access token, and that its `aud` names your API (RFC 8707);
|
|
24
|
+
* - enforces required scopes;
|
|
25
|
+
* - enforces sender constraint: a DPoP-bound token (`cnf.jkt`) must arrive
|
|
26
|
+
* with a valid DPoP proof for the same key (RFC 9449), and is never accepted
|
|
27
|
+
* as a plain Bearer token;
|
|
28
|
+
* - answers failures with the RFC 6750 / RFC 9728 `WWW-Authenticate`
|
|
29
|
+
* challenge (`resource_metadata`, `insufficient_scope` + the scopes needed),
|
|
30
|
+
* which is exactly what an MCP client needs to discover how to sign in;
|
|
31
|
+
* - builds the RFC 9728 protected-resource metadata document to serve at
|
|
32
|
+
* `/.well-known/oauth-protected-resource` on your API's host.
|
|
33
|
+
* - accepts OPAQUE access tokens too (an API, client or instance set to the
|
|
34
|
+
* `opaque` format): with `introspection` configured, a token that is not a
|
|
35
|
+
* JWT is validated at Atlas's introspection endpoint (RFC 7662) with your
|
|
36
|
+
* API's own client credentials, and the answer is cached briefly;
|
|
37
|
+
* Framework-agnostic: hand it any request with `method`, `url` and `headers`.
|
|
38
|
+
*/
|
|
39
|
+
/** Clock skew tolerated on `exp`/`nbf` and on DPoP proof `iat`. */
|
|
40
|
+
exports.ACCESS_TOKEN_CLOCK_SKEW_SECONDS = 5;
|
|
41
|
+
/** How old a DPoP proof may be. */
|
|
42
|
+
exports.DPOP_PROOF_MAX_AGE_SECONDS = 300;
|
|
43
|
+
const DPOP_ALGS = ['ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512', 'EdDSA'];
|
|
44
|
+
const DEFAULT_NONCE_WINDOW_SECONDS = 300;
|
|
45
|
+
/**
|
|
46
|
+
* An in-process nonce source: a random nonce per window; the current and the
|
|
47
|
+
* previous window's nonce are accepted. Use it when one process serves the API
|
|
48
|
+
* (or with sticky routing); behind several processes, use
|
|
49
|
+
* {@link hmacDpopNonceSource} with a shared secret.
|
|
50
|
+
*/
|
|
51
|
+
function memoryDpopNonceSource(options = {}) {
|
|
52
|
+
const window = (options.windowSeconds ?? DEFAULT_NONCE_WINDOW_SECONDS) * 1000;
|
|
53
|
+
const now = options.now ?? Date.now;
|
|
54
|
+
const issued = new Map();
|
|
55
|
+
const random = () => {
|
|
56
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
57
|
+
let bin = '';
|
|
58
|
+
for (const b of bytes)
|
|
59
|
+
bin += String.fromCharCode(b);
|
|
60
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
61
|
+
};
|
|
62
|
+
const at = (epoch) => {
|
|
63
|
+
let n = issued.get(epoch);
|
|
64
|
+
if (!n) {
|
|
65
|
+
n = random();
|
|
66
|
+
issued.set(epoch, n);
|
|
67
|
+
for (const e of issued.keys())
|
|
68
|
+
if (e < epoch - 1)
|
|
69
|
+
issued.delete(e);
|
|
70
|
+
}
|
|
71
|
+
return n;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
current: () => at(Math.floor(now() / window)),
|
|
75
|
+
valid: (nonce) => {
|
|
76
|
+
const epoch = Math.floor(now() / window);
|
|
77
|
+
return nonce === at(epoch) || nonce === issued.get(epoch - 1);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A stateless nonce source shared by every process holding the same secret (at
|
|
83
|
+
* least 32 bytes): the nonce for a window is base64url(HMAC-SHA256(secret,
|
|
84
|
+
* "atlas-dpop-nonce:" ‖ uint64-BE(window number))). A nonce is good in the window
|
|
85
|
+
* it was issued in and the next one. The derivation is the same in every Atlas
|
|
86
|
+
* server SDK, so services in different languages sharing the secret agree.
|
|
87
|
+
*/
|
|
88
|
+
function hmacDpopNonceSource(secret, options = {}) {
|
|
89
|
+
const key = typeof secret === 'string' ? new TextEncoder().encode(secret) : secret;
|
|
90
|
+
if (key.length < 32)
|
|
91
|
+
throw new Error('The DPoP nonce secret must be at least 32 bytes.');
|
|
92
|
+
const window = (options.windowSeconds ?? DEFAULT_NONCE_WINDOW_SECONDS) * 1000;
|
|
93
|
+
const now = options.now ?? Date.now;
|
|
94
|
+
const imported = crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
95
|
+
const at = async (epoch) => {
|
|
96
|
+
const prefix = new TextEncoder().encode('atlas-dpop-nonce:');
|
|
97
|
+
const msg = new Uint8Array(prefix.length + 8);
|
|
98
|
+
msg.set(prefix);
|
|
99
|
+
new DataView(msg.buffer).setBigUint64(prefix.length, BigInt(epoch));
|
|
100
|
+
const mac = new Uint8Array(await crypto.subtle.sign('HMAC', await imported, msg));
|
|
101
|
+
let bin = '';
|
|
102
|
+
for (const b of mac)
|
|
103
|
+
bin += String.fromCharCode(b);
|
|
104
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
105
|
+
};
|
|
106
|
+
const epoch = () => Math.floor(now() / window);
|
|
107
|
+
return {
|
|
108
|
+
current: () => at(epoch()),
|
|
109
|
+
valid: async (nonce) => {
|
|
110
|
+
const e = epoch();
|
|
111
|
+
const [a, b] = await Promise.all([at(e), at(e - 1)]);
|
|
112
|
+
return constantTimeEqual(nonce, a) || constantTimeEqual(nonce, b);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function constantTimeEqual(a, b) {
|
|
117
|
+
if (a.length !== b.length)
|
|
118
|
+
return false;
|
|
119
|
+
let diff = 0;
|
|
120
|
+
for (let i = 0; i < a.length; i++)
|
|
121
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
122
|
+
return diff === 0;
|
|
123
|
+
}
|
|
124
|
+
function memoryDpopReplayStore(max = 10_000) {
|
|
125
|
+
const seen = new Map();
|
|
126
|
+
return {
|
|
127
|
+
claim(jti, expiresAt) {
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
if ((seen.get(jti) ?? 0) > now)
|
|
130
|
+
return false;
|
|
131
|
+
seen.set(jti, expiresAt);
|
|
132
|
+
if (seen.size > max) {
|
|
133
|
+
for (const [k, v] of seen)
|
|
134
|
+
if (v <= now)
|
|
135
|
+
seen.delete(k);
|
|
136
|
+
while (seen.size > max)
|
|
137
|
+
seen.delete(seen.keys().next().value);
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* RFC 7662 introspection with a small TTL cache keyed by the token's SHA-256
|
|
145
|
+
* (the token itself is never kept). Returns the claims of an active token, or
|
|
146
|
+
* null for an inactive one; throws when Atlas could not be reached.
|
|
147
|
+
*/
|
|
148
|
+
function createIntrospector(issuer, options, deps = {}) {
|
|
149
|
+
const endpoint = options.endpoint ?? `${issuer.replace(/\/+$/, '')}/oauth2/introspect`;
|
|
150
|
+
const now = deps.now ?? Date.now;
|
|
151
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
152
|
+
const ttl = (options.cacheTtlSeconds ?? 60) * 1000;
|
|
153
|
+
const negativeTtl = (options.negativeCacheTtlSeconds ?? 10) * 1000;
|
|
154
|
+
const max = options.cacheMax ?? 10_000;
|
|
155
|
+
const cache = new Map();
|
|
156
|
+
const basic = `Basic ${btoa(`${encodeURIComponent(options.clientId)}:${encodeURIComponent(options.clientSecret)}`)}`;
|
|
157
|
+
return async (token) => {
|
|
158
|
+
const key = await sha256b64u(token);
|
|
159
|
+
const hit = cache.get(key);
|
|
160
|
+
if (hit && hit.until > now())
|
|
161
|
+
return hit.claims;
|
|
162
|
+
if (hit)
|
|
163
|
+
cache.delete(key);
|
|
164
|
+
const res = await doFetch(endpoint, {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
headers: {
|
|
167
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
168
|
+
accept: 'application/json',
|
|
169
|
+
authorization: basic,
|
|
170
|
+
},
|
|
171
|
+
body: new URLSearchParams({ token, token_type_hint: 'access_token' }).toString(),
|
|
172
|
+
});
|
|
173
|
+
if (!res.ok)
|
|
174
|
+
throw new Error(`Introspection failed with HTTP ${res.status}.`);
|
|
175
|
+
const body = (await res.json());
|
|
176
|
+
const claims = body.active === true && body.token_use !== 'refresh_token' ? body : null;
|
|
177
|
+
const until = claims
|
|
178
|
+
? Math.min(now() + ttl, typeof claims.exp === 'number' ? claims.exp * 1000 : now() + ttl)
|
|
179
|
+
: now() + negativeTtl;
|
|
180
|
+
if (until > now()) {
|
|
181
|
+
cache.set(key, { claims, until });
|
|
182
|
+
if (cache.size > max) {
|
|
183
|
+
for (const [k, v] of cache)
|
|
184
|
+
if (v.until <= now())
|
|
185
|
+
cache.delete(k);
|
|
186
|
+
while (cache.size > max)
|
|
187
|
+
cache.delete(cache.keys().next().value);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return claims;
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function header(req, name) {
|
|
194
|
+
const h = req.headers;
|
|
195
|
+
if (typeof h.get === 'function')
|
|
196
|
+
return h.get(name) ?? undefined;
|
|
197
|
+
const v = h[name] ?? h[name.toLowerCase()];
|
|
198
|
+
return Array.isArray(v) ? v[0] : v;
|
|
199
|
+
}
|
|
200
|
+
const quote = (v) => `"${v.replace(/["\\]/g, '\\$&')}"`;
|
|
201
|
+
/**
|
|
202
|
+
* Build an RFC 6750 / RFC 9449 / RFC 9728 `WWW-Authenticate` challenge.
|
|
203
|
+
* Without an `error`, it is the bare "authentication required" challenge
|
|
204
|
+
* (no token was sent), as RFC 6750 §3.1 asks.
|
|
205
|
+
*/
|
|
206
|
+
function buildWwwAuthenticate(opts) {
|
|
207
|
+
const parts = [];
|
|
208
|
+
if (opts.realm)
|
|
209
|
+
parts.push(`realm=${quote(opts.realm)}`);
|
|
210
|
+
if (opts.error)
|
|
211
|
+
parts.push(`error=${quote(opts.error)}`);
|
|
212
|
+
if (opts.error && opts.description)
|
|
213
|
+
parts.push(`error_description=${quote(opts.description)}`);
|
|
214
|
+
if (opts.scope && opts.scope.length > 0)
|
|
215
|
+
parts.push(`scope=${quote(opts.scope.join(' '))}`);
|
|
216
|
+
if (opts.resourceMetadataUrl)
|
|
217
|
+
parts.push(`resource_metadata=${quote(opts.resourceMetadataUrl)}`);
|
|
218
|
+
if (opts.scheme === 'DPoP' && opts.dpopAlgs)
|
|
219
|
+
parts.push(`algs=${quote(opts.dpopAlgs.join(' '))}`);
|
|
220
|
+
return `${opts.scheme ?? 'Bearer'}${parts.length ? ` ${parts.join(', ')}` : ''}`;
|
|
221
|
+
}
|
|
222
|
+
async function sha256b64u(input) {
|
|
223
|
+
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(input)));
|
|
224
|
+
let bin = '';
|
|
225
|
+
for (const b of digest)
|
|
226
|
+
bin += String.fromCharCode(b);
|
|
227
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
228
|
+
}
|
|
229
|
+
/** Strip query + fragment (RFC 9449 §4.3 `htu` comparison). */
|
|
230
|
+
function htuOf(url) {
|
|
231
|
+
try {
|
|
232
|
+
const u = new URL(url);
|
|
233
|
+
return `${u.protocol}//${u.host}${u.pathname}`;
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* A reusable verifier (one JWKS cache for the life of the process). Call it per
|
|
241
|
+
* request; it never throws for a bad token — it returns the status + challenge.
|
|
242
|
+
*/
|
|
243
|
+
function createAccessTokenVerifier(options) {
|
|
244
|
+
if (!options.issuer)
|
|
245
|
+
throw new Error('createAccessTokenVerifier needs `issuer`.');
|
|
246
|
+
if (options.jwks && options.jwksUrl)
|
|
247
|
+
throw new Error('Pass `jwks` or `jwksUrl`, not both.');
|
|
248
|
+
const issuer = options.issuer.replace(/\/+$/, '');
|
|
249
|
+
const now = () => (options.now ?? Date.now)();
|
|
250
|
+
const jwks = new jwks_cache_1.JwksCache({
|
|
251
|
+
url: options.jwks ? undefined : (options.jwksUrl ?? `${issuer}/.well-known/jwks.json`),
|
|
252
|
+
staticJwks: options.jwks,
|
|
253
|
+
fetchImpl: options.fetchImpl,
|
|
254
|
+
now: options.now,
|
|
255
|
+
});
|
|
256
|
+
const audiences = options.audience === false ? null : typeof options.audience === 'string' ? [options.audience] : [...options.audience];
|
|
257
|
+
const replay = options.dpopReplayStore ?? memoryDpopReplayStore();
|
|
258
|
+
const introspect = options.introspection
|
|
259
|
+
? createIntrospector(issuer, options.introspection, { fetchImpl: options.fetchImpl, now: options.now })
|
|
260
|
+
: null;
|
|
261
|
+
return async (request, extra) => {
|
|
262
|
+
const required = [...(options.requiredScopes ?? []), ...(extra?.requiredScopes ?? [])];
|
|
263
|
+
const scheme = options.requireDpop ? 'DPoP' : 'Bearer';
|
|
264
|
+
const nonce = options.dpopNonces ? await options.dpopNonces.current() : undefined;
|
|
265
|
+
const fail = (status, error, description, challengeScheme = scheme) => ({
|
|
266
|
+
ok: false,
|
|
267
|
+
status,
|
|
268
|
+
error,
|
|
269
|
+
description,
|
|
270
|
+
wwwAuthenticate: buildWwwAuthenticate({
|
|
271
|
+
scheme: challengeScheme,
|
|
272
|
+
realm: options.realm,
|
|
273
|
+
error,
|
|
274
|
+
description,
|
|
275
|
+
scope: error === 'insufficient_scope' || error === null ? required : undefined,
|
|
276
|
+
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
277
|
+
dpopAlgs: DPOP_ALGS,
|
|
278
|
+
}),
|
|
279
|
+
...(nonce ? { dpopNonce: nonce } : {}),
|
|
280
|
+
});
|
|
281
|
+
const authz = header(request, 'authorization');
|
|
282
|
+
if (!authz)
|
|
283
|
+
return fail(401, null, 'Authentication required.');
|
|
284
|
+
const m = /^(Bearer|DPoP)\s+([A-Za-z0-9\-._~+/]+=*)$/i.exec(authz.trim());
|
|
285
|
+
if (!m)
|
|
286
|
+
return fail(400, 'invalid_request', 'Malformed Authorization header.');
|
|
287
|
+
const presentedScheme = m[1].toLowerCase() === 'dpop' ? 'DPoP' : 'Bearer';
|
|
288
|
+
const token = m[2];
|
|
289
|
+
const isJwt = token.split('.').length === 3;
|
|
290
|
+
let claims;
|
|
291
|
+
if (!isJwt || (introspect && options.introspection?.introspectJwts)) {
|
|
292
|
+
// An opaque token (or a JWT the caller wants checked live) is validated by
|
|
293
|
+
// Atlas itself.
|
|
294
|
+
if (!introspect) {
|
|
295
|
+
return fail(401, 'invalid_token', 'The access token is not a JWT; configure `introspection` to accept opaque tokens.');
|
|
296
|
+
}
|
|
297
|
+
let active;
|
|
298
|
+
try {
|
|
299
|
+
active = await introspect(token);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return fail(401, 'invalid_token', 'The access token could not be validated right now.');
|
|
303
|
+
}
|
|
304
|
+
if (!active)
|
|
305
|
+
return fail(401, 'invalid_token', 'The access token is invalid or expired.');
|
|
306
|
+
if (active.iss !== undefined && String(active.iss).replace(/\/+$/, '') !== issuer) {
|
|
307
|
+
return fail(401, 'invalid_token', 'The access token was issued by another authorization server.');
|
|
308
|
+
}
|
|
309
|
+
if (typeof active.exp === 'number' && active.exp * 1000 + exports.ACCESS_TOKEN_CLOCK_SKEW_SECONDS * 1000 <= now()) {
|
|
310
|
+
return fail(401, 'invalid_token', 'The access token is invalid or expired.');
|
|
311
|
+
}
|
|
312
|
+
claims = active;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
const keys = await jwks.get((0, jwks_cache_1.readKid)(token));
|
|
316
|
+
if (!keys || keys.keys.length === 0)
|
|
317
|
+
return fail(401, 'invalid_token', 'No signing keys are available to verify the token.');
|
|
318
|
+
try {
|
|
319
|
+
const { payload } = await (0, jose_1.jwtVerify)(token, (0, jose_1.createLocalJWKSet)(keys), {
|
|
320
|
+
issuer,
|
|
321
|
+
algorithms: algs_1.ATLAS_SIGNING_ALGS,
|
|
322
|
+
clockTolerance: exports.ACCESS_TOKEN_CLOCK_SKEW_SECONDS,
|
|
323
|
+
currentDate: new Date(now()),
|
|
324
|
+
});
|
|
325
|
+
claims = payload;
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return fail(401, 'invalid_token', 'The access token is invalid or expired.');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (claims.token_use !== undefined && claims.token_use !== 'access_token') {
|
|
332
|
+
return fail(401, 'invalid_token', 'The token is not an access token.');
|
|
333
|
+
}
|
|
334
|
+
if (audiences) {
|
|
335
|
+
const aud = claims.aud === undefined ? [] : Array.isArray(claims.aud) ? claims.aud : [claims.aud];
|
|
336
|
+
if (!aud.some((a) => audiences.includes(a))) {
|
|
337
|
+
return fail(401, 'invalid_token', 'The access token was not issued for this resource.');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Sender constraint (RFC 9449). A bound token is only ever a DPoP token.
|
|
341
|
+
const jkt = claims.cnf?.jkt;
|
|
342
|
+
if (jkt || options.requireDpop || presentedScheme === 'DPoP') {
|
|
343
|
+
if (!jkt)
|
|
344
|
+
return fail(401, 'invalid_token', 'This resource requires a DPoP-bound access token.', 'DPoP');
|
|
345
|
+
if (presentedScheme !== 'DPoP') {
|
|
346
|
+
return fail(401, 'invalid_token', 'A DPoP-bound access token must be sent with the DPoP scheme.', 'DPoP');
|
|
347
|
+
}
|
|
348
|
+
const proof = header(request, 'dpop');
|
|
349
|
+
if (!proof)
|
|
350
|
+
return fail(401, 'invalid_dpop_proof', 'A DPoP proof is required.', 'DPoP');
|
|
351
|
+
const proofError = await checkDpopProof(proof, {
|
|
352
|
+
token,
|
|
353
|
+
jkt,
|
|
354
|
+
method: (request.method ?? 'GET').toUpperCase(),
|
|
355
|
+
url: request.url ?? '',
|
|
356
|
+
publicOrigin: options.publicOrigin,
|
|
357
|
+
now: now(),
|
|
358
|
+
replay,
|
|
359
|
+
nonces: options.dpopNonces,
|
|
360
|
+
});
|
|
361
|
+
if (proofError)
|
|
362
|
+
return fail(401, proofError.code, proofError.message, 'DPoP');
|
|
363
|
+
}
|
|
364
|
+
const scopes = (claims.scope ?? '').split(' ').filter(Boolean);
|
|
365
|
+
const granted = new Set([...scopes, ...(claims.permissions ?? [])]);
|
|
366
|
+
const missing = required.filter((s) => !granted.has(s));
|
|
367
|
+
if (missing.length > 0) {
|
|
368
|
+
return fail(403, 'insufficient_scope', `The access token is missing the required scope(s): ${missing.join(' ')}.`);
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
ok: true,
|
|
372
|
+
claims,
|
|
373
|
+
scopes,
|
|
374
|
+
subject: claims.sub,
|
|
375
|
+
clientId: (claims.client_id ?? claims.azp ?? null),
|
|
376
|
+
dpopBound: !!jkt,
|
|
377
|
+
...(nonce ? { dpopNonce: nonce } : {}),
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
async function checkDpopProof(proof, ctx) {
|
|
382
|
+
const refuse = (message) => ({ code: 'invalid_dpop_proof', message });
|
|
383
|
+
let jwk;
|
|
384
|
+
let alg;
|
|
385
|
+
try {
|
|
386
|
+
const h = (0, jose_1.decodeProtectedHeader)(proof);
|
|
387
|
+
if (h.typ !== 'dpop+jwt')
|
|
388
|
+
return refuse('The DPoP proof must have typ dpop+jwt.');
|
|
389
|
+
if (!h.alg || !DPOP_ALGS.includes(h.alg))
|
|
390
|
+
return refuse('The DPoP proof uses an unsupported algorithm.');
|
|
391
|
+
if (!h.jwk || typeof h.jwk !== 'object')
|
|
392
|
+
return refuse('The DPoP proof must carry its public key.');
|
|
393
|
+
jwk = h.jwk;
|
|
394
|
+
if ('d' in jwk || 'k' in jwk)
|
|
395
|
+
return refuse('The DPoP proof key must be a public key.');
|
|
396
|
+
alg = h.alg;
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
return refuse('The DPoP proof is malformed.');
|
|
400
|
+
}
|
|
401
|
+
let payload;
|
|
402
|
+
try {
|
|
403
|
+
const key = await (0, jose_1.importJWK)(jwk, alg);
|
|
404
|
+
({ payload } = await (0, jose_1.jwtVerify)(proof, key, { algorithms: [alg], typ: 'dpop+jwt', currentDate: new Date(ctx.now) }));
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return refuse('The DPoP proof signature is invalid.');
|
|
408
|
+
}
|
|
409
|
+
if ((await (0, jose_1.calculateJwkThumbprint)(jwk, 'sha256')) !== ctx.jkt) {
|
|
410
|
+
return refuse('The DPoP proof key does not match the token binding.');
|
|
411
|
+
}
|
|
412
|
+
if (payload.htm !== ctx.method)
|
|
413
|
+
return refuse('The DPoP proof htm does not match the request method.');
|
|
414
|
+
const absolute = /^https?:\/\//i.test(ctx.url) ? ctx.url : ctx.publicOrigin ? new URL(ctx.url, ctx.publicOrigin).toString() : null;
|
|
415
|
+
const expected = absolute ? htuOf(absolute) : null;
|
|
416
|
+
if (!expected || typeof payload.htu !== 'string' || htuOf(payload.htu) !== expected) {
|
|
417
|
+
return refuse('The DPoP proof htu does not match the request URL.');
|
|
418
|
+
}
|
|
419
|
+
const iat = typeof payload.iat === 'number' ? payload.iat * 1000 : NaN;
|
|
420
|
+
if (!Number.isFinite(iat) ||
|
|
421
|
+
iat > ctx.now + exports.ACCESS_TOKEN_CLOCK_SKEW_SECONDS * 1000 ||
|
|
422
|
+
ctx.now - iat > exports.DPOP_PROOF_MAX_AGE_SECONDS * 1000) {
|
|
423
|
+
return refuse('The DPoP proof is too old or from the future.');
|
|
424
|
+
}
|
|
425
|
+
if (payload.ath !== (await sha256b64u(ctx.token)))
|
|
426
|
+
return refuse('The DPoP proof ath does not match the access token.');
|
|
427
|
+
if (typeof payload.jti !== 'string' || !payload.jti)
|
|
428
|
+
return refuse('The DPoP proof needs a jti.');
|
|
429
|
+
if (ctx.nonces) {
|
|
430
|
+
const nonce = typeof payload.nonce === 'string' ? payload.nonce : '';
|
|
431
|
+
if (!nonce || !(await ctx.nonces.valid(nonce))) {
|
|
432
|
+
return { code: 'use_dpop_nonce', message: 'The DPoP proof must carry the nonce from the DPoP-Nonce header.' };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (!(await ctx.replay.claim(`${ctx.jkt}:${payload.jti}`, iat + exports.DPOP_PROOF_MAX_AGE_SECONDS * 1000))) {
|
|
436
|
+
return refuse('The DPoP proof has already been used.');
|
|
437
|
+
}
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
/** One-shot form of {@link createAccessTokenVerifier} (builds a fresh JWKS cache each call — prefer the factory). */
|
|
441
|
+
function verifyAccessToken(request, options) {
|
|
442
|
+
return createAccessTokenVerifier(options)(request);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* The RFC 9728 protected-resource metadata document for your API. Serve it as
|
|
446
|
+
* JSON at `https://<your api host>/.well-known/oauth-protected-resource` (and,
|
|
447
|
+
* for a resource with a path, at `/.well-known/oauth-protected-resource<path>`),
|
|
448
|
+
* and point `resourceMetadataUrl` at it. Atlas can also serve this document for
|
|
449
|
+
* you when the API is registered with metadata publishing turned on.
|
|
450
|
+
*/
|
|
451
|
+
function protectedResourceMetadata(opts) {
|
|
452
|
+
return {
|
|
453
|
+
resource: opts.resource,
|
|
454
|
+
authorization_servers: [opts.issuer.replace(/\/+$/, '')],
|
|
455
|
+
bearer_methods_supported: ['header'],
|
|
456
|
+
...(opts.scopesSupported ? { scopes_supported: [...opts.scopesSupported] } : {}),
|
|
457
|
+
...(opts.resourceName ? { resource_name: opts.resourceName } : {}),
|
|
458
|
+
...(opts.resourceDocumentation ? { resource_documentation: opts.resourceDocumentation } : {}),
|
|
459
|
+
dpop_signing_alg_values_supported: DPOP_ALGS,
|
|
460
|
+
...(opts.dpopBoundAccessTokensRequired ? { dpop_bound_access_tokens_required: true } : {}),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
/** The RFC 9728 well-known path for a resource identifier (path-inserted form). */
|
|
464
|
+
function protectedResourceMetadataPath(resource) {
|
|
465
|
+
const u = new URL(resource);
|
|
466
|
+
const path = u.pathname === '/' ? '' : u.pathname.replace(/\/+$/, '');
|
|
467
|
+
return `/.well-known/oauth-protected-resource${path}`;
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=oauth-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-resource.js","sourceRoot":"","sources":["../src/oauth-resource.ts"],"names":[],"mappings":"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"}
|
package/dist/oidc.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { type JWTPayload } from 'jose';
|
|
|
20
20
|
* minute so a burst of callbacks cannot become an outbound request flood),
|
|
21
21
|
* the code exchange with the client's authentication method, and the JWKS
|
|
22
22
|
* (the package's rate-limited kid-miss cache).
|
|
23
|
-
* - ID-token verification with the algorithm PINNED to RS256 (so `alg: none`
|
|
23
|
+
* - ID-token verification with the algorithm PINNED to RS256 or ES256 (so `alg: none`
|
|
24
24
|
* and HS* confusion are refused), `iss` exact, `aud` containing the client id
|
|
25
25
|
* (and `azp` equal to it when there are several audiences or an `azp` at all),
|
|
26
26
|
* `nonce` equal to the cookie's, `exp`/`iat` with a small tolerance, and
|
package/dist/oidc.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.resetOidcCaches = resetOidcCaches;
|
|
|
10
10
|
const jose_1 = require("jose");
|
|
11
11
|
const handshake_1 = require("./handshake");
|
|
12
12
|
const jwks_cache_1 = require("./jwks-cache");
|
|
13
|
+
const algs_1 = require("./algs");
|
|
13
14
|
class AtlasOidcError extends Error {
|
|
14
15
|
code;
|
|
15
16
|
/** The OAuth `error` value from the authorization or token endpoint, when there was one. */
|
|
@@ -247,8 +248,9 @@ async function verifyIdToken(idToken, discovery, opts) {
|
|
|
247
248
|
if (!header)
|
|
248
249
|
throw invalid('it is not a JWT');
|
|
249
250
|
// Pinned before any key lookup, so `none` and HS* never get near a key.
|
|
250
|
-
if (header.alg !== '
|
|
251
|
-
throw invalid(`its algorithm is ${String(header.alg)}, not RS256`);
|
|
251
|
+
if (typeof header.alg !== 'string' || !algs_1.ATLAS_SIGNING_ALGS.includes(header.alg)) {
|
|
252
|
+
throw invalid(`its algorithm is ${String(header.alg)}, not RS256 or ES256`);
|
|
253
|
+
}
|
|
252
254
|
const keys = await jwksFor(discovery.jwks_uri, opts).get(typeof header.kid === 'string' ? header.kid : undefined);
|
|
253
255
|
if (!keys || keys.keys.length === 0) {
|
|
254
256
|
throw new AtlasOidcError('discovery_failed', `The issuer's signing keys could not be fetched from ${discovery.jwks_uri}.`);
|
|
@@ -256,7 +258,7 @@ async function verifyIdToken(idToken, discovery, opts) {
|
|
|
256
258
|
let payload;
|
|
257
259
|
try {
|
|
258
260
|
({ payload } = await (0, jose_1.jwtVerify)(idToken, (0, jose_1.createLocalJWKSet)(keys), {
|
|
259
|
-
algorithms:
|
|
261
|
+
algorithms: algs_1.ATLAS_SIGNING_ALGS,
|
|
260
262
|
issuer: discovery.issuer,
|
|
261
263
|
audience: opts.clientId,
|
|
262
264
|
clockTolerance: opts.clockToleranceSec,
|