@dereekb/firebase-server 13.28.0 → 13.30.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/index.cjs.js +161 -2
- package/index.esm.js +160 -4
- package/mailgun/package.json +9 -9
- package/mcp/index.cjs.js +43 -10
- package/mcp/index.esm.js +43 -10
- package/mcp/package.json +11 -11
- package/mcp/src/lib/mcp.config.d.ts +19 -1
- package/mcp/src/lib/service/mcp.server.factory.d.ts +1 -1
- package/mcp/src/lib/service/mcp.tool-generator.d.ts +12 -1
- package/mcp/src/lib/service/mcp.visibility.d.ts +9 -4
- package/model/package.json +9 -9
- package/oidc/index.cjs.js +178 -82
- package/oidc/index.esm.js +179 -84
- package/oidc/package.json +10 -10
- package/oidc/src/lib/index.d.ts +1 -1
- package/oidc/src/lib/oidc.config.d.ts +14 -1
- package/oidc/src/lib/profile.d.ts +29 -0
- package/oidc/src/lib/service/oidc.auth.d.ts +1 -1
- package/package.json +10 -10
- package/src/lib/nest/controller/model/index.d.ts +1 -0
- package/src/lib/nest/controller/model/model.api.dispatch.d.ts +14 -2
- package/src/lib/nest/controller/model/model.api.get.service.d.ts +14 -0
- package/src/lib/nest/controller/model/model.api.scope.d.ts +102 -0
- package/src/lib/nest/model/api.details.d.ts +31 -2
- package/src/lib/nest/model/crud.assert.function.d.ts +10 -1
- package/test/index.cjs.js +10 -3
- package/test/index.esm.js +11 -4
- package/test/package.json +11 -11
- package/test/src/lib/oidc/oidc.test.flow.d.ts +1 -1
- package/twilio/package.json +8 -8
- package/zoho/package.json +9 -9
- package/oidc/src/lib/scope.d.ts +0 -19
package/oidc/index.esm.js
CHANGED
|
@@ -3,8 +3,8 @@ import { errors } from 'oidc-provider';
|
|
|
3
3
|
import { SECONDS_IN_MINUTE, SECONDS_IN_DAY, cachedGetter, unixDateTimeSecondsNumberToDate, unixDateTimeSecondsNumberForNow, selectiveFieldEncryptor, filterUndefinedValues, websiteUrlFromPaths, firstValue, hasHttpPrefix } from '@dereekb/util';
|
|
4
4
|
import { generateKeyPairSync, randomBytes } from 'node:crypto';
|
|
5
5
|
import { resolveEncryptionKey, encryptValue, decryptValue, createAesStringEncryptionProvider, isValidAES256GCMEncryptionSecret } from '@dereekb/nestjs';
|
|
6
|
-
import { where, iterateFirestoreDocumentSnapshotPairs, firestoreModelIdentity, snapshotConverterFunctions, optionalFirestoreDate, firestoreDate, firestoreEnum, firestorePassThroughField, AbstractFirestoreDocument, createOidcClientParamsType, deleteOidcClientParamsType, deleteOidcTokenParamsType, rotateOidcClientSecretParamsType, updateOidcClientParamsType, firestoreModelKey, oidcEntryIdentity, PUBLIC_PKCE_TOKEN_ENDPOINT_AUTH_METHOD, OIDC_ENTRY_CLIENT_TYPE, oidcEntriesByUserCodeQuery, oidcEntriesByUidQuery, oidcEntriesByGrantIdQuery,
|
|
7
|
-
import { firestoreEncryptedField, firebaseServerActionsContext, FirebaseServerEnvService, FirebaseServerAnalyticsService, FIREBASE_FIRESTORE_CONTEXT_TOKEN, FirebaseServerFirestoreContextModule
|
|
6
|
+
import { where, iterateFirestoreDocumentSnapshotPairs, firestoreModelIdentity, snapshotConverterFunctions, optionalFirestoreDate, firestoreDate, firestoreEnum, firestorePassThroughField, AbstractFirestoreDocument, createOidcClientParamsType, deleteOidcClientParamsType, deleteOidcTokenParamsType, rotateOidcClientSecretParamsType, updateOidcClientParamsType, firestoreModelKey, oidcEntryIdentity, PUBLIC_PKCE_TOKEN_ENDPOINT_AUTH_METHOD, OIDC_ENTRY_CLIENT_TYPE, oidcEntriesByUserCodeQuery, oidcEntriesByUidQuery, oidcEntriesByGrantIdQuery, oidcProviderProfilesForKeys, requiredScopesForOidcProviderProfiles, scopesForOidcProviderProfiles, oidcScopesFromScopeClaim, oidcEntryFirestoreCollection } from '@dereekb/firebase';
|
|
7
|
+
import { firestoreEncryptedField, firebaseServerActionsContext, FirebaseServerEnvService, FirebaseServerAnalyticsService, FIREBASE_FIRESTORE_CONTEXT_TOKEN, FirebaseServerFirestoreContextModule } from '@dereekb/firebase-server';
|
|
8
8
|
import { nanoid } from 'nanoid';
|
|
9
9
|
import { safeToJsDate } from '@dereekb/date';
|
|
10
10
|
import { makeUrlSearchParamsString } from '@dereekb/util/fetch';
|
|
@@ -2429,6 +2429,9 @@ function _ts_generator$7(thisArg, body) {
|
|
|
2429
2429
|
if (params.dbx_max_session_ttl != null) {
|
|
2430
2430
|
properties.dbx_max_session_ttl = params.dbx_max_session_ttl;
|
|
2431
2431
|
}
|
|
2432
|
+
if (params.dbx_provider_profiles != null) {
|
|
2433
|
+
properties.dbx_provider_profiles = params.dbx_provider_profiles;
|
|
2434
|
+
}
|
|
2432
2435
|
// Merge any pre-validated metadata (e.g., inline jwks for private_key_jwt in tests)
|
|
2433
2436
|
if (validatedMetadata === null || validatedMetadata === void 0 ? void 0 : validatedMetadata.jwks) {
|
|
2434
2437
|
properties.jwks = validatedMetadata.jwks;
|
|
@@ -2486,7 +2489,7 @@ function _ts_generator$7(thisArg, body) {
|
|
|
2486
2489
|
* @throws {Error} When the client is not found.
|
|
2487
2490
|
*/ function updateClient(clientId, params) {
|
|
2488
2491
|
return _async_to_generator$7(function() {
|
|
2489
|
-
var provider, ProviderClient, existing, updatedMetadata, _params_logo_uri, _params_client_uri, _params_dbx_max_session_ttl, client;
|
|
2492
|
+
var provider, ProviderClient, existing, updatedMetadata, _params_logo_uri, _params_client_uri, _params_dbx_max_session_ttl, _params_dbx_provider_profiles, client;
|
|
2490
2493
|
return _ts_generator$7(this, function(_state) {
|
|
2491
2494
|
switch(_state.label){
|
|
2492
2495
|
case 0:
|
|
@@ -2518,6 +2521,12 @@ function _ts_generator$7(thisArg, body) {
|
|
|
2518
2521
|
if (params.dbx_max_session_ttl !== undefined) {
|
|
2519
2522
|
updatedMetadata.dbx_max_session_ttl = (_params_dbx_max_session_ttl = params.dbx_max_session_ttl) !== null && _params_dbx_max_session_ttl !== void 0 ? _params_dbx_max_session_ttl : undefined;
|
|
2520
2523
|
}
|
|
2524
|
+
// Only overwrite the profile assignment when the field is explicitly provided. An omitted value
|
|
2525
|
+
// (including one stripped for a non-admin caller) preserves the existing assignment; `null`/`[]`
|
|
2526
|
+
// clears it. This is what makes the non-admin strip a no-op rather than a wipe.
|
|
2527
|
+
if (params.dbx_provider_profiles !== undefined) {
|
|
2528
|
+
updatedMetadata.dbx_provider_profiles = (_params_dbx_provider_profiles = params.dbx_provider_profiles) !== null && _params_dbx_provider_profiles !== void 0 ? _params_dbx_provider_profiles : undefined;
|
|
2529
|
+
}
|
|
2521
2530
|
// Mirrors oidc-provider's lib/helpers/add_client.js: re-validates and persists.
|
|
2522
2531
|
return [
|
|
2523
2532
|
4,
|
|
@@ -3536,6 +3545,25 @@ OidcProviderConfigService = __decorate([
|
|
|
3536
3545
|
__param(2, Inject(FirebaseServerEnvService))
|
|
3537
3546
|
], OidcProviderConfigService);
|
|
3538
3547
|
|
|
3548
|
+
/**
|
|
3549
|
+
* Custom oidc-provider client metadata field holding the {@link OidcProviderProfile} keys assigned
|
|
3550
|
+
* to a client. Registered via `extraClientMetadata` and persisted on the client's `OidcEntry` payload.
|
|
3551
|
+
*/ var DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA = 'dbx_provider_profiles';
|
|
3552
|
+
/**
|
|
3553
|
+
* Resolves the unlocked + required scope sets for a client from the provider-profile registry and
|
|
3554
|
+
* the profile keys assigned to that client.
|
|
3555
|
+
*
|
|
3556
|
+
* @param providerProfiles - The provider-profile registry (from {@link OidcProviderConfig.providerProfiles}).
|
|
3557
|
+
* @param clientProfileKeys - The profile keys assigned to the client (its `dbx_provider_profiles`).
|
|
3558
|
+
* @returns The unlocked and required scope sets for the client.
|
|
3559
|
+
*/ function oidcClientProviderProfileScopes(providerProfiles, clientProfileKeys) {
|
|
3560
|
+
var clientProfiles = oidcProviderProfilesForKeys(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : [], clientProfileKeys);
|
|
3561
|
+
return {
|
|
3562
|
+
unlocked: scopesForOidcProviderProfiles(clientProfiles),
|
|
3563
|
+
required: requiredScopesForOidcProviderProfiles(clientProfiles)
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3539
3567
|
function _array_like_to_array$4(arr, len) {
|
|
3540
3568
|
if (len == null || len > arr.length) len = arr.length;
|
|
3541
3569
|
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
@@ -4040,7 +4068,8 @@ function _ts_generator$5(thisArg, body) {
|
|
|
4040
4068
|
logo_uri: existing.logo_uri,
|
|
4041
4069
|
client_uri: existing.client_uri,
|
|
4042
4070
|
created_at: existing.created_at,
|
|
4043
|
-
dbx_max_session_ttl: existing.dbx_max_session_ttl
|
|
4071
|
+
dbx_max_session_ttl: existing.dbx_max_session_ttl,
|
|
4072
|
+
dbx_provider_profiles: existing.dbx_provider_profiles
|
|
4044
4073
|
};
|
|
4045
4074
|
}
|
|
4046
4075
|
return [
|
|
@@ -4147,7 +4176,8 @@ function _ts_generator$5(thisArg, body) {
|
|
|
4147
4176
|
],
|
|
4148
4177
|
extraClientMetadata: {
|
|
4149
4178
|
properties: [
|
|
4150
|
-
DBX_FIREBASE_SERVER_OIDC_MAX_SESSION_TTL_CLIENT_METADATA
|
|
4179
|
+
DBX_FIREBASE_SERVER_OIDC_MAX_SESSION_TTL_CLIENT_METADATA,
|
|
4180
|
+
DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA
|
|
4151
4181
|
],
|
|
4152
4182
|
validator: function validator(_ctx, key, value) {
|
|
4153
4183
|
if (key === DBX_FIREBASE_SERVER_OIDC_MAX_SESSION_TTL_CLIENT_METADATA && value !== undefined && value !== null) {
|
|
@@ -4157,6 +4187,22 @@ function _ts_generator$5(thisArg, body) {
|
|
|
4157
4187
|
if (value > serverMaxSeconds) {
|
|
4158
4188
|
throw new errors.InvalidClientMetadata("".concat(DBX_FIREBASE_SERVER_OIDC_MAX_SESSION_TTL_CLIENT_METADATA, " cannot exceed the server max of ").concat(serverMaxSeconds, " seconds."));
|
|
4159
4189
|
}
|
|
4190
|
+
} else if (key === DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA && value !== undefined && value !== null) {
|
|
4191
|
+
var _providerConfig_providerProfiles;
|
|
4192
|
+
if (!Array.isArray(value) || value.some(function(entry) {
|
|
4193
|
+
return typeof entry !== 'string';
|
|
4194
|
+
})) {
|
|
4195
|
+
throw new errors.InvalidClientMetadata("".concat(DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA, " must be an array of provider profile keys."));
|
|
4196
|
+
}
|
|
4197
|
+
var knownProfileKeys = new Set(((_providerConfig_providerProfiles = providerConfig.providerProfiles) !== null && _providerConfig_providerProfiles !== void 0 ? _providerConfig_providerProfiles : []).map(function(profile) {
|
|
4198
|
+
return profile.key;
|
|
4199
|
+
}));
|
|
4200
|
+
var unknownKey = value.find(function(entry) {
|
|
4201
|
+
return !knownProfileKeys.has(entry);
|
|
4202
|
+
});
|
|
4203
|
+
if (unknownKey !== undefined) {
|
|
4204
|
+
throw new errors.InvalidClientMetadata("".concat(DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA, " contains an unknown provider profile key: ").concat(unknownKey, "."));
|
|
4205
|
+
}
|
|
4160
4206
|
}
|
|
4161
4207
|
}
|
|
4162
4208
|
},
|
|
@@ -4184,7 +4230,7 @@ function _ts_generator$5(thisArg, body) {
|
|
|
4184
4230
|
interactions: {
|
|
4185
4231
|
url: function url(_ctx, interaction) {
|
|
4186
4232
|
return _async_to_generator$5(function() {
|
|
4187
|
-
var baseUrl, client_id, paramsToEncode, client, scopes, interactionLoginDetails, paramsString;
|
|
4233
|
+
var baseUrl, client_id, paramsToEncode, client, _client_dbx_provider_profiles, scopes, requestedScopeSet, required, requiredScopes, interactionLoginDetails, paramsString;
|
|
4188
4234
|
return _ts_generator$5(this, function(_state) {
|
|
4189
4235
|
switch(_state.label){
|
|
4190
4236
|
case 0:
|
|
@@ -4212,13 +4258,23 @@ function _ts_generator$5(thisArg, body) {
|
|
|
4212
4258
|
client = _state.sent();
|
|
4213
4259
|
if (client) {
|
|
4214
4260
|
scopes = interaction.params.scope;
|
|
4215
|
-
|
|
4261
|
+
// Surface the scopes the client's provider profiles force-require so the consent UI can
|
|
4262
|
+
// render them as required. Intersect with the actually-requested scopes so only visible
|
|
4263
|
+
// scope rows are flagged.
|
|
4264
|
+
requestedScopeSet = new Set(scopes.split(' ').filter(Boolean));
|
|
4265
|
+
required = oidcClientProviderProfileScopes(providerConfig.providerProfiles, (_client_dbx_provider_profiles = client.dbx_provider_profiles) !== null && _client_dbx_provider_profiles !== void 0 ? _client_dbx_provider_profiles : undefined).required;
|
|
4266
|
+
requiredScopes = Array.from(required).filter(function(scope) {
|
|
4267
|
+
return requestedScopeSet.has(scope);
|
|
4268
|
+
});
|
|
4269
|
+
interactionLoginDetails = _object_spread$3({
|
|
4216
4270
|
client_id: client_id,
|
|
4217
4271
|
client_name: client.client_name,
|
|
4218
4272
|
client_uri: client.client_uri,
|
|
4219
4273
|
logo_uri: client.logo_uri,
|
|
4220
4274
|
scopes: scopes
|
|
4221
|
-
}
|
|
4275
|
+
}, requiredScopes.length > 0 ? {
|
|
4276
|
+
requiredScopes: requiredScopes.join(' ')
|
|
4277
|
+
} : {});
|
|
4222
4278
|
paramsToEncode = _object_spread$3({}, paramsToEncode, interactionLoginDetails);
|
|
4223
4279
|
}
|
|
4224
4280
|
_state.label = 3;
|
|
@@ -5337,7 +5393,7 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
5337
5393
|
* `request.auth.token.scope` for OIDC callers and is `undefined` for non-OIDC
|
|
5338
5394
|
* (regular Firebase ID-token) callers.
|
|
5339
5395
|
*
|
|
5340
|
-
* Returning `undefined` for non-OIDC callers lets
|
|
5396
|
+
* Returning `undefined` for non-OIDC callers lets consumers (e.g. the MCP tool-visibility filter)
|
|
5341
5397
|
* skip scope enforcement instead of falsely treating the missing claim as "no scopes granted".
|
|
5342
5398
|
*
|
|
5343
5399
|
* The parameter is intentionally typed as `unknown` because `DecodedIdToken` (Firebase
|
|
@@ -5349,10 +5405,7 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
5349
5405
|
*/ function getOidcScopesFromRequest(request) {
|
|
5350
5406
|
var _request_auth_token, _request_auth;
|
|
5351
5407
|
var scope = request === null || request === void 0 ? void 0 : (_request_auth = request.auth) === null || _request_auth === void 0 ? void 0 : (_request_auth_token = _request_auth.token) === null || _request_auth_token === void 0 ? void 0 : _request_auth_token.scope;
|
|
5352
|
-
|
|
5353
|
-
return value.length > 0;
|
|
5354
|
-
})) : undefined;
|
|
5355
|
-
return result;
|
|
5408
|
+
return oidcScopesFromScopeClaim(scope);
|
|
5356
5409
|
}
|
|
5357
5410
|
|
|
5358
5411
|
function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
|
|
@@ -6157,7 +6210,7 @@ var OidcInteractionController_1;
|
|
|
6157
6210
|
* @throws {HttpException} HTTP 400 when the consent interaction cannot be completed.
|
|
6158
6211
|
*/ function postConsent(uid, body, res) {
|
|
6159
6212
|
return _async_to_generator$2(function() {
|
|
6160
|
-
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope, _this_accountService_providerConfig_adminOnlyScopes, _ref1, _ref2, _prompt_details_missingOIDCClaims, _prompt_details_missingResourceScopes, _this_accountService_delegate_isAdminUser, _this_accountService_delegate,
|
|
6213
|
+
var startedAt, clientId, accountId, _ref, _prompt_details_missingOIDCScope, _this_accountService_providerConfig_adminOnlyScopes, _ref1, _ref2, _ref3, _prompt_details_missingOIDCClaims, _prompt_details_missingResourceScopes, _this_accountService_delegate_isAdminUser, _this_accountService_delegate, _ref4, redirectTo, interaction, prompt, params, session, missingOIDCScope, existingGrant, _tmp, encounteredOIDCScopes, clientPayload, requestedOIDCScopeSet, adminOnlyScopes, requestsServiceToken, isAdmin, _tmp1, _ref5, redirectTo1, providerProfiles, _oidcClientProviderProfileScopes, clientUnlockedScopes, clientRequiredScopes, profileGatedScopes, disallowedGatedScopes, _ref6, redirectTo2, missingRequiredScopes, _ref7, redirectTo3, requestedRawTtl, clientMaxSessionTtl, expiresInSeconds, grant, _tmp2, _resolveEffectiveSubset, granted, rejected, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, value, encounteredOIDCClaims, missingOIDCClaims, _resolveEffectiveSubset1, granted1, rejected1, missingResourceScopes, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, indicator, scopes, _body_grantedResourceScopes, requestedSubset, encounteredResourceScopes, _resolveEffectiveSubset2, granted2, rejected2, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, value1, grantId, _ref8, redirectTo4, err;
|
|
6161
6214
|
return _ts_generator$2(this, function(_state) {
|
|
6162
6215
|
switch(_state.label){
|
|
6163
6216
|
case 0:
|
|
@@ -6172,9 +6225,9 @@ var OidcInteractionController_1;
|
|
|
6172
6225
|
case 2:
|
|
6173
6226
|
_state.trys.push([
|
|
6174
6227
|
2,
|
|
6175
|
-
|
|
6228
|
+
24,
|
|
6176
6229
|
,
|
|
6177
|
-
|
|
6230
|
+
25
|
|
6178
6231
|
]);
|
|
6179
6232
|
if (!!body.approved) return [
|
|
6180
6233
|
3,
|
|
@@ -6190,7 +6243,7 @@ var OidcInteractionController_1;
|
|
|
6190
6243
|
})
|
|
6191
6244
|
];
|
|
6192
6245
|
case 3:
|
|
6193
|
-
|
|
6246
|
+
_ref4 = _state.sent(), redirectTo = _ref4.returnTo;
|
|
6194
6247
|
res.json({
|
|
6195
6248
|
redirectTo: redirectTo
|
|
6196
6249
|
});
|
|
@@ -6233,6 +6286,12 @@ var OidcInteractionController_1;
|
|
|
6233
6286
|
// and re-submits them all. We accept already-encountered values as silent no-ops so a re-consent on a
|
|
6234
6287
|
// client the user has previously authorized doesn't fail validation.
|
|
6235
6288
|
encounteredOIDCScopes = existingGrant ? existingGrant.getOIDCScopeEncountered().split(' ').filter(Boolean) : [];
|
|
6289
|
+
return [
|
|
6290
|
+
4,
|
|
6291
|
+
this.oidcService.findClientPayload(clientId)
|
|
6292
|
+
];
|
|
6293
|
+
case 9:
|
|
6294
|
+
clientPayload = _state.sent();
|
|
6236
6295
|
// Admin-only scope gate. The requested OIDC scope set is `missingOIDCScope ∪ encounteredOIDCScopes`
|
|
6237
6296
|
// (a fresh consent has everything in `missing`; a re-consent may carry already-granted scopes in
|
|
6238
6297
|
// `encountered`). If that set intersects the provider's `adminOnlyScopes` and the resolving user is
|
|
@@ -6244,26 +6303,26 @@ var OidcInteractionController_1;
|
|
|
6244
6303
|
});
|
|
6245
6304
|
if (!accountId) return [
|
|
6246
6305
|
3,
|
|
6247
|
-
|
|
6306
|
+
11
|
|
6248
6307
|
];
|
|
6249
6308
|
return [
|
|
6250
6309
|
4,
|
|
6251
6310
|
(_ref1 = (_this_accountService_delegate_isAdminUser = (_this_accountService_delegate = this.accountService.delegate).isAdminUser) === null || _this_accountService_delegate_isAdminUser === void 0 ? void 0 : _this_accountService_delegate_isAdminUser.call(_this_accountService_delegate, this.accountService.userContext(accountId).authUserContext)) !== null && _ref1 !== void 0 ? _ref1 : false
|
|
6252
6311
|
];
|
|
6253
|
-
case
|
|
6312
|
+
case 10:
|
|
6254
6313
|
_tmp1 = _state.sent();
|
|
6255
6314
|
return [
|
|
6256
6315
|
3,
|
|
6257
|
-
|
|
6316
|
+
12
|
|
6258
6317
|
];
|
|
6259
|
-
case 10:
|
|
6260
|
-
_tmp1 = false;
|
|
6261
|
-
_state.label = 11;
|
|
6262
6318
|
case 11:
|
|
6319
|
+
_tmp1 = false;
|
|
6320
|
+
_state.label = 12;
|
|
6321
|
+
case 12:
|
|
6263
6322
|
isAdmin = _tmp1;
|
|
6264
6323
|
if (!(requestsServiceToken && !isAdmin)) return [
|
|
6265
6324
|
3,
|
|
6266
|
-
|
|
6325
|
+
14
|
|
6267
6326
|
];
|
|
6268
6327
|
return [
|
|
6269
6328
|
4,
|
|
@@ -6274,8 +6333,8 @@ var OidcInteractionController_1;
|
|
|
6274
6333
|
mergeWithLastSubmission: true
|
|
6275
6334
|
})
|
|
6276
6335
|
];
|
|
6277
|
-
case
|
|
6278
|
-
|
|
6336
|
+
case 13:
|
|
6337
|
+
_ref5 = _state.sent(), redirectTo1 = _ref5.returnTo;
|
|
6279
6338
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6280
6339
|
type: 'consent',
|
|
6281
6340
|
isSuccessful: false,
|
|
@@ -6292,20 +6351,89 @@ var OidcInteractionController_1;
|
|
|
6292
6351
|
return [
|
|
6293
6352
|
2
|
|
6294
6353
|
];
|
|
6295
|
-
case
|
|
6354
|
+
case 14:
|
|
6355
|
+
// Provider-profile scope gate. Any scope referenced by a provider profile is "gated" — available
|
|
6356
|
+
// only to clients whose assigned profiles unlock it. Independent of the admin-only gate above; a
|
|
6357
|
+
// scope may be subject to both.
|
|
6358
|
+
providerProfiles = this.accountService.providerConfig.providerProfiles;
|
|
6359
|
+
_oidcClientProviderProfileScopes = oidcClientProviderProfileScopes(providerProfiles, (_ref2 = clientPayload === null || clientPayload === void 0 ? void 0 : clientPayload.dbx_provider_profiles) !== null && _ref2 !== void 0 ? _ref2 : undefined), clientUnlockedScopes = _oidcClientProviderProfileScopes.unlocked, clientRequiredScopes = _oidcClientProviderProfileScopes.required;
|
|
6360
|
+
profileGatedScopes = scopesForOidcProviderProfiles(providerProfiles !== null && providerProfiles !== void 0 ? providerProfiles : []);
|
|
6361
|
+
// Unlock gate: reject any requested gated scope this client's profiles do not unlock.
|
|
6362
|
+
disallowedGatedScopes = Array.from(requestedOIDCScopeSet).filter(function(scope) {
|
|
6363
|
+
return profileGatedScopes.has(scope) && !clientUnlockedScopes.has(scope);
|
|
6364
|
+
});
|
|
6365
|
+
if (!(disallowedGatedScopes.length > 0)) return [
|
|
6366
|
+
3,
|
|
6367
|
+
16
|
|
6368
|
+
];
|
|
6369
|
+
return [
|
|
6370
|
+
4,
|
|
6371
|
+
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6372
|
+
error: 'access_denied',
|
|
6373
|
+
error_description: "The following scope(s) are not available to this client: ".concat(disallowedGatedScopes.join(', '), ".")
|
|
6374
|
+
}, {
|
|
6375
|
+
mergeWithLastSubmission: true
|
|
6376
|
+
})
|
|
6377
|
+
];
|
|
6378
|
+
case 15:
|
|
6379
|
+
_ref6 = _state.sent(), redirectTo2 = _ref6.returnTo;
|
|
6380
|
+
emitOidcAnalyticsEvent(this._analytics, {
|
|
6381
|
+
type: 'consent',
|
|
6382
|
+
isSuccessful: false,
|
|
6383
|
+
uid: accountId,
|
|
6384
|
+
clientId: clientId,
|
|
6385
|
+
reason: 'scope_not_unlocked_for_client',
|
|
6386
|
+
durationMs: Date.now() - startedAt
|
|
6387
|
+
}, this._logger);
|
|
6388
|
+
res.json({
|
|
6389
|
+
redirectTo: redirectTo2
|
|
6390
|
+
});
|
|
6391
|
+
return [
|
|
6392
|
+
2
|
|
6393
|
+
];
|
|
6394
|
+
case 16:
|
|
6395
|
+
// Required gate: a scope a client's profiles force-require (`require: 'required'`) must be present
|
|
6396
|
+
// in the request. Reject when the client did not request a required scope.
|
|
6397
|
+
missingRequiredScopes = Array.from(clientRequiredScopes).filter(function(scope) {
|
|
6398
|
+
return !requestedOIDCScopeSet.has(scope);
|
|
6399
|
+
});
|
|
6400
|
+
if (!(missingRequiredScopes.length > 0)) return [
|
|
6401
|
+
3,
|
|
6402
|
+
18
|
|
6403
|
+
];
|
|
6404
|
+
return [
|
|
6405
|
+
4,
|
|
6406
|
+
this.oidcInteractionService.finishInteractionByUid(uid, {
|
|
6407
|
+
error: 'access_denied',
|
|
6408
|
+
error_description: "This client must request the required scope(s): ".concat(missingRequiredScopes.join(', '), ".")
|
|
6409
|
+
}, {
|
|
6410
|
+
mergeWithLastSubmission: true
|
|
6411
|
+
})
|
|
6412
|
+
];
|
|
6413
|
+
case 17:
|
|
6414
|
+
_ref7 = _state.sent(), redirectTo3 = _ref7.returnTo;
|
|
6415
|
+
emitOidcAnalyticsEvent(this._analytics, {
|
|
6416
|
+
type: 'consent',
|
|
6417
|
+
isSuccessful: false,
|
|
6418
|
+
uid: accountId,
|
|
6419
|
+
clientId: clientId,
|
|
6420
|
+
reason: 'required_scope_missing',
|
|
6421
|
+
durationMs: Date.now() - startedAt
|
|
6422
|
+
}, this._logger);
|
|
6423
|
+
res.json({
|
|
6424
|
+
redirectTo: redirectTo3
|
|
6425
|
+
});
|
|
6426
|
+
return [
|
|
6427
|
+
2
|
|
6428
|
+
];
|
|
6429
|
+
case 18:
|
|
6296
6430
|
// Resolve the requested login duration up-front. The configured Grant TTL function (in
|
|
6297
6431
|
// OidcService.buildProviderConfiguration) only fires when oidc-provider's koa middleware
|
|
6298
6432
|
// drives `grant.save()`, so its `ctx.oidc.params` lookup of `dbx_session_ttl` returns
|
|
6299
6433
|
// undefined when the consent submit runs in this controller. We pre-set `expiresIn` on
|
|
6300
6434
|
// newly-created grants so they persist with the correct (tiered) TTL.
|
|
6301
6435
|
requestedRawTtl = params[DBX_FIREBASE_SERVER_OIDC_SESSION_TTL_PARAM];
|
|
6302
|
-
|
|
6303
|
-
4,
|
|
6304
|
-
this.oidcService.findClientPayload(clientId)
|
|
6305
|
-
];
|
|
6306
|
-
case 14:
|
|
6307
|
-
clientPayload = _state.sent();
|
|
6308
|
-
clientMaxSessionTtl = (_ref2 = clientPayload === null || clientPayload === void 0 ? void 0 : clientPayload.dbx_max_session_ttl) !== null && _ref2 !== void 0 ? _ref2 : undefined;
|
|
6436
|
+
clientMaxSessionTtl = (_ref3 = clientPayload === null || clientPayload === void 0 ? void 0 : clientPayload.dbx_max_session_ttl) !== null && _ref3 !== void 0 ? _ref3 : undefined;
|
|
6309
6437
|
expiresInSeconds = this.oidcService.resolveLoginDurationForGrant(requestedRawTtl, {
|
|
6310
6438
|
dbx_max_session_ttl: clientMaxSessionTtl
|
|
6311
6439
|
}, {
|
|
@@ -6314,28 +6442,30 @@ var OidcInteractionController_1;
|
|
|
6314
6442
|
});
|
|
6315
6443
|
if (!(existingGrant !== null && existingGrant !== void 0)) return [
|
|
6316
6444
|
3,
|
|
6317
|
-
|
|
6445
|
+
19
|
|
6318
6446
|
];
|
|
6319
6447
|
_tmp2 = existingGrant;
|
|
6320
6448
|
return [
|
|
6321
6449
|
3,
|
|
6322
|
-
|
|
6450
|
+
21
|
|
6323
6451
|
];
|
|
6324
|
-
case
|
|
6452
|
+
case 19:
|
|
6325
6453
|
return [
|
|
6326
6454
|
4,
|
|
6327
6455
|
this.oidcInteractionService.findOrCreateGrant(interaction.grantId, accountId, clientId, expiresInSeconds)
|
|
6328
6456
|
];
|
|
6329
|
-
case
|
|
6457
|
+
case 20:
|
|
6330
6458
|
_tmp2 = _state.sent();
|
|
6331
|
-
_state.label =
|
|
6332
|
-
case
|
|
6459
|
+
_state.label = 21;
|
|
6460
|
+
case 21:
|
|
6333
6461
|
grant = _tmp2;
|
|
6334
6462
|
if (missingOIDCScope.length > 0) {
|
|
6463
|
+
// Force-grant the client's required profile scopes (in addition to `openid`) so they cannot be
|
|
6464
|
+
// dropped at consent — the required gate above already guarantees they were requested.
|
|
6335
6465
|
_resolveEffectiveSubset = resolveEffectiveSubset({
|
|
6336
6466
|
missing: missingOIDCScope,
|
|
6337
6467
|
requestedSubset: body.grantedOIDCScopes,
|
|
6338
|
-
alwaysGranted: ALWAYS_GRANTED_OIDC_SCOPES,
|
|
6468
|
+
alwaysGranted: _to_consumable_array$1(ALWAYS_GRANTED_OIDC_SCOPES).concat(_to_consumable_array$1(clientRequiredScopes)),
|
|
6339
6469
|
alreadyEncountered: encounteredOIDCScopes
|
|
6340
6470
|
}), granted = _resolveEffectiveSubset.granted, rejected = _resolveEffectiveSubset.rejected;
|
|
6341
6471
|
if (granted.length > 0) {
|
|
@@ -6432,7 +6562,7 @@ var OidcInteractionController_1;
|
|
|
6432
6562
|
4,
|
|
6433
6563
|
grant.save()
|
|
6434
6564
|
];
|
|
6435
|
-
case
|
|
6565
|
+
case 22:
|
|
6436
6566
|
grantId = _state.sent();
|
|
6437
6567
|
return [
|
|
6438
6568
|
4,
|
|
@@ -6444,8 +6574,8 @@ var OidcInteractionController_1;
|
|
|
6444
6574
|
mergeWithLastSubmission: true
|
|
6445
6575
|
})
|
|
6446
6576
|
];
|
|
6447
|
-
case
|
|
6448
|
-
|
|
6577
|
+
case 23:
|
|
6578
|
+
_ref8 = _state.sent(), redirectTo4 = _ref8.returnTo;
|
|
6449
6579
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6450
6580
|
type: 'consent',
|
|
6451
6581
|
isSuccessful: true,
|
|
@@ -6457,13 +6587,13 @@ var OidcInteractionController_1;
|
|
|
6457
6587
|
durationMs: Date.now() - startedAt
|
|
6458
6588
|
}, this._logger);
|
|
6459
6589
|
res.json({
|
|
6460
|
-
redirectTo:
|
|
6590
|
+
redirectTo: redirectTo4
|
|
6461
6591
|
});
|
|
6462
6592
|
return [
|
|
6463
6593
|
3,
|
|
6464
|
-
|
|
6594
|
+
25
|
|
6465
6595
|
];
|
|
6466
|
-
case
|
|
6596
|
+
case 24:
|
|
6467
6597
|
err = _state.sent();
|
|
6468
6598
|
emitOidcAnalyticsEvent(this._analytics, {
|
|
6469
6599
|
type: 'consent',
|
|
@@ -6478,7 +6608,7 @@ var OidcInteractionController_1;
|
|
|
6478
6608
|
throw err;
|
|
6479
6609
|
}
|
|
6480
6610
|
throw new HttpException('Consent interaction failed', HttpStatus.BAD_REQUEST);
|
|
6481
|
-
case
|
|
6611
|
+
case 25:
|
|
6482
6612
|
return [
|
|
6483
6613
|
2
|
|
6484
6614
|
];
|
|
@@ -7646,39 +7776,4 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
7646
7776
|
};
|
|
7647
7777
|
}
|
|
7648
7778
|
|
|
7649
|
-
|
|
7650
|
-
* Builds a {@link AssertModelCrudRequestFunction} that rejects callModel requests
|
|
7651
|
-
* lacking the OIDC scope mapped from the call type.
|
|
7652
|
-
*
|
|
7653
|
-
* Bypasses the check (no-op) when the request is not OIDC-authenticated — i.e.
|
|
7654
|
-
* when {@link getOidcScopesFromRequest} returns `undefined` because there is no
|
|
7655
|
-
* `auth.token.scope` claim on the request. Regular Firebase ID-token callers are
|
|
7656
|
-
* unaffected and continue to be gated by auth roles.
|
|
7657
|
-
*
|
|
7658
|
-
* Bypasses the check for custom (non-CRUD) call types so app-specific verbs
|
|
7659
|
-
* remain unrestricted unless an app wires its own assertion.
|
|
7660
|
-
*
|
|
7661
|
-
* Wire as the `preAssert` of {@link onCallModel}.
|
|
7662
|
-
*
|
|
7663
|
-
* @returns The pre-assertion function ready to plug into `OnCallModelConfig.preAssert`.
|
|
7664
|
-
*/ function oidcCallModelScopePreAssert() {
|
|
7665
|
-
var fn = function fn(context) {
|
|
7666
|
-
var requiredScope = callModelOidcScopeForCallType(context.call);
|
|
7667
|
-
var scopes = requiredScope == null ? undefined : getOidcScopesFromRequest(context.request);
|
|
7668
|
-
var isMissingScope = requiredScope != null && scopes != null && !scopes.has(requiredScope);
|
|
7669
|
-
if (isMissingScope) {
|
|
7670
|
-
throw forbiddenError({
|
|
7671
|
-
status: 403,
|
|
7672
|
-
code: CALL_MODEL_MISSING_OIDC_SCOPE_ERROR_CODE,
|
|
7673
|
-
message: "Missing required OIDC scope for callModel: ".concat(requiredScope),
|
|
7674
|
-
data: {
|
|
7675
|
-
requiredScope: requiredScope,
|
|
7676
|
-
call: context.call
|
|
7677
|
-
}
|
|
7678
|
-
});
|
|
7679
|
-
}
|
|
7680
|
-
};
|
|
7681
|
-
return fn;
|
|
7682
|
-
}
|
|
7683
|
-
|
|
7684
|
-
export { DEFAULT_APP_OAUTH_CONSENT_PATH_PART, DEFAULT_APP_OAUTH_INTERACTION_PATH, DEFAULT_APP_OAUTH_LOGIN_PATH_PART, DEFAULT_MAX_ADMIN_LOGIN_DURATION_SECONDS, DEFAULT_MAX_NONADMIN_LOGIN_DURATION_SECONDS, DEFAULT_MAX_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_MAX_SERVICE_TOKEN_LOGIN_DURATION_SECONDS, DEFAULT_MIN_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_OIDC_ANALYTICS_EVENT_NAMES, DEFAULT_OIDC_ANALYTICS_EVENT_NAME_PREFIX, DEFAULT_OIDC_CODE_CHALLENGE_METHODS, DEFAULT_OIDC_ID_TOKEN_SIGNING_ALG_VALUES, DEFAULT_OIDC_ISSUER_PATH, DEFAULT_OIDC_ROUTES, DEFAULT_OIDC_SUBJECT_TYPES, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DEFAULT_OIDC_TOKEN_LIFETIMES, DEFAULT_ROTATED_KEY_MAX_AGE, FIREBASE_SERVER_OIDC_ANALYTICS_CONFIG, FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerOidcAnalyticsService, GRANTABLE_MODEL_NAMES, JwksFirestoreCollections, JwksKeyDocument, JwksService, JwksServiceConfig, JwksServiceStorageConfig, OIDC_ANALYTICS_SERVICE, OIDC_ENCRYPTED_PAYLOAD_FIELDS, OIDC_JSON_RENDER_ERROR_FUNCTION, OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY, OidcAccountService, OidcAccountServiceDelegate, OidcAccountServiceUserContext, OidcAnalyticsService, OidcAuth, OidcAuthBearerTokenMiddleware, OidcAuthMiddlewareConfig, OidcClientService, OidcEncryptionService, OidcInteractionController, OidcInteractionService, OidcModelServerActions, OidcModuleConfig, OidcProviderConfigService, OidcProviderController, OidcServerFirestoreCollections, OidcService, OidcWellKnownController, activeJwksKeysQuery, allOidcScopesStringForProviderConfig, appOidcAnalyticsModuleMetadata, appOidcModelModuleMetadata, applyOidcAuthMiddleware, applyOidcCorsMiddleware, buildBearerChallenge, buildFirebaseServerMcpResourceServer, createAdapterFactory, createOidcClientFactory, deleteOidcClientFactory, deleteOidcTokenFactory, deriveResourceMetadataUrlFromEnv, emitOidcAnalyticsEvent, getOidcScopesFromRequest, jwksKeyCollectionReference, jwksKeyConverter, jwksKeyFirestoreCollection, jwksKeyIdentity, jwksKeysWithStatusQuery, nonRetiredJwksKeysQuery, noopOidcAnalyticsService, oidcCallModelScopePreAssert, oidcCorsOriginDelegate, oidcFirestoreCollectionsFactory, oidcModelServerActions, oidcModelServerActionsFactory, oidcModuleConfigFactory, oidcModuleMetadata, resolveEffectiveSubset, rotateOidcClientSecretFactory, rotatedJwksKeysQuery, updateOidcClientFactory };
|
|
7779
|
+
export { DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA, DEFAULT_APP_OAUTH_CONSENT_PATH_PART, DEFAULT_APP_OAUTH_INTERACTION_PATH, DEFAULT_APP_OAUTH_LOGIN_PATH_PART, DEFAULT_MAX_ADMIN_LOGIN_DURATION_SECONDS, DEFAULT_MAX_NONADMIN_LOGIN_DURATION_SECONDS, DEFAULT_MAX_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_MAX_SERVICE_TOKEN_LOGIN_DURATION_SECONDS, DEFAULT_MIN_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_OIDC_ANALYTICS_EVENT_NAMES, DEFAULT_OIDC_ANALYTICS_EVENT_NAME_PREFIX, DEFAULT_OIDC_CODE_CHALLENGE_METHODS, DEFAULT_OIDC_ID_TOKEN_SIGNING_ALG_VALUES, DEFAULT_OIDC_ISSUER_PATH, DEFAULT_OIDC_ROUTES, DEFAULT_OIDC_SUBJECT_TYPES, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DEFAULT_OIDC_TOKEN_LIFETIMES, DEFAULT_ROTATED_KEY_MAX_AGE, FIREBASE_SERVER_OIDC_ANALYTICS_CONFIG, FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerOidcAnalyticsService, GRANTABLE_MODEL_NAMES, JwksFirestoreCollections, JwksKeyDocument, JwksService, JwksServiceConfig, JwksServiceStorageConfig, OIDC_ANALYTICS_SERVICE, OIDC_ENCRYPTED_PAYLOAD_FIELDS, OIDC_JSON_RENDER_ERROR_FUNCTION, OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY, OidcAccountService, OidcAccountServiceDelegate, OidcAccountServiceUserContext, OidcAnalyticsService, OidcAuth, OidcAuthBearerTokenMiddleware, OidcAuthMiddlewareConfig, OidcClientService, OidcEncryptionService, OidcInteractionController, OidcInteractionService, OidcModelServerActions, OidcModuleConfig, OidcProviderConfigService, OidcProviderController, OidcServerFirestoreCollections, OidcService, OidcWellKnownController, activeJwksKeysQuery, allOidcScopesStringForProviderConfig, appOidcAnalyticsModuleMetadata, appOidcModelModuleMetadata, applyOidcAuthMiddleware, applyOidcCorsMiddleware, buildBearerChallenge, buildFirebaseServerMcpResourceServer, createAdapterFactory, createOidcClientFactory, deleteOidcClientFactory, deleteOidcTokenFactory, deriveResourceMetadataUrlFromEnv, emitOidcAnalyticsEvent, getOidcScopesFromRequest, jwksKeyCollectionReference, jwksKeyConverter, jwksKeyFirestoreCollection, jwksKeyIdentity, jwksKeysWithStatusQuery, nonRetiredJwksKeysQuery, noopOidcAnalyticsService, oidcClientProviderProfileScopes, oidcCorsOriginDelegate, oidcFirestoreCollectionsFactory, oidcModelServerActions, oidcModelServerActionsFactory, oidcModuleConfigFactory, oidcModuleMetadata, resolveEffectiveSubset, rotateOidcClientSecretFactory, rotatedJwksKeysQuery, updateOidcClientFactory };
|
package/oidc/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/oidc",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.30.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/analytics": "13.
|
|
6
|
-
"@dereekb/date": "13.
|
|
7
|
-
"@dereekb/firebase": "13.
|
|
8
|
-
"@dereekb/firebase-server": "13.
|
|
9
|
-
"@dereekb/model": "13.
|
|
10
|
-
"@dereekb/nestjs": "13.
|
|
11
|
-
"@dereekb/rxjs": "13.
|
|
12
|
-
"@dereekb/util": "13.
|
|
13
|
-
"@dereekb/zoho": "13.
|
|
5
|
+
"@dereekb/analytics": "13.30.0",
|
|
6
|
+
"@dereekb/date": "13.30.0",
|
|
7
|
+
"@dereekb/firebase": "13.30.0",
|
|
8
|
+
"@dereekb/firebase-server": "13.30.0",
|
|
9
|
+
"@dereekb/model": "13.30.0",
|
|
10
|
+
"@dereekb/nestjs": "13.30.0",
|
|
11
|
+
"@dereekb/rxjs": "13.30.0",
|
|
12
|
+
"@dereekb/util": "13.30.0",
|
|
13
|
+
"@dereekb/zoho": "13.30.0",
|
|
14
14
|
"@nestjs/common": "^11.1.19",
|
|
15
15
|
"@nestjs/config": "^4.0.4",
|
|
16
16
|
"express": "^5.2.1",
|
package/oidc/src/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Configuration } from 'oidc-provider';
|
|
2
2
|
import { type WebsitePath, type SlashPath, type Seconds } from '@dereekb/util';
|
|
3
|
-
import { type OidcScope, type OidcTokenEndpointAuthMethod } from '@dereekb/firebase';
|
|
3
|
+
import { type OidcProviderProfile, type OidcScope, type OidcTokenEndpointAuthMethod } from '@dereekb/firebase';
|
|
4
4
|
import { type JwksServiceConfig } from './service/oidc.jwks.service';
|
|
5
5
|
import { type JwksKeyConverterConfig } from './model';
|
|
6
6
|
/**
|
|
@@ -104,6 +104,19 @@ export interface OidcProviderConfig<S extends OidcScope = OidcScope> {
|
|
|
104
104
|
* All other grants keep oidc-provider's default rotation behavior.
|
|
105
105
|
*/
|
|
106
106
|
readonly nonRotatingScopes?: readonly string[];
|
|
107
|
+
/**
|
|
108
|
+
* Named provider profiles that unlock (and optionally force-require) scopes for the OIDC clients
|
|
109
|
+
* they are assigned to. Any scope referenced by a profile is treated as restricted: a client may
|
|
110
|
+
* only obtain it when one of its assigned profiles (persisted as `dbx_provider_profiles` client
|
|
111
|
+
* metadata) unlocks it. A profile scope marked `require: 'required'` is force-required — surfaced
|
|
112
|
+
* as a required scope at consent and hard-rejected if not granted.
|
|
113
|
+
*
|
|
114
|
+
* Keeps the generic package app-agnostic: apps declare their profiles statically and list them
|
|
115
|
+
* here, rather than the package hard-coding any profile or scope name. This gate is independent of
|
|
116
|
+
* {@link adminOnlyScopes} (which gates by the resolving user's admin status); a scope may be
|
|
117
|
+
* subject to both.
|
|
118
|
+
*/
|
|
119
|
+
readonly providerProfiles?: readonly OidcProviderProfile<S>[];
|
|
107
120
|
}
|
|
108
121
|
/**
|
|
109
122
|
* Returns the space-delimited list of every scope declared on `providerConfig.claims`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type OidcProviderProfile, type OidcScope, type OidcProviderProfileKey } from '@dereekb/firebase';
|
|
2
|
+
/**
|
|
3
|
+
* Custom oidc-provider client metadata field holding the {@link OidcProviderProfile} keys assigned
|
|
4
|
+
* to a client. Registered via `extraClientMetadata` and persisted on the client's `OidcEntry` payload.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DBX_FIREBASE_SERVER_OIDC_PROVIDER_PROFILES_CLIENT_METADATA = "dbx_provider_profiles";
|
|
7
|
+
/**
|
|
8
|
+
* The scopes a client with the given assigned profile keys is allowed/required to obtain, resolved
|
|
9
|
+
* against the provider-profile registry.
|
|
10
|
+
*/
|
|
11
|
+
export interface OidcClientProviderProfileScopes<S extends OidcScope = OidcScope> {
|
|
12
|
+
/**
|
|
13
|
+
* Scopes unlocked for the client (the union of its assigned profiles' scopes).
|
|
14
|
+
*/
|
|
15
|
+
readonly unlocked: Set<S>;
|
|
16
|
+
/**
|
|
17
|
+
* Scopes the client's profiles force-require (`require: 'required'`).
|
|
18
|
+
*/
|
|
19
|
+
readonly required: Set<S>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolves the unlocked + required scope sets for a client from the provider-profile registry and
|
|
23
|
+
* the profile keys assigned to that client.
|
|
24
|
+
*
|
|
25
|
+
* @param providerProfiles - The provider-profile registry (from {@link OidcProviderConfig.providerProfiles}).
|
|
26
|
+
* @param clientProfileKeys - The profile keys assigned to the client (its `dbx_provider_profiles`).
|
|
27
|
+
* @returns The unlocked and required scope sets for the client.
|
|
28
|
+
*/
|
|
29
|
+
export declare function oidcClientProviderProfileScopes<S extends OidcScope = OidcScope>(providerProfiles: readonly OidcProviderProfile<S>[] | undefined, clientProfileKeys: readonly OidcProviderProfileKey[] | undefined): OidcClientProviderProfileScopes<S>;
|
|
@@ -33,7 +33,7 @@ export type OidcAuthenticatedRequest = FirebaseServerAuthenticatedRequest<OidcAu
|
|
|
33
33
|
* `request.auth.token.scope` for OIDC callers and is `undefined` for non-OIDC
|
|
34
34
|
* (regular Firebase ID-token) callers.
|
|
35
35
|
*
|
|
36
|
-
* Returning `undefined` for non-OIDC callers lets
|
|
36
|
+
* Returning `undefined` for non-OIDC callers lets consumers (e.g. the MCP tool-visibility filter)
|
|
37
37
|
* skip scope enforcement instead of falsely treating the missing claim as "no scopes granted".
|
|
38
38
|
*
|
|
39
39
|
* The parameter is intentionally typed as `unknown` because `DecodedIdToken` (Firebase
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.30.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"exports": {
|
|
6
6
|
"./test": {
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
"types": "./src/index.d.ts",
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@cantoo/pdf-lib": "^2.6.5",
|
|
60
|
-
"@dereekb/analytics": "13.
|
|
61
|
-
"@dereekb/date": "13.
|
|
62
|
-
"@dereekb/dbx-core": "13.
|
|
63
|
-
"@dereekb/firebase": "13.
|
|
64
|
-
"@dereekb/model": "13.
|
|
65
|
-
"@dereekb/nestjs": "13.
|
|
66
|
-
"@dereekb/rxjs": "13.
|
|
67
|
-
"@dereekb/util": "13.
|
|
68
|
-
"@dereekb/zoho": "13.
|
|
60
|
+
"@dereekb/analytics": "13.30.0",
|
|
61
|
+
"@dereekb/date": "13.30.0",
|
|
62
|
+
"@dereekb/dbx-core": "13.30.0",
|
|
63
|
+
"@dereekb/firebase": "13.30.0",
|
|
64
|
+
"@dereekb/model": "13.30.0",
|
|
65
|
+
"@dereekb/nestjs": "13.30.0",
|
|
66
|
+
"@dereekb/rxjs": "13.30.0",
|
|
67
|
+
"@dereekb/util": "13.30.0",
|
|
68
|
+
"@dereekb/zoho": "13.30.0",
|
|
69
69
|
"@google-cloud/firestore": "^7.11.6",
|
|
70
70
|
"@google-cloud/storage": "^7.19.0",
|
|
71
71
|
"@modelcontextprotocol/sdk": "1.29.0",
|