@dereekb/firebase-server 13.11.5 → 13.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/mailgun",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.11.5",
6
- "@dereekb/firebase": "13.11.5",
7
- "@dereekb/firebase-server": "13.11.5",
8
- "@dereekb/date": "13.11.5",
9
- "@dereekb/nestjs": "13.11.5",
10
- "@dereekb/model": "13.11.5",
11
- "@dereekb/rxjs": "13.11.5",
12
- "@dereekb/util": "13.11.5"
5
+ "@dereekb/analytics": "13.11.7",
6
+ "@dereekb/firebase": "13.11.7",
7
+ "@dereekb/firebase-server": "13.11.7",
8
+ "@dereekb/date": "13.11.7",
9
+ "@dereekb/nestjs": "13.11.7",
10
+ "@dereekb/model": "13.11.7",
11
+ "@dereekb/rxjs": "13.11.7",
12
+ "@dereekb/util": "13.11.7"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/model",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.11.5",
6
- "@dereekb/date": "13.11.5",
7
- "@dereekb/firebase": "13.11.5",
8
- "@dereekb/firebase-server": "13.11.5",
9
- "@dereekb/model": "13.11.5",
10
- "@dereekb/nestjs": "13.11.5",
11
- "@dereekb/rxjs": "13.11.5",
12
- "@dereekb/util": "13.11.5",
5
+ "@dereekb/analytics": "13.11.7",
6
+ "@dereekb/date": "13.11.7",
7
+ "@dereekb/firebase": "13.11.7",
8
+ "@dereekb/firebase-server": "13.11.7",
9
+ "@dereekb/model": "13.11.7",
10
+ "@dereekb/nestjs": "13.11.7",
11
+ "@dereekb/rxjs": "13.11.7",
12
+ "@dereekb/util": "13.11.7",
13
13
  "@nestjs/common": "^11.1.19",
14
14
  "@nestjs/config": "^4.0.4",
15
15
  "archiver": "^7.0.1",
package/oidc/index.cjs.js CHANGED
@@ -4452,6 +4452,55 @@ var _logger = new common.Logger('applyOidcAuthMiddleware');
4452
4452
  _logger.debug("Applied OAuth bearer token middleware for paths: ".concat(protectedPaths.join(', ')));
4453
4453
  }
4454
4454
 
4455
+ // MARK: Express-Level Helper
4456
+ /**
4457
+ * Enables CORS on the NestJS app for OIDC cross-origin requests originating from the frontend.
4458
+ *
4459
+ * When the OIDC issuer lives on a different origin than the frontend app (e.g. the frontend is
4460
+ * `https://app.example.com` and the OIDC server is at `https://api.example.com`), the frontend's
4461
+ * `DbxFirebaseOidcInteractionService` issues cross-origin POSTs to `/interaction/{uid}/login`
4462
+ * and `/interaction/{uid}/consent`. Because the POST body is `application/json`, the browser
4463
+ * sends a CORS preflight. Without an `Access-Control-Allow-Origin` reply the preflight fails,
4464
+ * the POST never reaches the server, and the OAuth flow stalls before `finishInteractionByUid`
4465
+ * can run.
4466
+ *
4467
+ * Origin is sourced from `FirebaseServerEnvService.appUrl`, which is the authoritative frontend
4468
+ * origin per environment. Single-origin deployments (e.g. local dev where the frontend and the
4469
+ * OIDC server share `http://localhost:9010`) still benefit: their cross-origin requests are
4470
+ * actually same-origin and CORS is a no-op.
4471
+ *
4472
+ * Credentials are intentionally NOT enabled (`Access-Control-Allow-Credentials` stays off). The
4473
+ * `/interaction/{uid}/*` POSTs carry the Firebase ID token in the JSON body, not in cookies, so
4474
+ * we keep the CORS surface minimal.
4475
+ *
4476
+ * @param nestApp - the NestJS application to configure.
4477
+ *
4478
+ * @example
4479
+ * ```ts
4480
+ * export const APP_NEST_SERVER_CONFIG: NestServerInstanceConfig<AppModule> = {
4481
+ * moduleClass: AppModule,
4482
+ * configureNestServerInstance: (nestApp) => {
4483
+ * applyOidcCorsMiddleware(nestApp);
4484
+ * applyOidcAuthMiddleware(nestApp);
4485
+ * }
4486
+ * };
4487
+ * ```
4488
+ */ function applyOidcCorsMiddleware(nestApp) {
4489
+ var envService = nestApp.get(firebaseServer.FirebaseServerEnvService);
4490
+ var origin = envService.appUrl;
4491
+ if (!origin) {
4492
+ return;
4493
+ }
4494
+ nestApp.enableCors({
4495
+ origin: origin,
4496
+ methods: [
4497
+ 'GET',
4498
+ 'POST',
4499
+ 'OPTIONS'
4500
+ ]
4501
+ });
4502
+ }
4503
+
4455
4504
  // MARK: Scopes
4456
4505
  /**
4457
4506
  * Reads the set of OIDC scopes carried by a callable request's bearer token.
@@ -6233,27 +6282,76 @@ function _unsupported_iterable_to_array(o, minLen) {
6233
6282
  'interaction/{*path}'
6234
6283
  ];
6235
6284
  // MARK: Provider Factories
6285
+ /**
6286
+ * Extracts the origin (protocol + host + port) from `envService.appApiUrl`, when it points at a
6287
+ * different origin than `envService.appUrl`. Used to root the OIDC issuer at the API host when
6288
+ * the frontend and the OIDC server live on different origins.
6289
+ *
6290
+ * Returns `undefined` if `appApiUrl` is missing, equal to `appUrl`, or shares its origin — the
6291
+ * caller then falls back to `appUrl` (the single-origin default). The compare is on the parsed
6292
+ * URL origin so a default `appApiUrl = "${appUrl}/api"` is treated as the same origin.
6293
+ *
6294
+ * @param envService - the Firebase server environment service.
6295
+ * @returns The API origin (no trailing slash) when distinct from the frontend origin, otherwise `undefined`.
6296
+ *
6297
+ * @example
6298
+ * ```typescript
6299
+ * // appUrl = 'https://app.example.com', appApiUrl = 'https://app.example.com/api'
6300
+ * // → undefined (same origin; fall back to appUrl)
6301
+ *
6302
+ * // appUrl = 'https://app.example.com', appApiUrl = 'https://api.example.com'
6303
+ * // → 'https://api.example.com'
6304
+ * ```
6305
+ */ function resolveOidcIssuerOriginFromEnv(envService) {
6306
+ var appUrl = envService.appUrl;
6307
+ var appApiUrl = envService.appApiUrl;
6308
+ var result;
6309
+ if (appUrl && appApiUrl) {
6310
+ try {
6311
+ var appOrigin = new URL(appUrl).origin;
6312
+ var apiOrigin = new URL(appApiUrl).origin;
6313
+ if (apiOrigin !== appOrigin) {
6314
+ result = apiOrigin;
6315
+ }
6316
+ } catch (unused) {
6317
+ // appUrl / appApiUrl validity is enforced elsewhere; ignore parse errors here so the
6318
+ // caller's appUrl-based fallback path still runs.
6319
+ }
6320
+ }
6321
+ return result;
6322
+ }
6236
6323
  /**
6237
6324
  * Factory that builds {@link OidcModuleConfig} from environment variables and the app's {@link FirebaseServerEnvService}.
6238
6325
  *
6239
- * Derives the issuer URL from `appUrl` + the optional `OIDC_ISSUER_PATH` env var (defaults to `/oidc`).
6240
- * Reads the JWKS encryption secret from `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments,
6241
- * a deterministic fallback is used.
6326
+ * Derives the issuer URL from `appUrl` (or, when set to a distinct origin, the origin of `appApiUrl`)
6327
+ * plus {@link DEFAULT_OIDC_ISSUER_PATH} (defaults to `/oidc`). Reads the JWKS encryption secret from
6328
+ * `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments, a deterministic fallback is used.
6329
+ *
6330
+ * The issuer can also be overridden directly by passing `issuer` on the `config` block to
6331
+ * {@link oidcModuleMetadata}; the override wins over the factory-derived value.
6242
6332
  *
6243
6333
  * @param configService - the NestJS ConfigService for reading environment variables
6244
6334
  * @param envService - the Firebase server environment service for app URL and env detection
6245
6335
  * @returns the constructed OidcModuleConfig
6246
- * @throws {Error} When `appUrl` is missing, lacks an HTTP prefix, or the encryption secret is invalid.
6336
+ * @throws {Error} When `appUrl` is missing, the resolved issuer lacks an HTTP prefix, or the encryption secret is invalid.
6247
6337
  */ function oidcModuleConfigFactory(configService, envService) {
6248
- var _configService_get;
6338
+ var _resolveOidcIssuerOriginFromEnv, _configService_get;
6249
6339
  var appUrl = envService.appUrl;
6250
6340
  if (!appUrl) {
6251
6341
  throw new Error('oidcModuleConfigFactory: appUrl is required on the server environment config.');
6252
6342
  }
6253
6343
  var issuerPath = DEFAULT_OIDC_ISSUER_PATH;
6254
- var issuer = "".concat(appUrl).concat(issuerPath);
6344
+ // The issuer base is the origin where the OIDC server lives. When `appApiUrl` is set on
6345
+ // a different origin from `appUrl` (e.g., the frontend lives on `https://app.example.com`
6346
+ // while the OIDC server lives on `https://api.example.com`), use its origin so cookies
6347
+ // emitted by oidc-provider are scoped to the API host. Otherwise fall back to `appUrl` —
6348
+ // the common single-origin case where both the frontend and the OIDC server share a host.
6349
+ // Consumers can still override the resolved issuer entirely via the `config.issuer` field
6350
+ // on `oidcModuleMetadata({ config: { issuer: ... } })`.
6351
+ var issuerBase = (_resolveOidcIssuerOriginFromEnv = resolveOidcIssuerOriginFromEnv(envService)) !== null && _resolveOidcIssuerOriginFromEnv !== void 0 ? _resolveOidcIssuerOriginFromEnv : appUrl;
6352
+ var issuer = "".concat(issuerBase).concat(issuerPath);
6255
6353
  if (!util.hasHttpPrefix(issuer)) {
6256
- throw new Error("oidcModuleConfigFactory: appUrl must have an http(s) prefix. Received: ".concat(appUrl));
6354
+ throw new Error("oidcModuleConfigFactory: issuer must have an http(s) prefix. Received: ".concat(issuer));
6257
6355
  }
6258
6356
  var encryptionSecret = (_configService_get = configService.get(OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY)) !== null && _configService_get !== void 0 ? _configService_get : '';
6259
6357
  if (!nestjs.isValidAES256GCMEncryptionSecret(encryptionSecret)) {
@@ -6466,6 +6564,7 @@ exports.OidcServerFirestoreCollections = OidcServerFirestoreCollections;
6466
6564
  exports.activeJwksKeysQuery = activeJwksKeysQuery;
6467
6565
  exports.appOidcModelModuleMetadata = appOidcModelModuleMetadata;
6468
6566
  exports.applyOidcAuthMiddleware = applyOidcAuthMiddleware;
6567
+ exports.applyOidcCorsMiddleware = applyOidcCorsMiddleware;
6469
6568
  exports.createAdapterFactory = createAdapterFactory;
6470
6569
  exports.createOidcClientFactory = createOidcClientFactory;
6471
6570
  exports.deleteOidcClientFactory = deleteOidcClientFactory;
package/oidc/index.esm.js CHANGED
@@ -4450,6 +4450,55 @@ var _logger = new Logger('applyOidcAuthMiddleware');
4450
4450
  _logger.debug("Applied OAuth bearer token middleware for paths: ".concat(protectedPaths.join(', ')));
4451
4451
  }
4452
4452
 
4453
+ // MARK: Express-Level Helper
4454
+ /**
4455
+ * Enables CORS on the NestJS app for OIDC cross-origin requests originating from the frontend.
4456
+ *
4457
+ * When the OIDC issuer lives on a different origin than the frontend app (e.g. the frontend is
4458
+ * `https://app.example.com` and the OIDC server is at `https://api.example.com`), the frontend's
4459
+ * `DbxFirebaseOidcInteractionService` issues cross-origin POSTs to `/interaction/{uid}/login`
4460
+ * and `/interaction/{uid}/consent`. Because the POST body is `application/json`, the browser
4461
+ * sends a CORS preflight. Without an `Access-Control-Allow-Origin` reply the preflight fails,
4462
+ * the POST never reaches the server, and the OAuth flow stalls before `finishInteractionByUid`
4463
+ * can run.
4464
+ *
4465
+ * Origin is sourced from `FirebaseServerEnvService.appUrl`, which is the authoritative frontend
4466
+ * origin per environment. Single-origin deployments (e.g. local dev where the frontend and the
4467
+ * OIDC server share `http://localhost:9010`) still benefit: their cross-origin requests are
4468
+ * actually same-origin and CORS is a no-op.
4469
+ *
4470
+ * Credentials are intentionally NOT enabled (`Access-Control-Allow-Credentials` stays off). The
4471
+ * `/interaction/{uid}/*` POSTs carry the Firebase ID token in the JSON body, not in cookies, so
4472
+ * we keep the CORS surface minimal.
4473
+ *
4474
+ * @param nestApp - the NestJS application to configure.
4475
+ *
4476
+ * @example
4477
+ * ```ts
4478
+ * export const APP_NEST_SERVER_CONFIG: NestServerInstanceConfig<AppModule> = {
4479
+ * moduleClass: AppModule,
4480
+ * configureNestServerInstance: (nestApp) => {
4481
+ * applyOidcCorsMiddleware(nestApp);
4482
+ * applyOidcAuthMiddleware(nestApp);
4483
+ * }
4484
+ * };
4485
+ * ```
4486
+ */ function applyOidcCorsMiddleware(nestApp) {
4487
+ var envService = nestApp.get(FirebaseServerEnvService);
4488
+ var origin = envService.appUrl;
4489
+ if (!origin) {
4490
+ return;
4491
+ }
4492
+ nestApp.enableCors({
4493
+ origin: origin,
4494
+ methods: [
4495
+ 'GET',
4496
+ 'POST',
4497
+ 'OPTIONS'
4498
+ ]
4499
+ });
4500
+ }
4501
+
4453
4502
  // MARK: Scopes
4454
4503
  /**
4455
4504
  * Reads the set of OIDC scopes carried by a callable request's bearer token.
@@ -6231,27 +6280,76 @@ function _unsupported_iterable_to_array(o, minLen) {
6231
6280
  'interaction/{*path}'
6232
6281
  ];
6233
6282
  // MARK: Provider Factories
6283
+ /**
6284
+ * Extracts the origin (protocol + host + port) from `envService.appApiUrl`, when it points at a
6285
+ * different origin than `envService.appUrl`. Used to root the OIDC issuer at the API host when
6286
+ * the frontend and the OIDC server live on different origins.
6287
+ *
6288
+ * Returns `undefined` if `appApiUrl` is missing, equal to `appUrl`, or shares its origin — the
6289
+ * caller then falls back to `appUrl` (the single-origin default). The compare is on the parsed
6290
+ * URL origin so a default `appApiUrl = "${appUrl}/api"` is treated as the same origin.
6291
+ *
6292
+ * @param envService - the Firebase server environment service.
6293
+ * @returns The API origin (no trailing slash) when distinct from the frontend origin, otherwise `undefined`.
6294
+ *
6295
+ * @example
6296
+ * ```typescript
6297
+ * // appUrl = 'https://app.example.com', appApiUrl = 'https://app.example.com/api'
6298
+ * // → undefined (same origin; fall back to appUrl)
6299
+ *
6300
+ * // appUrl = 'https://app.example.com', appApiUrl = 'https://api.example.com'
6301
+ * // → 'https://api.example.com'
6302
+ * ```
6303
+ */ function resolveOidcIssuerOriginFromEnv(envService) {
6304
+ var appUrl = envService.appUrl;
6305
+ var appApiUrl = envService.appApiUrl;
6306
+ var result;
6307
+ if (appUrl && appApiUrl) {
6308
+ try {
6309
+ var appOrigin = new URL(appUrl).origin;
6310
+ var apiOrigin = new URL(appApiUrl).origin;
6311
+ if (apiOrigin !== appOrigin) {
6312
+ result = apiOrigin;
6313
+ }
6314
+ } catch (unused) {
6315
+ // appUrl / appApiUrl validity is enforced elsewhere; ignore parse errors here so the
6316
+ // caller's appUrl-based fallback path still runs.
6317
+ }
6318
+ }
6319
+ return result;
6320
+ }
6234
6321
  /**
6235
6322
  * Factory that builds {@link OidcModuleConfig} from environment variables and the app's {@link FirebaseServerEnvService}.
6236
6323
  *
6237
- * Derives the issuer URL from `appUrl` + the optional `OIDC_ISSUER_PATH` env var (defaults to `/oidc`).
6238
- * Reads the JWKS encryption secret from `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments,
6239
- * a deterministic fallback is used.
6324
+ * Derives the issuer URL from `appUrl` (or, when set to a distinct origin, the origin of `appApiUrl`)
6325
+ * plus {@link DEFAULT_OIDC_ISSUER_PATH} (defaults to `/oidc`). Reads the JWKS encryption secret from
6326
+ * `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments, a deterministic fallback is used.
6327
+ *
6328
+ * The issuer can also be overridden directly by passing `issuer` on the `config` block to
6329
+ * {@link oidcModuleMetadata}; the override wins over the factory-derived value.
6240
6330
  *
6241
6331
  * @param configService - the NestJS ConfigService for reading environment variables
6242
6332
  * @param envService - the Firebase server environment service for app URL and env detection
6243
6333
  * @returns the constructed OidcModuleConfig
6244
- * @throws {Error} When `appUrl` is missing, lacks an HTTP prefix, or the encryption secret is invalid.
6334
+ * @throws {Error} When `appUrl` is missing, the resolved issuer lacks an HTTP prefix, or the encryption secret is invalid.
6245
6335
  */ function oidcModuleConfigFactory(configService, envService) {
6246
- var _configService_get;
6336
+ var _resolveOidcIssuerOriginFromEnv, _configService_get;
6247
6337
  var appUrl = envService.appUrl;
6248
6338
  if (!appUrl) {
6249
6339
  throw new Error('oidcModuleConfigFactory: appUrl is required on the server environment config.');
6250
6340
  }
6251
6341
  var issuerPath = DEFAULT_OIDC_ISSUER_PATH;
6252
- var issuer = "".concat(appUrl).concat(issuerPath);
6342
+ // The issuer base is the origin where the OIDC server lives. When `appApiUrl` is set on
6343
+ // a different origin from `appUrl` (e.g., the frontend lives on `https://app.example.com`
6344
+ // while the OIDC server lives on `https://api.example.com`), use its origin so cookies
6345
+ // emitted by oidc-provider are scoped to the API host. Otherwise fall back to `appUrl` —
6346
+ // the common single-origin case where both the frontend and the OIDC server share a host.
6347
+ // Consumers can still override the resolved issuer entirely via the `config.issuer` field
6348
+ // on `oidcModuleMetadata({ config: { issuer: ... } })`.
6349
+ var issuerBase = (_resolveOidcIssuerOriginFromEnv = resolveOidcIssuerOriginFromEnv(envService)) !== null && _resolveOidcIssuerOriginFromEnv !== void 0 ? _resolveOidcIssuerOriginFromEnv : appUrl;
6350
+ var issuer = "".concat(issuerBase).concat(issuerPath);
6253
6351
  if (!hasHttpPrefix(issuer)) {
6254
- throw new Error("oidcModuleConfigFactory: appUrl must have an http(s) prefix. Received: ".concat(appUrl));
6352
+ throw new Error("oidcModuleConfigFactory: issuer must have an http(s) prefix. Received: ".concat(issuer));
6255
6353
  }
6256
6354
  var encryptionSecret = (_configService_get = configService.get(OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY)) !== null && _configService_get !== void 0 ? _configService_get : '';
6257
6355
  if (!isValidAES256GCMEncryptionSecret(encryptionSecret)) {
@@ -6431,4 +6529,4 @@ function _unsupported_iterable_to_array(o, minLen) {
6431
6529
  return fn;
6432
6530
  }
6433
6531
 
6434
- export { DEFAULT_APP_OAUTH_CONSENT_PATH_PART, DEFAULT_APP_OAUTH_INTERACTION_PATH, DEFAULT_APP_OAUTH_LOGIN_PATH_PART, DEFAULT_MAX_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_MIN_REQUESTED_LOGIN_DURATION_SECONDS, 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_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, GRANTABLE_MODEL_NAMES, JwksFirestoreCollections, JwksKeyDocument, JwksService, JwksServiceConfig, JwksServiceStorageConfig, OIDC_ENCRYPTED_PAYLOAD_FIELDS, OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY, OidcAccountService, OidcAccountServiceDelegate, OidcAccountServiceUserContext, OidcAuth, OidcAuthBearerTokenMiddleware, OidcAuthMiddlewareConfig, OidcClientService, OidcEncryptionService, OidcInteractionController, OidcInteractionService, OidcModelServerActions, OidcModuleConfig, OidcProviderConfigService, OidcProviderController, OidcServerFirestoreCollections, OidcService, OidcWellKnownController, activeJwksKeysQuery, appOidcModelModuleMetadata, applyOidcAuthMiddleware, createAdapterFactory, createOidcClientFactory, deleteOidcClientFactory, deleteOidcTokenFactory, getOidcScopesFromRequest, jwksKeyCollectionReference, jwksKeyConverter, jwksKeyFirestoreCollection, jwksKeyIdentity, jwksKeysWithStatusQuery, nonRetiredJwksKeysQuery, oidcCallModelScopePreAssert, oidcFirestoreCollectionsFactory, oidcModelServerActions, oidcModelServerActionsFactory, oidcModuleConfigFactory, oidcModuleMetadata, rotateOidcClientSecretFactory, rotatedJwksKeysQuery, updateOidcClientFactory };
6532
+ export { DEFAULT_APP_OAUTH_CONSENT_PATH_PART, DEFAULT_APP_OAUTH_INTERACTION_PATH, DEFAULT_APP_OAUTH_LOGIN_PATH_PART, DEFAULT_MAX_REQUESTED_LOGIN_DURATION_SECONDS, DEFAULT_MIN_REQUESTED_LOGIN_DURATION_SECONDS, 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_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, GRANTABLE_MODEL_NAMES, JwksFirestoreCollections, JwksKeyDocument, JwksService, JwksServiceConfig, JwksServiceStorageConfig, OIDC_ENCRYPTED_PAYLOAD_FIELDS, OIDC_JWKS_ENCRYPTION_SECRET_ENV_KEY, OidcAccountService, OidcAccountServiceDelegate, OidcAccountServiceUserContext, OidcAuth, OidcAuthBearerTokenMiddleware, OidcAuthMiddlewareConfig, OidcClientService, OidcEncryptionService, OidcInteractionController, OidcInteractionService, OidcModelServerActions, OidcModuleConfig, OidcProviderConfigService, OidcProviderController, OidcServerFirestoreCollections, OidcService, OidcWellKnownController, activeJwksKeysQuery, appOidcModelModuleMetadata, applyOidcAuthMiddleware, applyOidcCorsMiddleware, createAdapterFactory, createOidcClientFactory, deleteOidcClientFactory, deleteOidcTokenFactory, getOidcScopesFromRequest, jwksKeyCollectionReference, jwksKeyConverter, jwksKeyFirestoreCollection, jwksKeyIdentity, jwksKeysWithStatusQuery, nonRetiredJwksKeysQuery, oidcCallModelScopePreAssert, oidcFirestoreCollectionsFactory, oidcModelServerActions, oidcModelServerActionsFactory, oidcModuleConfigFactory, oidcModuleMetadata, rotateOidcClientSecretFactory, rotatedJwksKeysQuery, updateOidcClientFactory };
package/oidc/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/oidc",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.11.5",
6
- "@dereekb/date": "13.11.5",
7
- "@dereekb/firebase": "13.11.5",
8
- "@dereekb/firebase-server": "13.11.5",
9
- "@dereekb/model": "13.11.5",
10
- "@dereekb/nestjs": "13.11.5",
11
- "@dereekb/rxjs": "13.11.5",
12
- "@dereekb/util": "13.11.5",
13
- "@dereekb/zoho": "13.11.5",
5
+ "@dereekb/analytics": "13.11.7",
6
+ "@dereekb/date": "13.11.7",
7
+ "@dereekb/firebase": "13.11.7",
8
+ "@dereekb/firebase-server": "13.11.7",
9
+ "@dereekb/model": "13.11.7",
10
+ "@dereekb/nestjs": "13.11.7",
11
+ "@dereekb/rxjs": "13.11.7",
12
+ "@dereekb/util": "13.11.7",
13
+ "@dereekb/zoho": "13.11.7",
14
14
  "@nestjs/common": "^11.1.19",
15
15
  "@nestjs/config": "^4.0.4",
16
16
  "express": "^5.2.1",
@@ -1,3 +1,4 @@
1
1
  export * from './oauth-auth.decorator';
2
2
  export * from './oauth-auth.middleware';
3
3
  export * from './oauth-auth.module';
4
+ export * from './oauth-cors.module';
@@ -0,0 +1,35 @@
1
+ import { type INestApplication } from '@nestjs/common';
2
+ /**
3
+ * Enables CORS on the NestJS app for OIDC cross-origin requests originating from the frontend.
4
+ *
5
+ * When the OIDC issuer lives on a different origin than the frontend app (e.g. the frontend is
6
+ * `https://app.example.com` and the OIDC server is at `https://api.example.com`), the frontend's
7
+ * `DbxFirebaseOidcInteractionService` issues cross-origin POSTs to `/interaction/{uid}/login`
8
+ * and `/interaction/{uid}/consent`. Because the POST body is `application/json`, the browser
9
+ * sends a CORS preflight. Without an `Access-Control-Allow-Origin` reply the preflight fails,
10
+ * the POST never reaches the server, and the OAuth flow stalls before `finishInteractionByUid`
11
+ * can run.
12
+ *
13
+ * Origin is sourced from `FirebaseServerEnvService.appUrl`, which is the authoritative frontend
14
+ * origin per environment. Single-origin deployments (e.g. local dev where the frontend and the
15
+ * OIDC server share `http://localhost:9010`) still benefit: their cross-origin requests are
16
+ * actually same-origin and CORS is a no-op.
17
+ *
18
+ * Credentials are intentionally NOT enabled (`Access-Control-Allow-Credentials` stays off). The
19
+ * `/interaction/{uid}/*` POSTs carry the Firebase ID token in the JSON body, not in cookies, so
20
+ * we keep the CORS surface minimal.
21
+ *
22
+ * @param nestApp - the NestJS application to configure.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * export const APP_NEST_SERVER_CONFIG: NestServerInstanceConfig<AppModule> = {
27
+ * moduleClass: AppModule,
28
+ * configureNestServerInstance: (nestApp) => {
29
+ * applyOidcCorsMiddleware(nestApp);
30
+ * applyOidcAuthMiddleware(nestApp);
31
+ * }
32
+ * };
33
+ * ```
34
+ */
35
+ export declare function applyOidcCorsMiddleware(nestApp: INestApplication): void;
@@ -61,14 +61,17 @@ export declare const FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE: strin
61
61
  /**
62
62
  * Factory that builds {@link OidcModuleConfig} from environment variables and the app's {@link FirebaseServerEnvService}.
63
63
  *
64
- * Derives the issuer URL from `appUrl` + the optional `OIDC_ISSUER_PATH` env var (defaults to `/oidc`).
65
- * Reads the JWKS encryption secret from `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments,
66
- * a deterministic fallback is used.
64
+ * Derives the issuer URL from `appUrl` (or, when set to a distinct origin, the origin of `appApiUrl`)
65
+ * plus {@link DEFAULT_OIDC_ISSUER_PATH} (defaults to `/oidc`). Reads the JWKS encryption secret from
66
+ * `OIDC_JWKS_ENCRYPTION_SECRET`; in test environments, a deterministic fallback is used.
67
+ *
68
+ * The issuer can also be overridden directly by passing `issuer` on the `config` block to
69
+ * {@link oidcModuleMetadata}; the override wins over the factory-derived value.
67
70
  *
68
71
  * @param configService - the NestJS ConfigService for reading environment variables
69
72
  * @param envService - the Firebase server environment service for app URL and env detection
70
73
  * @returns the constructed OidcModuleConfig
71
- * @throws {Error} When `appUrl` is missing, lacks an HTTP prefix, or the encryption secret is invalid.
74
+ * @throws {Error} When `appUrl` is missing, the resolved issuer lacks an HTTP prefix, or the encryption secret is invalid.
72
75
  */
73
76
  export declare function oidcModuleConfigFactory(configService: ConfigService, envService: FirebaseServerEnvService): OidcModuleConfig;
74
77
  /**
@@ -88,8 +91,13 @@ export interface ProvideAppOidcModuleMetadataConfig extends Pick<ModuleMetadata,
88
91
  readonly dependencyModule: Required<ModuleMetadata>['imports']['0'];
89
92
  /**
90
93
  * Optional overrides to merge into the {@link OidcModuleConfig} produced by the factory.
94
+ *
95
+ * The `issuer` override is honored verbatim and takes precedence over the factory-derived issuer
96
+ * (which is normally built from `envService.appApiUrl` origin ?? `envService.appUrl`). Pass an
97
+ * explicit `issuer` when the consumer wants a canonical issuer URL that does not match either
98
+ * environment URL — e.g., when serving OIDC behind a non-`/oidc` path or under a vanity host.
91
99
  */
92
- readonly config?: Partial<Pick<OidcModuleConfig, 'suppressBodyParserWarning' | 'renderError' | 'protectedPaths' | 'appOAuthInteractionPath' | 'appOAuthLoginUrlPart' | 'appOAuthConsentUrlPart' | 'tokenEndpointAuthMethods' | 'registrationEnabled' | 'trustProxy' | 'trustProxyInNonProduction' | 'tokenLifetimes' | 'maxRequestedLoginDuration' | 'minRequestedLoginDuration' | 'defaultRequestedLoginDuration'>>;
100
+ readonly config?: Partial<Pick<OidcModuleConfig, 'issuer' | 'suppressBodyParserWarning' | 'renderError' | 'protectedPaths' | 'appOAuthInteractionPath' | 'appOAuthLoginUrlPart' | 'appOAuthConsentUrlPart' | 'tokenEndpointAuthMethods' | 'registrationEnabled' | 'trustProxy' | 'trustProxyInNonProduction' | 'tokenLifetimes' | 'maxRequestedLoginDuration' | 'minRequestedLoginDuration' | 'defaultRequestedLoginDuration'>>;
93
101
  }
94
102
  /**
95
103
  * Convenience function used to generate ModuleMetadata for an app's OidcModule.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "sideEffects": false,
5
5
  "exports": {
6
6
  "./test": {
@@ -44,15 +44,15 @@
44
44
  "main": "./index.cjs.js",
45
45
  "types": "./src/index.d.ts",
46
46
  "peerDependencies": {
47
- "@dereekb/analytics": "13.11.5",
48
- "@dereekb/date": "13.11.5",
49
- "@dereekb/dbx-core": "13.11.5",
50
- "@dereekb/firebase": "13.11.5",
51
- "@dereekb/model": "13.11.5",
52
- "@dereekb/nestjs": "13.11.5",
53
- "@dereekb/rxjs": "13.11.5",
54
- "@dereekb/util": "13.11.5",
55
- "@dereekb/zoho": "13.11.5",
47
+ "@dereekb/analytics": "13.11.7",
48
+ "@dereekb/date": "13.11.7",
49
+ "@dereekb/dbx-core": "13.11.7",
50
+ "@dereekb/firebase": "13.11.7",
51
+ "@dereekb/model": "13.11.7",
52
+ "@dereekb/nestjs": "13.11.7",
53
+ "@dereekb/rxjs": "13.11.7",
54
+ "@dereekb/util": "13.11.7",
55
+ "@dereekb/zoho": "13.11.7",
56
56
  "@google-cloud/firestore": "^7.11.6",
57
57
  "@google-cloud/storage": "^7.19.0",
58
58
  "@nestjs/common": "^11.1.19",
package/test/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/test",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.11.5",
6
- "@dereekb/date": "13.11.5",
7
- "@dereekb/firebase": "13.11.5",
8
- "@dereekb/firebase-server": "13.11.5",
9
- "@dereekb/firebase-server/oidc": "13.11.5",
10
- "@dereekb/model": "13.11.5",
11
- "@dereekb/nestjs": "13.11.5",
12
- "@dereekb/rxjs": "13.11.5",
13
- "@dereekb/util": "13.11.5",
5
+ "@dereekb/analytics": "13.11.7",
6
+ "@dereekb/date": "13.11.7",
7
+ "@dereekb/firebase": "13.11.7",
8
+ "@dereekb/firebase-server": "13.11.7",
9
+ "@dereekb/firebase-server/oidc": "13.11.7",
10
+ "@dereekb/model": "13.11.7",
11
+ "@dereekb/nestjs": "13.11.7",
12
+ "@dereekb/rxjs": "13.11.7",
13
+ "@dereekb/util": "13.11.7",
14
14
  "@google-cloud/firestore": "^7.11.6",
15
15
  "@google-cloud/storage": "^7.19.0",
16
16
  "@nestjs/common": "^11.1.19",
@@ -23,7 +23,7 @@
23
23
  "supertest": "^7.2.2"
24
24
  },
25
25
  "devDependencies": {
26
- "@dereekb/nestjs": "13.11.5"
26
+ "@dereekb/nestjs": "13.11.7"
27
27
  },
28
28
  "exports": {
29
29
  "./package.json": "./package.json",
package/zoho/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/zoho",
3
- "version": "13.11.5",
3
+ "version": "13.11.7",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.11.5",
6
- "@dereekb/date": "13.11.5",
7
- "@dereekb/model": "13.11.5",
8
- "@dereekb/nestjs": "13.11.5",
9
- "@dereekb/rxjs": "13.11.5",
10
- "@dereekb/firebase": "13.11.5",
11
- "@dereekb/util": "13.11.5",
12
- "@dereekb/zoho": "13.11.5"
5
+ "@dereekb/analytics": "13.11.7",
6
+ "@dereekb/date": "13.11.7",
7
+ "@dereekb/model": "13.11.7",
8
+ "@dereekb/nestjs": "13.11.7",
9
+ "@dereekb/rxjs": "13.11.7",
10
+ "@dereekb/firebase": "13.11.7",
11
+ "@dereekb/util": "13.11.7",
12
+ "@dereekb/zoho": "13.11.7"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",