@dereekb/oauth-resource 14.4.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/LICENSE +21 -0
- package/README.md +185 -0
- package/express/index.d.ts +1 -0
- package/express/index.esm.js +321 -0
- package/express/package.json +29 -0
- package/express/src/index.d.ts +1 -0
- package/express/src/lib/bearer.middleware.d.ts +78 -0
- package/express/src/lib/index.d.ts +2 -0
- package/express/src/lib/well-known.router.d.ts +35 -0
- package/firebase/index.d.ts +1 -0
- package/firebase/index.esm.js +1924 -0
- package/firebase/package.json +27 -0
- package/firebase/src/index.d.ts +1 -0
- package/firebase/src/lib/firestore/firestore.sdk-identity.d.ts +165 -0
- package/firebase/src/lib/firestore/index.d.ts +1 -0
- package/firebase/src/lib/index.d.ts +2 -0
- package/firebase/src/lib/session/firebase-client.config.d.ts +86 -0
- package/firebase/src/lib/session/firebase-user-session.d.ts +223 -0
- package/firebase/src/lib/session/firebase-user-session.pool.d.ts +168 -0
- package/firebase/src/lib/session/firestore-session.cache.d.ts +79 -0
- package/firebase/src/lib/session/firestore-session.client.d.ts +149 -0
- package/firebase/src/lib/session/index.d.ts +5 -0
- package/index.d.ts +1 -0
- package/index.esm.js +1066 -0
- package/package.json +53 -0
- package/src/index.d.ts +1 -0
- package/src/lib/auth/index.d.ts +1 -0
- package/src/lib/auth/oauth.resource.auth.d.ts +55 -0
- package/src/lib/challenge/bearer.challenge.d.ts +73 -0
- package/src/lib/challenge/index.d.ts +1 -0
- package/src/lib/error/index.d.ts +1 -0
- package/src/lib/error/oauth.resource.error.d.ts +76 -0
- package/src/lib/index.d.ts +6 -0
- package/src/lib/issuer/index.d.ts +1 -0
- package/src/lib/issuer/issuer.profile.d.ts +98 -0
- package/src/lib/metadata/index.d.ts +1 -0
- package/src/lib/metadata/protected-resource.metadata.d.ts +64 -0
- package/src/lib/verify/index.d.ts +1 -0
- package/src/lib/verify/verify.bearer.d.ts +95 -0
package/index.esm.js
ADDED
|
@@ -0,0 +1,1066 @@
|
|
|
1
|
+
import { BaseError } from 'make-error';
|
|
2
|
+
import { cachedGetter } from '@dereekb/util';
|
|
3
|
+
import { createRemoteJWKSet, decodeJwt, decodeProtectedHeader, errors, jwtVerify } from 'jose';
|
|
4
|
+
|
|
5
|
+
// MARK: Conversion
|
|
6
|
+
/**
|
|
7
|
+
* Fallback `clientId` used for a verified Firebase ID token, which names no OAuth client.
|
|
8
|
+
*/ var FIREBASE_AUTH_INFO_CLIENT_ID = 'firebase';
|
|
9
|
+
/**
|
|
10
|
+
* Splits a space-delimited OAuth `scope` claim into its entries.
|
|
11
|
+
*
|
|
12
|
+
* @param scope - The raw `scope` claim value, if any.
|
|
13
|
+
* @returns The scope entries, empty when the claim is absent or not a string.
|
|
14
|
+
*/ function scopesFromScopeClaim(scope) {
|
|
15
|
+
return typeof scope === 'string' ? scope.split(' ').filter(function(entry) {
|
|
16
|
+
return entry.length > 0;
|
|
17
|
+
}) : [];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Converts a {@link VerifiedBearer} into the {@link OAuthResourceAuthInfo} attached to the request.
|
|
21
|
+
*
|
|
22
|
+
* A token with no `client_id` claim is not from an OAuth client: a Firebase ID token reports
|
|
23
|
+
* {@link FIREBASE_AUTH_INFO_CLIENT_ID}, and any other issuer falls back to the subject.
|
|
24
|
+
*
|
|
25
|
+
* @param verified - The verified bearer token.
|
|
26
|
+
* @returns The auth info.
|
|
27
|
+
*/ function oauthResourceAuthInfoForVerifiedBearer(verified) {
|
|
28
|
+
var claimClientId = verified.claims['client_id'];
|
|
29
|
+
var fallbackClientId = verified.kind === 'firebase' ? FIREBASE_AUTH_INFO_CLIENT_ID : verified.subject;
|
|
30
|
+
return {
|
|
31
|
+
token: verified.token,
|
|
32
|
+
clientId: typeof claimClientId === 'string' ? claimClientId : fallbackClientId,
|
|
33
|
+
scopes: scopesFromScopeClaim(verified.claims['scope']),
|
|
34
|
+
expiresAt: verified.claims.exp,
|
|
35
|
+
extra: {
|
|
36
|
+
sub: verified.subject,
|
|
37
|
+
iss: verified.issuer,
|
|
38
|
+
kind: verified.kind
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// MARK: Challenge
|
|
44
|
+
/**
|
|
45
|
+
* Builds the `WWW-Authenticate: Bearer ...` challenge string emitted alongside a 401 / 403 on an
|
|
46
|
+
* OAuth-protected route.
|
|
47
|
+
*
|
|
48
|
+
* Per RFC 6750 §3 / RFC 7235, auth-params are comma-separated. Parameter order is not significant
|
|
49
|
+
* to a client; this emits `realm`, `resource_metadata`, `error`, `error_description`, `scope`.
|
|
50
|
+
*
|
|
51
|
+
* @param config - The error token plus the optional realm / metadata / description / scope params.
|
|
52
|
+
* @returns The header value, e.g. `Bearer resource_metadata="…", error="invalid_token"`.
|
|
53
|
+
*/ function buildBearerChallenge(config) {
|
|
54
|
+
var params = [];
|
|
55
|
+
if (config.realm) {
|
|
56
|
+
params.push('realm="'.concat(config.realm, '"'));
|
|
57
|
+
}
|
|
58
|
+
if (config.resourceMetadataUrl) {
|
|
59
|
+
params.push('resource_metadata="'.concat(config.resourceMetadataUrl, '"'));
|
|
60
|
+
}
|
|
61
|
+
params.push('error="'.concat(config.error, '"'));
|
|
62
|
+
if (config.errorDescription) {
|
|
63
|
+
params.push('error_description="'.concat(config.errorDescription, '"'));
|
|
64
|
+
}
|
|
65
|
+
if (config.scope) {
|
|
66
|
+
params.push('scope="'.concat(config.scope, '"'));
|
|
67
|
+
}
|
|
68
|
+
return "Bearer ".concat(params.join(', '));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Selects the RFC 6750 §3 `error` token for a failure: `insufficient_scope` for a policy (403)
|
|
72
|
+
* failure, `invalid_token` when a token was presented but failed, and `invalid_request` when the
|
|
73
|
+
* request carried no token at all.
|
|
74
|
+
*
|
|
75
|
+
* @param config - The failure code and whether a token was presented.
|
|
76
|
+
* @returns The RFC 6750 error token.
|
|
77
|
+
*/ function bearerChallengeErrorForCode(config) {
|
|
78
|
+
var result;
|
|
79
|
+
if (config.code === 'forbidden') {
|
|
80
|
+
result = 'insufficient_scope';
|
|
81
|
+
} else if (config.hadToken) {
|
|
82
|
+
result = 'invalid_token';
|
|
83
|
+
} else {
|
|
84
|
+
result = 'invalid_request';
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
// MARK: Header
|
|
89
|
+
/**
|
|
90
|
+
* The `Authorization` header scheme prefix a bearer token is presented with.
|
|
91
|
+
*/ var BEARER_AUTHORIZATION_PREFIX = 'Bearer ';
|
|
92
|
+
/**
|
|
93
|
+
* Reads the raw bearer token out of an `Authorization` header value.
|
|
94
|
+
*
|
|
95
|
+
* @param header - The raw `Authorization` header value, if any.
|
|
96
|
+
* @returns The token, or `undefined` when the header is absent, uses another scheme, or is empty.
|
|
97
|
+
*/ function readBearerToken(header) {
|
|
98
|
+
var token;
|
|
99
|
+
if (header === null || header === void 0 ? void 0 : header.startsWith(BEARER_AUTHORIZATION_PREFIX)) {
|
|
100
|
+
var raw = header.slice(BEARER_AUTHORIZATION_PREFIX.length).trim();
|
|
101
|
+
token = raw.length > 0 ? raw : undefined;
|
|
102
|
+
}
|
|
103
|
+
return token;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function _assert_this_initialized(self) {
|
|
107
|
+
if (self === void 0) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
108
|
+
return self;
|
|
109
|
+
}
|
|
110
|
+
function _call_super(_this, derived, args) {
|
|
111
|
+
derived = _get_prototype_of(derived);
|
|
112
|
+
return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
|
|
113
|
+
}
|
|
114
|
+
function _class_call_check(instance, Constructor) {
|
|
115
|
+
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
|
|
116
|
+
}
|
|
117
|
+
function _defineProperties(target, props) {
|
|
118
|
+
for(var i = 0; i < props.length; i++){
|
|
119
|
+
var descriptor = props[i];
|
|
120
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
121
|
+
descriptor.configurable = true;
|
|
122
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
123
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
127
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
128
|
+
return Constructor;
|
|
129
|
+
}
|
|
130
|
+
function _define_property$1(obj, key, value) {
|
|
131
|
+
if (key in obj) {
|
|
132
|
+
Object.defineProperty(obj, key, {
|
|
133
|
+
value: value,
|
|
134
|
+
enumerable: true,
|
|
135
|
+
configurable: true,
|
|
136
|
+
writable: true
|
|
137
|
+
});
|
|
138
|
+
} else obj[key] = value;
|
|
139
|
+
return obj;
|
|
140
|
+
}
|
|
141
|
+
function _get_prototype_of(o) {
|
|
142
|
+
_get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
|
|
143
|
+
return o.__proto__ || Object.getPrototypeOf(o);
|
|
144
|
+
};
|
|
145
|
+
return _get_prototype_of(o);
|
|
146
|
+
}
|
|
147
|
+
function _inherits(subClass, superClass) {
|
|
148
|
+
if (typeof superClass !== "function" && superClass !== null) {
|
|
149
|
+
throw new TypeError("Super expression must either be null or a function");
|
|
150
|
+
}
|
|
151
|
+
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
152
|
+
constructor: {
|
|
153
|
+
value: subClass,
|
|
154
|
+
writable: true,
|
|
155
|
+
configurable: true
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
if (superClass) _set_prototype_of(subClass, superClass);
|
|
159
|
+
}
|
|
160
|
+
function _instanceof$1(left, right) {
|
|
161
|
+
"@swc/helpers - instanceof";
|
|
162
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
163
|
+
return !!right[Symbol.hasInstance](left);
|
|
164
|
+
} else return left instanceof right;
|
|
165
|
+
}
|
|
166
|
+
function _is_native_reflect_construct() {
|
|
167
|
+
try {
|
|
168
|
+
var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
|
|
169
|
+
} catch (_) {}
|
|
170
|
+
return (_is_native_reflect_construct = function() {
|
|
171
|
+
return !!result;
|
|
172
|
+
})();
|
|
173
|
+
}
|
|
174
|
+
function _object_spread$1(target) {
|
|
175
|
+
for(var i = 1; i < arguments.length; i++){
|
|
176
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
177
|
+
var ownKeys = Object.keys(source);
|
|
178
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
179
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
180
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
ownKeys.forEach(function(key) {
|
|
184
|
+
_define_property$1(target, key, source[key]);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return target;
|
|
188
|
+
}
|
|
189
|
+
function _possible_constructor_return(self, call) {
|
|
190
|
+
if (call && (_type_of(call) === "object" || typeof call === "function")) return call;
|
|
191
|
+
return _assert_this_initialized(self);
|
|
192
|
+
}
|
|
193
|
+
function _set_prototype_of(o, p) {
|
|
194
|
+
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
|
|
195
|
+
o.__proto__ = p;
|
|
196
|
+
return o;
|
|
197
|
+
};
|
|
198
|
+
return _set_prototype_of(o, p);
|
|
199
|
+
}
|
|
200
|
+
function _type_of(obj) {
|
|
201
|
+
"@swc/helpers - typeof";
|
|
202
|
+
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* HTTP status paired with each {@link OAuthResourceErrorCode}.
|
|
206
|
+
*/ var OAUTH_RESOURCE_ERROR_STATUS_CODES = {
|
|
207
|
+
unauthorized: 401,
|
|
208
|
+
forbidden: 403
|
|
209
|
+
};
|
|
210
|
+
// MARK: Error
|
|
211
|
+
/**
|
|
212
|
+
* Error raised when a bearer token fails verification or a policy gate.
|
|
213
|
+
*
|
|
214
|
+
* Consumers that already have their own API error type do not have to catch and re-wrap this one:
|
|
215
|
+
* pass an {@link OAuthResourceErrorFactory} on the verification options and the verifier throws
|
|
216
|
+
* that type instead.
|
|
217
|
+
*/ var OAuthResourceError = /*#__PURE__*/ function(BaseError) {
|
|
218
|
+
_inherits(OAuthResourceError, BaseError);
|
|
219
|
+
function OAuthResourceError(input) {
|
|
220
|
+
_class_call_check(this, OAuthResourceError);
|
|
221
|
+
var _this;
|
|
222
|
+
var _input_status;
|
|
223
|
+
_this = _call_super(this, OAuthResourceError, [
|
|
224
|
+
input.message
|
|
225
|
+
]), _define_property$1(_this, "code", void 0), _define_property$1(_this, "status", void 0), _define_property$1(_this, "details", void 0);
|
|
226
|
+
_this.code = input.code;
|
|
227
|
+
_this.status = (_input_status = input.status) !== null && _input_status !== void 0 ? _input_status : OAUTH_RESOURCE_ERROR_STATUS_CODES[input.code];
|
|
228
|
+
if (input.details != null) {
|
|
229
|
+
_this.details = input.details;
|
|
230
|
+
}
|
|
231
|
+
return _this;
|
|
232
|
+
}
|
|
233
|
+
_create_class(OAuthResourceError, [
|
|
234
|
+
{
|
|
235
|
+
/**
|
|
236
|
+
* Builds the default JSON error body for this error.
|
|
237
|
+
*
|
|
238
|
+
* @returns The error envelope.
|
|
239
|
+
*/ key: "toEnvelope",
|
|
240
|
+
value: function toEnvelope() {
|
|
241
|
+
return {
|
|
242
|
+
error: _object_spread$1({
|
|
243
|
+
code: this.code,
|
|
244
|
+
message: this.message
|
|
245
|
+
}, this.details == null ? {} : {
|
|
246
|
+
details: this.details
|
|
247
|
+
})
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
]);
|
|
252
|
+
return OAuthResourceError;
|
|
253
|
+
}(BaseError);
|
|
254
|
+
/**
|
|
255
|
+
* Default {@link OAuthResourceErrorFactory}, producing an {@link OAuthResourceError}.
|
|
256
|
+
*
|
|
257
|
+
* @param input - The code, message, status, and details of the failure.
|
|
258
|
+
* @returns The error to throw.
|
|
259
|
+
*/ var defaultOAuthResourceErrorFactory = function defaultOAuthResourceErrorFactory(input) {
|
|
260
|
+
return new OAuthResourceError(input);
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Returns true when the input is an {@link OAuthResourceError}.
|
|
264
|
+
*
|
|
265
|
+
* @param error - The value to test.
|
|
266
|
+
* @returns Whether the value is an {@link OAuthResourceError}.
|
|
267
|
+
*/ function isOAuthResourceError(error) {
|
|
268
|
+
return _instanceof$1(error, OAuthResourceError);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
|
|
272
|
+
try {
|
|
273
|
+
var info = gen[key](arg);
|
|
274
|
+
var value = info.value;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
reject(error);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (info.done) resolve(value);
|
|
280
|
+
else Promise.resolve(value).then(_next, _throw);
|
|
281
|
+
}
|
|
282
|
+
function _async_to_generator$1(fn) {
|
|
283
|
+
return function() {
|
|
284
|
+
var self = this, args = arguments;
|
|
285
|
+
return new Promise(function(resolve, reject) {
|
|
286
|
+
var gen = fn.apply(self, args);
|
|
287
|
+
function _next(value) {
|
|
288
|
+
asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
|
|
289
|
+
}
|
|
290
|
+
function _throw(err) {
|
|
291
|
+
asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
|
|
292
|
+
}
|
|
293
|
+
_next(undefined);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function _ts_generator$1(thisArg, body) {
|
|
298
|
+
var f, y, t, _ = {
|
|
299
|
+
label: 0,
|
|
300
|
+
sent: function() {
|
|
301
|
+
if (t[0] & 1) throw t[1];
|
|
302
|
+
return t[1];
|
|
303
|
+
},
|
|
304
|
+
trys: [],
|
|
305
|
+
ops: []
|
|
306
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
307
|
+
return d(g, "next", {
|
|
308
|
+
value: verb(0)
|
|
309
|
+
}), d(g, "throw", {
|
|
310
|
+
value: verb(1)
|
|
311
|
+
}), d(g, "return", {
|
|
312
|
+
value: verb(2)
|
|
313
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
314
|
+
value: function() {
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
}), g;
|
|
318
|
+
function verb(n) {
|
|
319
|
+
return function(v) {
|
|
320
|
+
return step([
|
|
321
|
+
n,
|
|
322
|
+
v
|
|
323
|
+
]);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function step(op) {
|
|
327
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
328
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
329
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
330
|
+
if (y = 0, t) op = [
|
|
331
|
+
op[0] & 2,
|
|
332
|
+
t.value
|
|
333
|
+
];
|
|
334
|
+
switch(op[0]){
|
|
335
|
+
case 0:
|
|
336
|
+
case 1:
|
|
337
|
+
t = op;
|
|
338
|
+
break;
|
|
339
|
+
case 4:
|
|
340
|
+
_.label++;
|
|
341
|
+
return {
|
|
342
|
+
value: op[1],
|
|
343
|
+
done: false
|
|
344
|
+
};
|
|
345
|
+
case 5:
|
|
346
|
+
_.label++;
|
|
347
|
+
y = op[1];
|
|
348
|
+
op = [
|
|
349
|
+
0
|
|
350
|
+
];
|
|
351
|
+
continue;
|
|
352
|
+
case 7:
|
|
353
|
+
op = _.ops.pop();
|
|
354
|
+
_.trys.pop();
|
|
355
|
+
continue;
|
|
356
|
+
default:
|
|
357
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
358
|
+
_ = 0;
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
362
|
+
_.label = op[1];
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
366
|
+
_.label = t[1];
|
|
367
|
+
t = op;
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
if (t && _.label < t[2]) {
|
|
371
|
+
_.label = t[2];
|
|
372
|
+
_.ops.push(op);
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
if (t[2]) _.ops.pop();
|
|
376
|
+
_.trys.pop();
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
op = body.call(thisArg, _);
|
|
380
|
+
} catch (e) {
|
|
381
|
+
op = [
|
|
382
|
+
6,
|
|
383
|
+
e
|
|
384
|
+
];
|
|
385
|
+
y = 0;
|
|
386
|
+
} finally{
|
|
387
|
+
f = t = 0;
|
|
388
|
+
}
|
|
389
|
+
if (op[0] & 5) throw op[1];
|
|
390
|
+
return {
|
|
391
|
+
value: op[0] ? op[1] : void 0,
|
|
392
|
+
done: true
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// MARK: Constants
|
|
397
|
+
/**
|
|
398
|
+
* Google's public JWKS for Firebase ID tokens (the `securetoken` signer).
|
|
399
|
+
*/ var FIREBASE_SECURETOKEN_JWKS_URL = 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com';
|
|
400
|
+
/**
|
|
401
|
+
* Path appended to an issuer to read its OpenID Connect discovery document.
|
|
402
|
+
*/ var OPENID_CONFIGURATION_PATH = '/.well-known/openid-configuration';
|
|
403
|
+
/**
|
|
404
|
+
* Builds the `iss` value Firebase stamps on a project's ID tokens.
|
|
405
|
+
*
|
|
406
|
+
* @param projectId - The Firebase project id.
|
|
407
|
+
* @returns The issuer URL.
|
|
408
|
+
*/ function firebaseIssuerForProject(projectId) {
|
|
409
|
+
return "https://securetoken.google.com/".concat(projectId);
|
|
410
|
+
}
|
|
411
|
+
// MARK: Profiles
|
|
412
|
+
/**
|
|
413
|
+
* Builds the issuer → profile map the bearer verifier dispatches on: one
|
|
414
|
+
* Firebase profile per trusted project id (sharing Google's JWKS) and one
|
|
415
|
+
* OIDC profile per trusted issuer (JWKS discovered from
|
|
416
|
+
* `{iss}/.well-known/openid-configuration`, falling back to `{iss}/jwks`).
|
|
417
|
+
*
|
|
418
|
+
* @param config - The trusted project ids / issuers / audiences + optional fetch.
|
|
419
|
+
* @returns Profiles keyed by their `iss` value.
|
|
420
|
+
*/ function buildIssuerProfiles(config) {
|
|
421
|
+
var _config_fetch, _config_audiences, _config_firebaseProjectIds, _config_oidcIssuers;
|
|
422
|
+
var fetchFn = (_config_fetch = config.fetch) !== null && _config_fetch !== void 0 ? _config_fetch : globalThis.fetch.bind(globalThis);
|
|
423
|
+
var audiences = (_config_audiences = config.audiences) !== null && _config_audiences !== void 0 ? _config_audiences : [];
|
|
424
|
+
var profiles = new Map();
|
|
425
|
+
// jose caches the key set and refetches on an unknown `kid` (30 s cooldown). Built on first use
|
|
426
|
+
// rather than at map-construction time, so a bad URL is a per-request 401 and not a boot failure.
|
|
427
|
+
var firebaseKeys = cachedGetter(function() {
|
|
428
|
+
var _config_firebaseJwksUrl;
|
|
429
|
+
return createRemoteJWKSet(new URL((_config_firebaseJwksUrl = config.firebaseJwksUrl) !== null && _config_firebaseJwksUrl !== void 0 ? _config_firebaseJwksUrl : FIREBASE_SECURETOKEN_JWKS_URL));
|
|
430
|
+
});
|
|
431
|
+
((_config_firebaseProjectIds = config.firebaseProjectIds) !== null && _config_firebaseProjectIds !== void 0 ? _config_firebaseProjectIds : []).forEach(function(projectId) {
|
|
432
|
+
var issuer = firebaseIssuerForProject(projectId);
|
|
433
|
+
profiles.set(issuer, {
|
|
434
|
+
kind: 'firebase',
|
|
435
|
+
issuer: issuer,
|
|
436
|
+
audiences: [
|
|
437
|
+
projectId
|
|
438
|
+
],
|
|
439
|
+
getKey: function getKey() {
|
|
440
|
+
return _async_to_generator$1(function() {
|
|
441
|
+
return _ts_generator$1(this, function(_state) {
|
|
442
|
+
return [
|
|
443
|
+
2,
|
|
444
|
+
firebaseKeys()
|
|
445
|
+
];
|
|
446
|
+
});
|
|
447
|
+
})();
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
((_config_oidcIssuers = config.oidcIssuers) !== null && _config_oidcIssuers !== void 0 ? _config_oidcIssuers : []).forEach(function(input) {
|
|
452
|
+
var _entry_getKey, _entry_audiences;
|
|
453
|
+
var entry = typeof input === 'string' ? {
|
|
454
|
+
issuer: input
|
|
455
|
+
} : input;
|
|
456
|
+
var issuer = entry.issuer;
|
|
457
|
+
var getKey = (_entry_getKey = entry.getKey) !== null && _entry_getKey !== void 0 ? _entry_getKey : memoizeSuccess(function() {
|
|
458
|
+
return discoverOidcJwks(issuer, fetchFn);
|
|
459
|
+
});
|
|
460
|
+
profiles.set(issuer, {
|
|
461
|
+
kind: 'oidc',
|
|
462
|
+
issuer: issuer,
|
|
463
|
+
audiences: (_entry_audiences = entry.audiences) !== null && _entry_audiences !== void 0 ? _entry_audiences : audiences,
|
|
464
|
+
getKey: getKey
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
return profiles;
|
|
468
|
+
}
|
|
469
|
+
function discoverOidcJwks(issuer, fetchFn) {
|
|
470
|
+
return _async_to_generator$1(function() {
|
|
471
|
+
var jwksUri, response, document;
|
|
472
|
+
return _ts_generator$1(this, function(_state) {
|
|
473
|
+
switch(_state.label){
|
|
474
|
+
case 0:
|
|
475
|
+
jwksUri = "".concat(issuer, "/jwks");
|
|
476
|
+
_state.label = 1;
|
|
477
|
+
case 1:
|
|
478
|
+
_state.trys.push([
|
|
479
|
+
1,
|
|
480
|
+
5,
|
|
481
|
+
,
|
|
482
|
+
6
|
|
483
|
+
]);
|
|
484
|
+
return [
|
|
485
|
+
4,
|
|
486
|
+
fetchFn("".concat(issuer).concat(OPENID_CONFIGURATION_PATH))
|
|
487
|
+
];
|
|
488
|
+
case 2:
|
|
489
|
+
response = _state.sent();
|
|
490
|
+
if (!response.ok) return [
|
|
491
|
+
3,
|
|
492
|
+
4
|
|
493
|
+
];
|
|
494
|
+
return [
|
|
495
|
+
4,
|
|
496
|
+
response.json()
|
|
497
|
+
];
|
|
498
|
+
case 3:
|
|
499
|
+
document = _state.sent();
|
|
500
|
+
if (typeof document.jwks_uri === 'string' && document.jwks_uri.length > 0) {
|
|
501
|
+
jwksUri = document.jwks_uri;
|
|
502
|
+
}
|
|
503
|
+
_state.label = 4;
|
|
504
|
+
case 4:
|
|
505
|
+
return [
|
|
506
|
+
3,
|
|
507
|
+
6
|
|
508
|
+
];
|
|
509
|
+
case 5:
|
|
510
|
+
_state.sent();
|
|
511
|
+
return [
|
|
512
|
+
3,
|
|
513
|
+
6
|
|
514
|
+
];
|
|
515
|
+
case 6:
|
|
516
|
+
return [
|
|
517
|
+
2,
|
|
518
|
+
createRemoteJWKSet(new URL(jwksUri))
|
|
519
|
+
];
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
})();
|
|
523
|
+
}
|
|
524
|
+
// Caches the resolved value only once it resolved — a rejected attempt is
|
|
525
|
+
// retried on the next call, so a discovery outage never latches.
|
|
526
|
+
function memoizeSuccess(load) {
|
|
527
|
+
var cached;
|
|
528
|
+
return function() {
|
|
529
|
+
var result = cached;
|
|
530
|
+
if (result == null) {
|
|
531
|
+
result = load().catch(function(error) {
|
|
532
|
+
cached = undefined;
|
|
533
|
+
throw error;
|
|
534
|
+
});
|
|
535
|
+
cached = result;
|
|
536
|
+
}
|
|
537
|
+
return result;
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function _array_like_to_array$1(arr, len) {
|
|
542
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
543
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
544
|
+
return arr2;
|
|
545
|
+
}
|
|
546
|
+
function _array_without_holes$1(arr) {
|
|
547
|
+
if (Array.isArray(arr)) return _array_like_to_array$1(arr);
|
|
548
|
+
}
|
|
549
|
+
function _define_property(obj, key, value) {
|
|
550
|
+
if (key in obj) {
|
|
551
|
+
Object.defineProperty(obj, key, {
|
|
552
|
+
value: value,
|
|
553
|
+
enumerable: true,
|
|
554
|
+
configurable: true,
|
|
555
|
+
writable: true
|
|
556
|
+
});
|
|
557
|
+
} else obj[key] = value;
|
|
558
|
+
return obj;
|
|
559
|
+
}
|
|
560
|
+
function _iterable_to_array$1(iter) {
|
|
561
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
562
|
+
return Array.from(iter);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function _non_iterable_spread$1() {
|
|
566
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
567
|
+
}
|
|
568
|
+
function _object_spread(target) {
|
|
569
|
+
for(var i = 1; i < arguments.length; i++){
|
|
570
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
571
|
+
var ownKeys = Object.keys(source);
|
|
572
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
573
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
574
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
ownKeys.forEach(function(key) {
|
|
578
|
+
_define_property(target, key, source[key]);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
return target;
|
|
582
|
+
}
|
|
583
|
+
function _to_consumable_array$1(arr) {
|
|
584
|
+
return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
|
|
585
|
+
}
|
|
586
|
+
function _unsupported_iterable_to_array$1(o, minLen) {
|
|
587
|
+
if (!o) return;
|
|
588
|
+
if (typeof o === "string") return _array_like_to_array$1(o, minLen);
|
|
589
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
590
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
591
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
592
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
|
|
593
|
+
}
|
|
594
|
+
// MARK: Constants
|
|
595
|
+
/**
|
|
596
|
+
* RFC 9728 §3 well-known path for OAuth 2.0 protected-resource metadata.
|
|
597
|
+
*/ var OAUTH_PROTECTED_RESOURCE_PATH = '/.well-known/oauth-protected-resource';
|
|
598
|
+
/**
|
|
599
|
+
* Builds the RFC 9728 §3.1 path-suffixed well-known path for a resource — the form MCP clients
|
|
600
|
+
* try first (e.g. `/.well-known/oauth-protected-resource/mcp` for a resource served at `/mcp`).
|
|
601
|
+
*
|
|
602
|
+
* @param resourcePath - The resource's path on the origin, with or without a leading slash.
|
|
603
|
+
* @returns The path-suffixed well-known path.
|
|
604
|
+
*/ function oauthProtectedResourcePathForResource(resourcePath) {
|
|
605
|
+
var suffix = resourcePath.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
606
|
+
return suffix.length > 0 ? "".concat(OAUTH_PROTECTED_RESOURCE_PATH, "/").concat(suffix) : OAUTH_PROTECTED_RESOURCE_PATH;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Builds the RFC 9728 protected-resource metadata document.
|
|
610
|
+
*
|
|
611
|
+
* Hand-rolled deliberately: the MCP SDK's builder also wants the authorization-server metadata
|
|
612
|
+
* document, which a resource server never hosts — it points at one instead.
|
|
613
|
+
*
|
|
614
|
+
* @param config - The resource identifier, its authorization servers, and the advertised scopes.
|
|
615
|
+
* @returns The metadata document.
|
|
616
|
+
*/ function buildProtectedResourceMetadata(config) {
|
|
617
|
+
var _config_scopesSupported, _config_bearerMethodsSupported;
|
|
618
|
+
return _object_spread({
|
|
619
|
+
resource: config.resource,
|
|
620
|
+
authorization_servers: _to_consumable_array$1(config.authorizationServers),
|
|
621
|
+
scopes_supported: _to_consumable_array$1((_config_scopesSupported = config.scopesSupported) !== null && _config_scopesSupported !== void 0 ? _config_scopesSupported : []),
|
|
622
|
+
bearer_methods_supported: _to_consumable_array$1((_config_bearerMethodsSupported = config.bearerMethodsSupported) !== null && _config_bearerMethodsSupported !== void 0 ? _config_bearerMethodsSupported : [
|
|
623
|
+
'header'
|
|
624
|
+
])
|
|
625
|
+
}, config.resourceName == null ? {} : {
|
|
626
|
+
resource_name: config.resourceName
|
|
627
|
+
}, config.resourceDocumentation == null ? {} : {
|
|
628
|
+
resource_documentation: config.resourceDocumentation
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function _array_like_to_array(arr, len) {
|
|
633
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
634
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
635
|
+
return arr2;
|
|
636
|
+
}
|
|
637
|
+
function _array_without_holes(arr) {
|
|
638
|
+
if (Array.isArray(arr)) return _array_like_to_array(arr);
|
|
639
|
+
}
|
|
640
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
641
|
+
try {
|
|
642
|
+
var info = gen[key](arg);
|
|
643
|
+
var value = info.value;
|
|
644
|
+
} catch (error) {
|
|
645
|
+
reject(error);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (info.done) resolve(value);
|
|
649
|
+
else Promise.resolve(value).then(_next, _throw);
|
|
650
|
+
}
|
|
651
|
+
function _async_to_generator(fn) {
|
|
652
|
+
return function() {
|
|
653
|
+
var self = this, args = arguments;
|
|
654
|
+
return new Promise(function(resolve, reject) {
|
|
655
|
+
var gen = fn.apply(self, args);
|
|
656
|
+
function _next(value) {
|
|
657
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
658
|
+
}
|
|
659
|
+
function _throw(err) {
|
|
660
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
661
|
+
}
|
|
662
|
+
_next(undefined);
|
|
663
|
+
});
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function _instanceof(left, right) {
|
|
667
|
+
"@swc/helpers - instanceof";
|
|
668
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
669
|
+
return !!right[Symbol.hasInstance](left);
|
|
670
|
+
} else return left instanceof right;
|
|
671
|
+
}
|
|
672
|
+
function _iterable_to_array(iter) {
|
|
673
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
674
|
+
return Array.from(iter);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function _non_iterable_spread() {
|
|
678
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
679
|
+
}
|
|
680
|
+
function _to_consumable_array(arr) {
|
|
681
|
+
return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
|
|
682
|
+
}
|
|
683
|
+
function _ts_generator(thisArg, body) {
|
|
684
|
+
var f, y, t, _ = {
|
|
685
|
+
label: 0,
|
|
686
|
+
sent: function() {
|
|
687
|
+
if (t[0] & 1) throw t[1];
|
|
688
|
+
return t[1];
|
|
689
|
+
},
|
|
690
|
+
trys: [],
|
|
691
|
+
ops: []
|
|
692
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
693
|
+
return d(g, "next", {
|
|
694
|
+
value: verb(0)
|
|
695
|
+
}), d(g, "throw", {
|
|
696
|
+
value: verb(1)
|
|
697
|
+
}), d(g, "return", {
|
|
698
|
+
value: verb(2)
|
|
699
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
700
|
+
value: function() {
|
|
701
|
+
return this;
|
|
702
|
+
}
|
|
703
|
+
}), g;
|
|
704
|
+
function verb(n) {
|
|
705
|
+
return function(v) {
|
|
706
|
+
return step([
|
|
707
|
+
n,
|
|
708
|
+
v
|
|
709
|
+
]);
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function step(op) {
|
|
713
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
714
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
715
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
716
|
+
if (y = 0, t) op = [
|
|
717
|
+
op[0] & 2,
|
|
718
|
+
t.value
|
|
719
|
+
];
|
|
720
|
+
switch(op[0]){
|
|
721
|
+
case 0:
|
|
722
|
+
case 1:
|
|
723
|
+
t = op;
|
|
724
|
+
break;
|
|
725
|
+
case 4:
|
|
726
|
+
_.label++;
|
|
727
|
+
return {
|
|
728
|
+
value: op[1],
|
|
729
|
+
done: false
|
|
730
|
+
};
|
|
731
|
+
case 5:
|
|
732
|
+
_.label++;
|
|
733
|
+
y = op[1];
|
|
734
|
+
op = [
|
|
735
|
+
0
|
|
736
|
+
];
|
|
737
|
+
continue;
|
|
738
|
+
case 7:
|
|
739
|
+
op = _.ops.pop();
|
|
740
|
+
_.trys.pop();
|
|
741
|
+
continue;
|
|
742
|
+
default:
|
|
743
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
744
|
+
_ = 0;
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
748
|
+
_.label = op[1];
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
752
|
+
_.label = t[1];
|
|
753
|
+
t = op;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
if (t && _.label < t[2]) {
|
|
757
|
+
_.label = t[2];
|
|
758
|
+
_.ops.push(op);
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
if (t[2]) _.ops.pop();
|
|
762
|
+
_.trys.pop();
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
op = body.call(thisArg, _);
|
|
766
|
+
} catch (e) {
|
|
767
|
+
op = [
|
|
768
|
+
6,
|
|
769
|
+
e
|
|
770
|
+
];
|
|
771
|
+
y = 0;
|
|
772
|
+
} finally{
|
|
773
|
+
f = t = 0;
|
|
774
|
+
}
|
|
775
|
+
if (op[0] & 5) throw op[1];
|
|
776
|
+
return {
|
|
777
|
+
value: op[0] ? op[1] : void 0,
|
|
778
|
+
done: true
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function _unsupported_iterable_to_array(o, minLen) {
|
|
783
|
+
if (!o) return;
|
|
784
|
+
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
785
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
786
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
787
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
788
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
789
|
+
}
|
|
790
|
+
// MARK: Constants
|
|
791
|
+
/**
|
|
792
|
+
* Leeway applied to `exp` / `nbf` / `iat` / `auth_time`.
|
|
793
|
+
*/ var BEARER_CLOCK_TOLERANCE_SECONDS = 60;
|
|
794
|
+
/**
|
|
795
|
+
* The signing algorithms accepted by default (Firebase and oidc-provider both sign RS256).
|
|
796
|
+
*/ var BEARER_ALGORITHMS = [
|
|
797
|
+
'RS256'
|
|
798
|
+
];
|
|
799
|
+
/**
|
|
800
|
+
* Issuer kinds the claim gates apply to by default.
|
|
801
|
+
*/ var DEFAULT_BEARER_CLAIM_GATE_KINDS = [
|
|
802
|
+
'firebase'
|
|
803
|
+
];
|
|
804
|
+
// MARK: Verify
|
|
805
|
+
/**
|
|
806
|
+
* Verifies a bearer JWT against the trusted issuer profiles: the `iss`
|
|
807
|
+
* claim selects the profile, the profile's JWKS verifies the RS256
|
|
808
|
+
* signature, and jose enforces `iss` / `aud` / `exp` / `nbf` / `iat` with a
|
|
809
|
+
* 60 s tolerance. Firebase tokens additionally get the `auth_time` sanity
|
|
810
|
+
* check and the optional claim gates. Under the Firebase emulator an
|
|
811
|
+
* unsigned (`alg: none`) token is accepted after the same claim checks —
|
|
812
|
+
* the emulator never signs, and the flag is never set in production.
|
|
813
|
+
*
|
|
814
|
+
* Scopes are deliberately NOT enforced here: a resource server's scope policy is per-route, so it
|
|
815
|
+
* belongs to the caller (see the Express adapter's `requiredScopes`).
|
|
816
|
+
*
|
|
817
|
+
* @param token - The raw bearer token.
|
|
818
|
+
* @param options - Trusted profiles + policy.
|
|
819
|
+
* @returns The verified token.
|
|
820
|
+
* @throws {OAuthResourceError} `unauthorized` for any malformed / untrusted / invalid token; `forbidden` when a claim gate fails. Replaceable via {@link VerifyBearerOptions.errorFactory}.
|
|
821
|
+
*/ function verifyBearerJwt(token, options) {
|
|
822
|
+
return _async_to_generator(function() {
|
|
823
|
+
var _options_errorFactory, _options_clockToleranceSeconds, _options_nowSeconds, _options_claimGateKinds, errorFactory, clockTolerance, unverified, profile, now, context, claims, _options_algorithms, authTime, claimGateKinds;
|
|
824
|
+
return _ts_generator(this, function(_state) {
|
|
825
|
+
switch(_state.label){
|
|
826
|
+
case 0:
|
|
827
|
+
errorFactory = (_options_errorFactory = options.errorFactory) !== null && _options_errorFactory !== void 0 ? _options_errorFactory : defaultOAuthResourceErrorFactory;
|
|
828
|
+
clockTolerance = (_options_clockToleranceSeconds = options.clockToleranceSeconds) !== null && _options_clockToleranceSeconds !== void 0 ? _options_clockToleranceSeconds : BEARER_CLOCK_TOLERANCE_SECONDS;
|
|
829
|
+
try {
|
|
830
|
+
unverified = decodeJwt(token);
|
|
831
|
+
} catch (unused) {
|
|
832
|
+
throw errorFactory({
|
|
833
|
+
code: 'unauthorized',
|
|
834
|
+
message: 'Malformed bearer token.'
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
profile = unverified.iss === undefined ? undefined : options.profiles.get(unverified.iss);
|
|
838
|
+
if (!profile) {
|
|
839
|
+
throw errorFactory({
|
|
840
|
+
code: 'unauthorized',
|
|
841
|
+
message: 'Untrusted token issuer.'
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
now = ((_options_nowSeconds = options.nowSeconds) !== null && _options_nowSeconds !== void 0 ? _options_nowSeconds : defaultNowSeconds)();
|
|
845
|
+
context = {
|
|
846
|
+
profile: profile,
|
|
847
|
+
now: now,
|
|
848
|
+
clockTolerance: clockTolerance,
|
|
849
|
+
errorFactory: errorFactory
|
|
850
|
+
};
|
|
851
|
+
if (!(profile.kind === 'firebase' && options.firebaseEmulator === true && isUnsignedToken(token))) return [
|
|
852
|
+
3,
|
|
853
|
+
1
|
|
854
|
+
];
|
|
855
|
+
claims = verifyUnsignedEmulatorToken(unverified, context);
|
|
856
|
+
return [
|
|
857
|
+
3,
|
|
858
|
+
3
|
|
859
|
+
];
|
|
860
|
+
case 1:
|
|
861
|
+
return [
|
|
862
|
+
4,
|
|
863
|
+
verifySignedToken(token, context, (_options_algorithms = options.algorithms) !== null && _options_algorithms !== void 0 ? _options_algorithms : BEARER_ALGORITHMS)
|
|
864
|
+
];
|
|
865
|
+
case 2:
|
|
866
|
+
claims = _state.sent();
|
|
867
|
+
_state.label = 3;
|
|
868
|
+
case 3:
|
|
869
|
+
if (typeof claims.sub !== 'string' || claims.sub.length === 0) {
|
|
870
|
+
throw errorFactory({
|
|
871
|
+
code: 'unauthorized',
|
|
872
|
+
message: 'Token has no subject.'
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
if (profile.kind === 'firebase') {
|
|
876
|
+
authTime = claims['auth_time'];
|
|
877
|
+
if (typeof authTime === 'number' && authTime > now + clockTolerance) {
|
|
878
|
+
throw errorFactory({
|
|
879
|
+
code: 'unauthorized',
|
|
880
|
+
message: 'Token auth_time is in the future.'
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
claimGateKinds = (_options_claimGateKinds = options.claimGateKinds) !== null && _options_claimGateKinds !== void 0 ? _options_claimGateKinds : DEFAULT_BEARER_CLAIM_GATE_KINDS;
|
|
885
|
+
if (!claimGateKinds.includes(profile.kind)) return [
|
|
886
|
+
3,
|
|
887
|
+
5
|
|
888
|
+
];
|
|
889
|
+
return [
|
|
890
|
+
4,
|
|
891
|
+
assertClaimGates(claims, options, context)
|
|
892
|
+
];
|
|
893
|
+
case 4:
|
|
894
|
+
_state.sent();
|
|
895
|
+
_state.label = 5;
|
|
896
|
+
case 5:
|
|
897
|
+
return [
|
|
898
|
+
2,
|
|
899
|
+
{
|
|
900
|
+
kind: profile.kind,
|
|
901
|
+
issuer: profile.issuer,
|
|
902
|
+
subject: claims.sub,
|
|
903
|
+
claims: claims,
|
|
904
|
+
token: token
|
|
905
|
+
}
|
|
906
|
+
];
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
})();
|
|
910
|
+
}
|
|
911
|
+
function defaultNowSeconds() {
|
|
912
|
+
return Math.floor(Date.now() / 1000);
|
|
913
|
+
}
|
|
914
|
+
function isUnsignedToken(token) {
|
|
915
|
+
var unsigned = false;
|
|
916
|
+
try {
|
|
917
|
+
unsigned = decodeProtectedHeader(token).alg === 'none';
|
|
918
|
+
} catch (unused) {
|
|
919
|
+
// undecodable header — treat as signed so the signature path rejects it
|
|
920
|
+
}
|
|
921
|
+
return unsigned;
|
|
922
|
+
}
|
|
923
|
+
function assertClaimGates(claims, options, context) {
|
|
924
|
+
return _async_to_generator(function() {
|
|
925
|
+
var _options_requiredClaims, requiredClaims, missingClaim, allowed;
|
|
926
|
+
return _ts_generator(this, function(_state) {
|
|
927
|
+
switch(_state.label){
|
|
928
|
+
case 0:
|
|
929
|
+
requiredClaims = (_options_requiredClaims = options.requiredClaims) !== null && _options_requiredClaims !== void 0 ? _options_requiredClaims : [];
|
|
930
|
+
missingClaim = requiredClaims.find(function(claim) {
|
|
931
|
+
return !claims[claim];
|
|
932
|
+
});
|
|
933
|
+
if (missingClaim != null) {
|
|
934
|
+
throw context.errorFactory({
|
|
935
|
+
code: 'forbidden',
|
|
936
|
+
message: 'Token is missing the required "'.concat(missingClaim, '" claim.'),
|
|
937
|
+
details: {
|
|
938
|
+
claim: missingClaim
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
if (!(options.claimPredicate != null)) return [
|
|
943
|
+
3,
|
|
944
|
+
2
|
|
945
|
+
];
|
|
946
|
+
return [
|
|
947
|
+
4,
|
|
948
|
+
options.claimPredicate(claims, context.profile)
|
|
949
|
+
];
|
|
950
|
+
case 1:
|
|
951
|
+
allowed = _state.sent();
|
|
952
|
+
if (!allowed) {
|
|
953
|
+
throw context.errorFactory({
|
|
954
|
+
code: 'forbidden',
|
|
955
|
+
message: 'Token failed the resource server claim policy.'
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
_state.label = 2;
|
|
959
|
+
case 2:
|
|
960
|
+
return [
|
|
961
|
+
2
|
|
962
|
+
];
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
})();
|
|
966
|
+
}
|
|
967
|
+
function verifySignedToken(token, context, algorithms) {
|
|
968
|
+
return _async_to_generator(function() {
|
|
969
|
+
var profile, now, clockTolerance, errorFactory, claims, getKey, verified, error, code;
|
|
970
|
+
return _ts_generator(this, function(_state) {
|
|
971
|
+
switch(_state.label){
|
|
972
|
+
case 0:
|
|
973
|
+
profile = context.profile, now = context.now, clockTolerance = context.clockTolerance, errorFactory = context.errorFactory;
|
|
974
|
+
_state.label = 1;
|
|
975
|
+
case 1:
|
|
976
|
+
_state.trys.push([
|
|
977
|
+
1,
|
|
978
|
+
4,
|
|
979
|
+
,
|
|
980
|
+
5
|
|
981
|
+
]);
|
|
982
|
+
return [
|
|
983
|
+
4,
|
|
984
|
+
profile.getKey()
|
|
985
|
+
];
|
|
986
|
+
case 2:
|
|
987
|
+
getKey = _state.sent();
|
|
988
|
+
return [
|
|
989
|
+
4,
|
|
990
|
+
jwtVerify(token, getKey, {
|
|
991
|
+
issuer: profile.issuer,
|
|
992
|
+
audience: _to_consumable_array(profile.audiences),
|
|
993
|
+
algorithms: _to_consumable_array(algorithms),
|
|
994
|
+
clockTolerance: clockTolerance,
|
|
995
|
+
currentDate: new Date(now * 1000)
|
|
996
|
+
})
|
|
997
|
+
];
|
|
998
|
+
case 3:
|
|
999
|
+
verified = _state.sent();
|
|
1000
|
+
claims = verified.payload;
|
|
1001
|
+
return [
|
|
1002
|
+
3,
|
|
1003
|
+
5
|
|
1004
|
+
];
|
|
1005
|
+
case 4:
|
|
1006
|
+
error = _state.sent();
|
|
1007
|
+
code = _instanceof(error, errors.JOSEError) ? error.code : 'ERR_JWT_INVALID';
|
|
1008
|
+
throw errorFactory({
|
|
1009
|
+
code: 'unauthorized',
|
|
1010
|
+
message: "Invalid bearer token (".concat(code, ").")
|
|
1011
|
+
});
|
|
1012
|
+
case 5:
|
|
1013
|
+
return [
|
|
1014
|
+
2,
|
|
1015
|
+
claims
|
|
1016
|
+
];
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
})();
|
|
1020
|
+
}
|
|
1021
|
+
// The emulator issues `alg: none` tokens; firebase-admin skips the signature
|
|
1022
|
+
// under FIREBASE_AUTH_EMULATOR_HOST and checks the claims only, so the same
|
|
1023
|
+
// iss / aud / exp / iat gates are applied here. The error strings reproduce jose's
|
|
1024
|
+
// so both paths look identical to a caller.
|
|
1025
|
+
function verifyUnsignedEmulatorToken(claims, context) {
|
|
1026
|
+
var _claims_aud;
|
|
1027
|
+
var profile = context.profile, now = context.now, clockTolerance = context.clockTolerance, errorFactory = context.errorFactory;
|
|
1028
|
+
var audiences = typeof claims.aud === 'string' ? [
|
|
1029
|
+
claims.aud
|
|
1030
|
+
] : (_claims_aud = claims.aud) !== null && _claims_aud !== void 0 ? _claims_aud : [];
|
|
1031
|
+
if (claims.iss !== profile.issuer) {
|
|
1032
|
+
throw errorFactory({
|
|
1033
|
+
code: 'unauthorized',
|
|
1034
|
+
message: 'Invalid bearer token (ERR_JWT_CLAIM_VALIDATION_FAILED: iss).'
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
if (!audiences.some(function(aud) {
|
|
1038
|
+
return profile.audiences.includes(aud);
|
|
1039
|
+
})) {
|
|
1040
|
+
throw errorFactory({
|
|
1041
|
+
code: 'unauthorized',
|
|
1042
|
+
message: 'Invalid bearer token (ERR_JWT_CLAIM_VALIDATION_FAILED: aud).'
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
if (typeof claims.exp !== 'number' || claims.exp + clockTolerance <= now) {
|
|
1046
|
+
throw errorFactory({
|
|
1047
|
+
code: 'unauthorized',
|
|
1048
|
+
message: 'Invalid bearer token (ERR_JWT_EXPIRED).'
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
if (typeof claims.nbf === 'number' && claims.nbf > now + clockTolerance) {
|
|
1052
|
+
throw errorFactory({
|
|
1053
|
+
code: 'unauthorized',
|
|
1054
|
+
message: 'Invalid bearer token (ERR_JWT_CLAIM_VALIDATION_FAILED: nbf).'
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
if (typeof claims.iat === 'number' && claims.iat > now + clockTolerance) {
|
|
1058
|
+
throw errorFactory({
|
|
1059
|
+
code: 'unauthorized',
|
|
1060
|
+
message: 'Invalid bearer token (ERR_JWT_CLAIM_VALIDATION_FAILED: iat).'
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
return claims;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
export { BEARER_ALGORITHMS, BEARER_AUTHORIZATION_PREFIX, BEARER_CLOCK_TOLERANCE_SECONDS, DEFAULT_BEARER_CLAIM_GATE_KINDS, FIREBASE_AUTH_INFO_CLIENT_ID, FIREBASE_SECURETOKEN_JWKS_URL, OAUTH_PROTECTED_RESOURCE_PATH, OAUTH_RESOURCE_ERROR_STATUS_CODES, OAuthResourceError, OPENID_CONFIGURATION_PATH, bearerChallengeErrorForCode, buildBearerChallenge, buildIssuerProfiles, buildProtectedResourceMetadata, defaultOAuthResourceErrorFactory, firebaseIssuerForProject, isOAuthResourceError, oauthProtectedResourcePathForResource, oauthResourceAuthInfoForVerifiedBearer, readBearerToken, scopesFromScopeClaim, verifyBearerJwt };
|