@backstage/plugin-auth-backend 0.4.7 → 0.5.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/dist/index.cjs.js CHANGED
@@ -17,12 +17,12 @@ var passportGoogleOauth20 = require('passport-google-oauth20');
17
17
  var passportMicrosoft = require('passport-microsoft');
18
18
  var got = require('got');
19
19
  var OAuth2Strategy = require('passport-oauth2');
20
+ var openidClient = require('openid-client');
20
21
  var passportOktaOauth = require('passport-okta-oauth');
21
22
  var passportBitbucketOauth2 = require('passport-bitbucket-oauth2');
22
- var fetch = require('cross-fetch');
23
+ var fetch = require('node-fetch');
23
24
  var NodeCache = require('node-cache');
24
25
  var jose = require('jose');
25
- var openidClient = require('openid-client');
26
26
  var passportSaml = require('passport-saml');
27
27
  var passportOneloginOauth = require('passport-onelogin-oauth');
28
28
  var catalogClient = require('@backstage/catalog-client');
@@ -46,14 +46,12 @@ function _interopNamespace(e) {
46
46
  var d = Object.getOwnPropertyDescriptor(e, k);
47
47
  Object.defineProperty(n, k, d.get ? d : {
48
48
  enumerable: true,
49
- get: function () {
50
- return e[k];
51
- }
49
+ get: function () { return e[k]; }
52
50
  });
53
51
  }
54
52
  });
55
53
  }
56
- n['default'] = e;
54
+ n["default"] = e;
57
55
  return Object.freeze(n);
58
56
  }
59
57
 
@@ -88,7 +86,7 @@ const makeProfileInfo = (profile, idToken) => {
88
86
  let displayName = (_b = (_a = profile.displayName) != null ? _a : profile.username) != null ? _b : profile.id;
89
87
  if ((!email || !picture || !displayName) && idToken) {
90
88
  try {
91
- const decoded = jwtDecoder__default['default'](idToken);
89
+ const decoded = jwtDecoder__default["default"](idToken);
92
90
  if (!email && decoded.email) {
93
91
  email = decoded.email;
94
92
  }
@@ -112,16 +110,16 @@ const executeRedirectStrategy = async (req, providerStrategy, options) => {
112
110
  return new Promise((resolve) => {
113
111
  const strategy = Object.create(providerStrategy);
114
112
  strategy.redirect = (url, status) => {
115
- resolve({url, status: status != null ? status : void 0});
113
+ resolve({ url, status: status != null ? status : void 0 });
116
114
  };
117
- strategy.authenticate(req, {...options});
115
+ strategy.authenticate(req, { ...options });
118
116
  });
119
117
  };
120
118
  const executeFrameHandlerStrategy = async (req, providerStrategy) => {
121
119
  return new Promise((resolve, reject) => {
122
120
  const strategy = Object.create(providerStrategy);
123
121
  strategy.success = (result, privateInfo) => {
124
- resolve({result, privateInfo});
122
+ resolve({ result, privateInfo });
125
123
  };
126
124
  strategy.fail = (info) => {
127
125
  var _a;
@@ -193,7 +191,7 @@ const readState = (stateString) => {
193
191
  return state;
194
192
  };
195
193
  const encodeState = (state) => {
196
- const stateString = new URLSearchParams(pickBy__default['default'](state, (value) => value !== void 0)).toString();
194
+ const stateString = new URLSearchParams(pickBy__default["default"](state, (value) => value !== void 0)).toString();
197
195
  return Buffer.from(stateString, "utf-8").toString("hex");
198
196
  };
199
197
  const verifyNonce = (req, providerId) => {
@@ -218,7 +216,7 @@ class OAuthEnvironmentHandler {
218
216
  }
219
217
  static mapConfig(config, factoryFunc) {
220
218
  const envs = config.keys();
221
- const handlers = new Map();
219
+ const handlers = /* @__PURE__ */ new Map();
222
220
  for (const env of envs) {
223
221
  const envConfig = config.getConfig(env);
224
222
  const handler = factoryFunc(envConfig);
@@ -227,22 +225,22 @@ class OAuthEnvironmentHandler {
227
225
  return new OAuthEnvironmentHandler(handlers);
228
226
  }
229
227
  async start(req, res) {
230
- const provider = this.getProviderForEnv(req, res);
231
- await (provider == null ? void 0 : provider.start(req, res));
228
+ const provider = this.getProviderForEnv(req);
229
+ await provider.start(req, res);
232
230
  }
233
231
  async frameHandler(req, res) {
234
- const provider = this.getProviderForEnv(req, res);
235
- await (provider == null ? void 0 : provider.frameHandler(req, res));
232
+ const provider = this.getProviderForEnv(req);
233
+ await provider.frameHandler(req, res);
236
234
  }
237
235
  async refresh(req, res) {
238
236
  var _a;
239
- const provider = this.getProviderForEnv(req, res);
240
- await ((_a = provider == null ? void 0 : provider.refresh) == null ? void 0 : _a.call(provider, req, res));
237
+ const provider = this.getProviderForEnv(req);
238
+ await ((_a = provider.refresh) == null ? void 0 : _a.call(provider, req, res));
241
239
  }
242
240
  async logout(req, res) {
243
241
  var _a;
244
- const provider = this.getProviderForEnv(req, res);
245
- await ((_a = provider == null ? void 0 : provider.logout) == null ? void 0 : _a.call(provider, req, res));
242
+ const provider = this.getProviderForEnv(req);
243
+ await ((_a = provider.logout) == null ? void 0 : _a.call(provider, req, res));
246
244
  }
247
245
  getRequestFromEnv(req) {
248
246
  var _a, _b;
@@ -257,19 +255,16 @@ class OAuthEnvironmentHandler {
257
255
  const env = readState(stateParams).env;
258
256
  return env;
259
257
  }
260
- getProviderForEnv(req, res) {
258
+ getProviderForEnv(req) {
261
259
  const env = this.getRequestFromEnv(req);
262
260
  if (!env) {
263
261
  throw new errors.InputError(`Must specify 'env' query to select environment`);
264
262
  }
265
- if (!this.handlers.has(env)) {
266
- res.status(404).send(`Missing configuration.
267
- <br>
268
- <br>
269
- For this flow to work you need to supply a valid configuration for the "${env}" environment of provider.`);
270
- return void 0;
263
+ const handler = this.handlers.get(env);
264
+ if (!handler) {
265
+ throw new errors.NotFoundError(`No configuration available for the '${env}' environment of this provider.`);
271
266
  }
272
- return this.handlers.get(env);
267
+ return handler;
273
268
  }
274
269
  }
275
270
 
@@ -290,11 +285,11 @@ const postMessageResponse = (res, appOrigin, response) => {
290
285
  window.close();
291
286
  }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)
292
287
  `;
293
- const hash = crypto__default['default'].createHash("sha256").update(script).digest("base64");
288
+ const hash = crypto__default["default"].createHash("sha256").update(script).digest("base64");
294
289
  res.setHeader("Content-Type", "text/html");
295
290
  res.setHeader("X-Frame-Options", "sameorigin");
296
291
  res.setHeader("Content-Security-Policy", `script-src 'sha256-${hash}'`);
297
- res.end(`<html><body><script>${script}</script></body></html>`);
292
+ res.end(`<html><body><script>${script}<\/script></body></html>`);
298
293
  };
299
294
  const ensuresXRequestedWith = (req) => {
300
295
  const requiredHeader = req.header("X-Requested-With");
@@ -304,6 +299,25 @@ const ensuresXRequestedWith = (req) => {
304
299
  return true;
305
300
  };
306
301
 
302
+ function parseJwtPayload(token) {
303
+ const [_header, payload, _signature] = token.split(".");
304
+ return JSON.parse(Buffer.from(payload, "base64").toString());
305
+ }
306
+ function prepareBackstageIdentityResponse(result) {
307
+ const { sub, ent } = parseJwtPayload(result.token);
308
+ return {
309
+ ...{
310
+ idToken: result.token,
311
+ ...result
312
+ },
313
+ identity: {
314
+ type: "user",
315
+ userEntityRef: sub,
316
+ ownershipEntityRefs: ent != null ? ent : []
317
+ }
318
+ };
319
+ }
320
+
307
321
  const THOUSAND_DAYS_MS = 1e3 * 24 * 60 * 60 * 1e3;
308
322
  const TEN_MINUTES_MS = 600 * 1e3;
309
323
  class OAuthAdapter {
@@ -355,7 +369,7 @@ class OAuthAdapter {
355
369
  };
356
370
  }
357
371
  static fromConfig(config, handlers, options) {
358
- const {origin: appOrigin} = new url.URL(config.appUrl);
372
+ const { origin: appOrigin } = new url.URL(config.appUrl);
359
373
  const secure = config.baseUrl.startsWith("https://");
360
374
  const url$1 = new url.URL(config.baseUrl);
361
375
  const cookiePath = `${url$1.pathname}/${options.providerId}`;
@@ -379,11 +393,11 @@ class OAuthAdapter {
379
393
  if (this.options.persistScopes) {
380
394
  this.setScopesCookie(res, scope);
381
395
  }
382
- const nonce = crypto__default['default'].randomBytes(16).toString("base64");
396
+ const nonce = crypto__default["default"].randomBytes(16).toString("base64");
383
397
  this.setNonceCookie(res, nonce);
384
- const state = {nonce, env, origin};
385
- const forwardReq = Object.assign(req, {scope, state});
386
- const {url, status} = await this.handlers.start(forwardReq);
398
+ const state = { nonce, env, origin };
399
+ const forwardReq = Object.assign(req, { scope, state });
400
+ const { url, status } = await this.handlers.start(forwardReq);
387
401
  res.statusCode = status || 302;
388
402
  res.setHeader("Location", url);
389
403
  res.setHeader("Content-Length", "0");
@@ -405,7 +419,7 @@ class OAuthAdapter {
405
419
  }
406
420
  }
407
421
  verifyNonce(req, this.options.providerId);
408
- const {response, refreshToken} = await this.handlers.handler(req);
422
+ const { response, refreshToken } = await this.handlers.handler(req);
409
423
  if (this.options.persistScopes) {
410
424
  const grantedScopes = this.getScopesFromCookie(req, this.options.providerId);
411
425
  response.providerInfo.scope = grantedScopes;
@@ -413,63 +427,62 @@ class OAuthAdapter {
413
427
  if (refreshToken && !this.options.disableRefresh) {
414
428
  this.setRefreshTokenCookie(res, refreshToken);
415
429
  }
416
- await this.populateIdentity(response.backstageIdentity);
430
+ const identity = await this.populateIdentity(response.backstageIdentity);
417
431
  return postMessageResponse(res, appOrigin, {
418
432
  type: "authorization_response",
419
- response
433
+ response: { ...response, backstageIdentity: identity }
420
434
  });
421
435
  } catch (error) {
422
- const {name, message} = errors.isError(error) ? error : new Error("Encountered invalid error");
436
+ const { name, message } = errors.isError(error) ? error : new Error("Encountered invalid error");
423
437
  return postMessageResponse(res, appOrigin, {
424
438
  type: "authorization_response",
425
- error: {name, message}
439
+ error: { name, message }
426
440
  });
427
441
  }
428
442
  }
429
443
  async logout(req, res) {
430
444
  if (!ensuresXRequestedWith(req)) {
431
- res.status(401).send("Invalid X-Requested-With header");
432
- return;
445
+ throw new errors.AuthenticationError("Invalid X-Requested-With header");
433
446
  }
434
447
  this.removeRefreshTokenCookie(res);
435
- res.status(200).send("logout!");
448
+ res.status(200).end();
436
449
  }
437
450
  async refresh(req, res) {
438
451
  var _a, _b;
439
452
  if (!ensuresXRequestedWith(req)) {
440
- res.status(401).send("Invalid X-Requested-With header");
441
- return;
453
+ throw new errors.AuthenticationError("Invalid X-Requested-With header");
442
454
  }
443
455
  if (!this.handlers.refresh || this.options.disableRefresh) {
444
- res.status(400).send(`Refresh token not supported for provider: ${this.options.providerId}`);
445
- return;
456
+ throw new errors.InputError(`Refresh token is not supported for provider ${this.options.providerId}`);
446
457
  }
447
458
  try {
448
459
  const refreshToken = req.cookies[`${this.options.providerId}-refresh-token`];
449
460
  if (!refreshToken) {
450
- throw new Error("Missing session cookie");
461
+ throw new errors.InputError("Missing session cookie");
451
462
  }
452
463
  const scope = (_b = (_a = req.query.scope) == null ? void 0 : _a.toString()) != null ? _b : "";
453
- const forwardReq = Object.assign(req, {scope, refreshToken});
464
+ const forwardReq = Object.assign(req, { scope, refreshToken });
454
465
  const response = await this.handlers.refresh(forwardReq);
455
- await this.populateIdentity(response.backstageIdentity);
466
+ const backstageIdentity = await this.populateIdentity(response.backstageIdentity);
456
467
  if (response.providerInfo.refreshToken && response.providerInfo.refreshToken !== refreshToken) {
457
468
  this.setRefreshTokenCookie(res, response.providerInfo.refreshToken);
458
469
  }
459
- res.status(200).json(response);
470
+ res.status(200).json({ ...response, backstageIdentity });
460
471
  } catch (error) {
461
- res.status(401).send(String(error));
472
+ throw new errors.AuthenticationError("Refresh failed", error);
462
473
  }
463
474
  }
464
475
  async populateIdentity(identity) {
465
476
  if (!identity) {
466
- return;
477
+ return void 0;
467
478
  }
468
- if (!identity.idToken) {
469
- identity.idToken = await this.options.tokenIssuer.issueToken({
470
- claims: {sub: identity.id}
471
- });
479
+ if (identity.token) {
480
+ return prepareBackstageIdentityResponse(identity);
472
481
  }
482
+ const token = await this.options.tokenIssuer.issueToken({
483
+ claims: { sub: identity.id }
484
+ });
485
+ return prepareBackstageIdentityResponse({ ...identity, token });
473
486
  }
474
487
  }
475
488
 
@@ -486,9 +499,9 @@ class CatalogIdentityClient {
486
499
  filter[`metadata.annotations.${key}`] = value;
487
500
  }
488
501
  const token = await this.tokenIssuer.issueToken({
489
- claims: {sub: "backstage.io/auth-backend"}
502
+ claims: { sub: "backstage.io/auth-backend" }
490
503
  });
491
- const {items} = await this.catalogApi.getEntities({filter}, {token});
504
+ const { items } = await this.catalogApi.getEntities({ filter }, { token });
492
505
  if (items.length !== 1) {
493
506
  if (items.length > 1) {
494
507
  throw new errors.ConflictError("User lookup resulted in multiple matches");
@@ -498,10 +511,8 @@ class CatalogIdentityClient {
498
511
  }
499
512
  return items[0];
500
513
  }
501
- async resolveCatalogMembership({
502
- entityRefs,
503
- logger
504
- }) {
514
+ async resolveCatalogMembership(query) {
515
+ const { entityRefs, logger } = query;
505
516
  const resolvedEntityRefs = entityRefs.map((ref) => {
506
517
  try {
507
518
  const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
@@ -519,7 +530,7 @@ class CatalogIdentityClient {
519
530
  "metadata.namespace": ref.namespace,
520
531
  "metadata.name": ref.name
521
532
  }));
522
- const entities = await this.catalogApi.getEntities({filter}).then((r) => r.items);
533
+ const entities = await this.catalogApi.getEntities({ filter }).then((r) => r.items);
523
534
  if (entityRefs.length !== entities.length) {
524
535
  const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
525
536
  const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
@@ -563,7 +574,7 @@ class GithubAuthProvider {
563
574
  userProfileURL: options.userProfileUrl,
564
575
  authorizationURL: options.authorizationUrl
565
576
  }, (accessToken, refreshToken, params, fullProfile, done) => {
566
- done(void 0, {fullProfile, params, accessToken}, {refreshToken});
577
+ done(void 0, { fullProfile, params, accessToken }, { refreshToken });
567
578
  });
568
579
  }
569
580
  async start(req) {
@@ -573,7 +584,7 @@ class GithubAuthProvider {
573
584
  });
574
585
  }
575
586
  async handler(req) {
576
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
587
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
577
588
  return {
578
589
  response: await this.handleResult(result),
579
590
  refreshToken: privateInfo.refreshToken
@@ -594,7 +605,7 @@ class GithubAuthProvider {
594
605
  });
595
606
  }
596
607
  async handleResult(result) {
597
- const {profile} = await this.authHandler(result);
608
+ const { profile } = await this.authHandler(result);
598
609
  const expiresInStr = result.params.expires_in;
599
610
  const response = {
600
611
  providerInfo: {
@@ -619,12 +630,12 @@ class GithubAuthProvider {
619
630
  }
620
631
  }
621
632
  const githubDefaultSignInResolver = async (info, ctx) => {
622
- const {fullProfile} = info.result;
633
+ const { fullProfile } = info.result;
623
634
  const userId = fullProfile.username || fullProfile.id;
624
635
  const token = await ctx.tokenIssuer.issueToken({
625
- claims: {sub: userId, ent: [`user:default/${userId}`]}
636
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
626
637
  });
627
- return {id: userId, token};
638
+ return { id: userId, token };
628
639
  };
629
640
  const createGithubProvider = (options) => {
630
641
  return ({
@@ -648,7 +659,7 @@ const createGithubProvider = (options) => {
648
659
  catalogApi,
649
660
  tokenIssuer
650
661
  });
651
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile}) => ({
662
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
652
663
  profile: makeProfileInfo(fullProfile)
653
664
  });
654
665
  const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : githubDefaultSignInResolver;
@@ -658,7 +669,7 @@ const createGithubProvider = (options) => {
658
669
  logger
659
670
  });
660
671
  const stateEncoder = (_c = options == null ? void 0 : options.stateEncoder) != null ? _c : async (req) => {
661
- return {encodedState: encodeState(req.state)};
672
+ return { encodedState: encodeState(req.state) };
662
673
  };
663
674
  const provider = new GithubAuthProvider({
664
675
  clientId,
@@ -683,15 +694,15 @@ const createGithubProvider = (options) => {
683
694
  };
684
695
 
685
696
  const gitlabDefaultSignInResolver = async (info, ctx) => {
686
- const {profile, result} = info;
697
+ const { profile, result } = info;
687
698
  let id = result.fullProfile.id;
688
699
  if (profile.email) {
689
700
  id = profile.email.split("@")[0];
690
701
  }
691
702
  const token = await ctx.tokenIssuer.issueToken({
692
- claims: {sub: id, ent: [`user:default/${id}`]}
703
+ claims: { sub: id, ent: [`user:default/${id}`] }
693
704
  });
694
- return {id, token};
705
+ return { id, token };
695
706
  };
696
707
  const gitlabDefaultAuthHandler = async ({
697
708
  fullProfile,
@@ -712,7 +723,7 @@ class GitlabAuthProvider {
712
723
  callbackURL: options.callbackUrl,
713
724
  baseURL: options.baseUrl
714
725
  }, (accessToken, refreshToken, params, fullProfile, done) => {
715
- done(void 0, {fullProfile, params, accessToken}, {
726
+ done(void 0, { fullProfile, params, accessToken }, {
716
727
  refreshToken
717
728
  });
718
729
  });
@@ -724,7 +735,7 @@ class GitlabAuthProvider {
724
735
  });
725
736
  }
726
737
  async handler(req) {
727
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
738
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
728
739
  return {
729
740
  response: await this.handleResult(result),
730
741
  refreshToken: privateInfo.refreshToken
@@ -745,7 +756,7 @@ class GitlabAuthProvider {
745
756
  });
746
757
  }
747
758
  async handleResult(result) {
748
- const {profile} = await this.authHandler(result);
759
+ const { profile } = await this.authHandler(result);
749
760
  const response = {
750
761
  providerInfo: {
751
762
  idToken: result.params.id_token,
@@ -846,14 +857,14 @@ class GoogleAuthProvider {
846
857
  });
847
858
  }
848
859
  async handler(req) {
849
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
860
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
850
861
  return {
851
862
  response: await this.handleResult(result),
852
863
  refreshToken: privateInfo.refreshToken
853
864
  };
854
865
  }
855
866
  async refresh(req) {
856
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
867
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
857
868
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
858
869
  return this.handleResult({
859
870
  fullProfile,
@@ -863,7 +874,7 @@ class GoogleAuthProvider {
863
874
  });
864
875
  }
865
876
  async handleResult(result) {
866
- const {profile} = await this.authHandler(result);
877
+ const { profile } = await this.authHandler(result);
867
878
  const response = {
868
879
  providerInfo: {
869
880
  idToken: result.params.id_token,
@@ -887,7 +898,7 @@ class GoogleAuthProvider {
887
898
  }
888
899
  }
889
900
  const googleEmailSignInResolver = async (info, ctx) => {
890
- const {profile} = info;
901
+ const { profile } = info;
891
902
  if (!profile.email) {
892
903
  throw new Error("Google profile contained no email");
893
904
  }
@@ -897,11 +908,11 @@ const googleEmailSignInResolver = async (info, ctx) => {
897
908
  }
898
909
  });
899
910
  const claims = getEntityClaims(entity);
900
- const token = await ctx.tokenIssuer.issueToken({claims});
901
- return {id: entity.metadata.name, entity, token};
911
+ const token = await ctx.tokenIssuer.issueToken({ claims });
912
+ return { id: entity.metadata.name, entity, token };
902
913
  };
903
914
  const googleDefaultSignInResolver = async (info, ctx) => {
904
- const {profile} = info;
915
+ const { profile } = info;
905
916
  if (!profile.email) {
906
917
  throw new Error("Google profile contained no email");
907
918
  }
@@ -918,9 +929,9 @@ const googleDefaultSignInResolver = async (info, ctx) => {
918
929
  userId = profile.email.split("@")[0];
919
930
  }
920
931
  const token = await ctx.tokenIssuer.issueToken({
921
- claims: {sub: userId, ent: [`user:default/${userId}`]}
932
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
922
933
  });
923
- return {id: userId, token};
934
+ return { id: userId, token };
924
935
  };
925
936
  const createGoogleProvider = (options) => {
926
937
  return ({
@@ -939,7 +950,7 @@ const createGoogleProvider = (options) => {
939
950
  catalogApi,
940
951
  tokenIssuer
941
952
  });
942
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile, params}) => ({
953
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
943
954
  profile: makeProfileInfo(fullProfile, params.id_token)
944
955
  });
945
956
  const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : googleDefaultSignInResolver;
@@ -981,7 +992,7 @@ class MicrosoftAuthProvider {
981
992
  tokenURL: options.tokenUrl,
982
993
  passReqToCallback: false
983
994
  }, (accessToken, refreshToken, params, fullProfile, done) => {
984
- done(void 0, {fullProfile, accessToken, params}, {refreshToken});
995
+ done(void 0, { fullProfile, accessToken, params }, { refreshToken });
985
996
  });
986
997
  }
987
998
  async start(req) {
@@ -991,14 +1002,14 @@ class MicrosoftAuthProvider {
991
1002
  });
992
1003
  }
993
1004
  async handler(req) {
994
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
1005
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
995
1006
  return {
996
1007
  response: await this.handleResult(result),
997
1008
  refreshToken: privateInfo.refreshToken
998
1009
  };
999
1010
  }
1000
1011
  async refresh(req) {
1001
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1012
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1002
1013
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1003
1014
  return this.handleResult({
1004
1015
  fullProfile,
@@ -1009,8 +1020,8 @@ class MicrosoftAuthProvider {
1009
1020
  }
1010
1021
  async handleResult(result) {
1011
1022
  const photo = await this.getUserPhoto(result.accessToken);
1012
- result.fullProfile.photos = photo ? [{value: photo}] : void 0;
1013
- const {profile} = await this.authHandler(result);
1023
+ result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1024
+ const { profile } = await this.authHandler(result);
1014
1025
  const response = {
1015
1026
  providerInfo: {
1016
1027
  idToken: result.params.id_token,
@@ -1034,7 +1045,7 @@ class MicrosoftAuthProvider {
1034
1045
  }
1035
1046
  getUserPhoto(accessToken) {
1036
1047
  return new Promise((resolve) => {
1037
- got__default['default'].get("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1048
+ got__default["default"].get("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1038
1049
  encoding: "binary",
1039
1050
  responseType: "buffer",
1040
1051
  headers: {
@@ -1051,7 +1062,7 @@ class MicrosoftAuthProvider {
1051
1062
  }
1052
1063
  }
1053
1064
  const microsoftEmailSignInResolver = async (info, ctx) => {
1054
- const {profile} = info;
1065
+ const { profile } = info;
1055
1066
  if (!profile.email) {
1056
1067
  throw new Error("Microsoft profile contained no email");
1057
1068
  }
@@ -1061,19 +1072,19 @@ const microsoftEmailSignInResolver = async (info, ctx) => {
1061
1072
  }
1062
1073
  });
1063
1074
  const claims = getEntityClaims(entity);
1064
- const token = await ctx.tokenIssuer.issueToken({claims});
1065
- return {id: entity.metadata.name, entity, token};
1075
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1076
+ return { id: entity.metadata.name, entity, token };
1066
1077
  };
1067
1078
  const microsoftDefaultSignInResolver = async (info, ctx) => {
1068
- const {profile} = info;
1079
+ const { profile } = info;
1069
1080
  if (!profile.email) {
1070
1081
  throw new Error("Profile contained no email");
1071
1082
  }
1072
1083
  const userId = profile.email.split("@")[0];
1073
1084
  const token = await ctx.tokenIssuer.issueToken({
1074
- claims: {sub: userId, ent: [`user:default/${userId}`]}
1085
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
1075
1086
  });
1076
- return {id: userId, token};
1087
+ return { id: userId, token };
1077
1088
  };
1078
1089
  const createMicrosoftProvider = (options) => {
1079
1090
  return ({
@@ -1095,7 +1106,7 @@ const createMicrosoftProvider = (options) => {
1095
1106
  catalogApi,
1096
1107
  tokenIssuer
1097
1108
  });
1098
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile, params}) => ({
1109
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1099
1110
  profile: makeProfileInfo(fullProfile, params.id_token)
1100
1111
  });
1101
1112
  const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : microsoftDefaultSignInResolver;
@@ -1138,7 +1149,10 @@ class OAuth2AuthProvider {
1138
1149
  authorizationURL: options.authorizationUrl,
1139
1150
  tokenURL: options.tokenUrl,
1140
1151
  passReqToCallback: false,
1141
- scope: options.scope
1152
+ scope: options.scope,
1153
+ customHeaders: options.includeBasicAuth ? {
1154
+ Authorization: `Basic ${this.encodeClientCredentials(options.clientId, options.clientSecret)}`
1155
+ } : void 0
1142
1156
  }, (accessToken, refreshToken, params, fullProfile, done) => {
1143
1157
  done(void 0, {
1144
1158
  fullProfile,
@@ -1159,7 +1173,7 @@ class OAuth2AuthProvider {
1159
1173
  });
1160
1174
  }
1161
1175
  async handler(req) {
1162
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
1176
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1163
1177
  return {
1164
1178
  response: await this.handleResult(result),
1165
1179
  refreshToken: privateInfo.refreshToken
@@ -1181,7 +1195,7 @@ class OAuth2AuthProvider {
1181
1195
  });
1182
1196
  }
1183
1197
  async handleResult(result) {
1184
- const {profile} = await this.authHandler(result);
1198
+ const { profile } = await this.authHandler(result);
1185
1199
  const response = {
1186
1200
  providerInfo: {
1187
1201
  idToken: result.params.id_token,
@@ -1204,17 +1218,20 @@ class OAuth2AuthProvider {
1204
1218
  }
1205
1219
  return response;
1206
1220
  }
1221
+ encodeClientCredentials(clientID, clientSecret) {
1222
+ return Buffer.from(`${clientID}:${clientSecret}`).toString("base64");
1223
+ }
1207
1224
  }
1208
- const oAuth2DefaultSignInResolver = async (info, ctx) => {
1209
- const {profile} = info;
1225
+ const oAuth2DefaultSignInResolver$1 = async (info, ctx) => {
1226
+ const { profile } = info;
1210
1227
  if (!profile.email) {
1211
1228
  throw new Error("Profile contained no email");
1212
1229
  }
1213
1230
  const userId = profile.email.split("@")[0];
1214
1231
  const token = await ctx.tokenIssuer.issueToken({
1215
- claims: {sub: userId, ent: [`user:default/${userId}`]}
1232
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
1216
1233
  });
1217
- return {id: userId, token};
1234
+ return { id: userId, token };
1218
1235
  };
1219
1236
  const createOAuth2Provider = (options) => {
1220
1237
  return ({
@@ -1232,15 +1249,16 @@ const createOAuth2Provider = (options) => {
1232
1249
  const authorizationUrl = envConfig.getString("authorizationUrl");
1233
1250
  const tokenUrl = envConfig.getString("tokenUrl");
1234
1251
  const scope = envConfig.getOptionalString("scope");
1252
+ const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1235
1253
  const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1236
1254
  const catalogIdentityClient = new CatalogIdentityClient({
1237
1255
  catalogApi,
1238
1256
  tokenIssuer
1239
1257
  });
1240
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile, params}) => ({
1258
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1241
1259
  profile: makeProfileInfo(fullProfile, params.id_token)
1242
1260
  });
1243
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver;
1261
+ const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver$1;
1244
1262
  const signInResolver = (info) => signInResolverFn(info, {
1245
1263
  catalogIdentityClient,
1246
1264
  tokenIssuer,
@@ -1257,7 +1275,8 @@ const createOAuth2Provider = (options) => {
1257
1275
  authorizationUrl,
1258
1276
  tokenUrl,
1259
1277
  scope,
1260
- logger
1278
+ logger,
1279
+ includeBasicAuth
1261
1280
  });
1262
1281
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1263
1282
  disableRefresh,
@@ -1267,6 +1286,168 @@ const createOAuth2Provider = (options) => {
1267
1286
  });
1268
1287
  };
1269
1288
 
1289
+ class OidcAuthProvider {
1290
+ constructor(options) {
1291
+ this.implementation = this.setupStrategy(options);
1292
+ this.scope = options.scope;
1293
+ this.prompt = options.prompt;
1294
+ this.signInResolver = options.signInResolver;
1295
+ this.authHandler = options.authHandler;
1296
+ this.tokenIssuer = options.tokenIssuer;
1297
+ this.catalogIdentityClient = options.catalogIdentityClient;
1298
+ this.logger = options.logger;
1299
+ }
1300
+ async start(req) {
1301
+ const { strategy } = await this.implementation;
1302
+ const options = {
1303
+ scope: req.scope || this.scope || "openid profile email",
1304
+ state: encodeState(req.state)
1305
+ };
1306
+ const prompt = this.prompt || "none";
1307
+ if (prompt !== "auto") {
1308
+ options.prompt = prompt;
1309
+ }
1310
+ return await executeRedirectStrategy(req, strategy, options);
1311
+ }
1312
+ async handler(req) {
1313
+ const { strategy } = await this.implementation;
1314
+ const strategyResponse = await executeFrameHandlerStrategy(req, strategy);
1315
+ const {
1316
+ result: { userinfo, tokenset },
1317
+ privateInfo
1318
+ } = strategyResponse;
1319
+ const identityResponse = await this.handleResult({ tokenset, userinfo });
1320
+ return {
1321
+ response: identityResponse,
1322
+ refreshToken: privateInfo.refreshToken
1323
+ };
1324
+ }
1325
+ async refresh(req) {
1326
+ const { client } = await this.implementation;
1327
+ const tokenset = await client.refresh(req.refreshToken);
1328
+ if (!tokenset.access_token) {
1329
+ throw new Error("Refresh failed");
1330
+ }
1331
+ const profile = await client.userinfo(tokenset.access_token);
1332
+ return this.handleResult({ tokenset, userinfo: profile });
1333
+ }
1334
+ async setupStrategy(options) {
1335
+ const issuer = await openidClient.Issuer.discover(options.metadataUrl);
1336
+ const client = new issuer.Client({
1337
+ access_type: "offline",
1338
+ client_id: options.clientId,
1339
+ client_secret: options.clientSecret,
1340
+ redirect_uris: [options.callbackUrl],
1341
+ response_types: ["code"],
1342
+ id_token_signed_response_alg: options.tokenSignedResponseAlg || "RS256",
1343
+ scope: options.scope || ""
1344
+ });
1345
+ const strategy = new openidClient.Strategy({
1346
+ client,
1347
+ passReqToCallback: false
1348
+ }, (tokenset, userinfo, done) => {
1349
+ if (typeof done !== "function") {
1350
+ throw new Error("OIDC IdP must provide a userinfo_endpoint in the metadata response");
1351
+ }
1352
+ done(void 0, { tokenset, userinfo }, {
1353
+ refreshToken: tokenset.refresh_token
1354
+ });
1355
+ });
1356
+ strategy.error = console.error;
1357
+ return { strategy, client };
1358
+ }
1359
+ async handleResult(result) {
1360
+ const { profile } = await this.authHandler(result);
1361
+ const response = {
1362
+ providerInfo: {
1363
+ idToken: result.tokenset.id_token,
1364
+ accessToken: result.tokenset.access_token,
1365
+ refreshToken: result.tokenset.refresh_token,
1366
+ scope: result.tokenset.scope,
1367
+ expiresInSeconds: result.tokenset.expires_in
1368
+ },
1369
+ profile
1370
+ };
1371
+ if (this.signInResolver) {
1372
+ response.backstageIdentity = await this.signInResolver({
1373
+ result,
1374
+ profile
1375
+ }, {
1376
+ tokenIssuer: this.tokenIssuer,
1377
+ catalogIdentityClient: this.catalogIdentityClient,
1378
+ logger: this.logger
1379
+ });
1380
+ }
1381
+ return response;
1382
+ }
1383
+ }
1384
+ const oAuth2DefaultSignInResolver = async (info, ctx) => {
1385
+ const { profile } = info;
1386
+ if (!profile.email) {
1387
+ throw new Error("Profile contained no email");
1388
+ }
1389
+ const userId = profile.email.split("@")[0];
1390
+ const token = await ctx.tokenIssuer.issueToken({
1391
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
1392
+ });
1393
+ return { id: userId, token };
1394
+ };
1395
+ const createOidcProvider = (options) => {
1396
+ return ({
1397
+ providerId,
1398
+ globalConfig,
1399
+ config,
1400
+ tokenIssuer,
1401
+ catalogApi,
1402
+ logger
1403
+ }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1404
+ var _a, _b;
1405
+ const clientId = envConfig.getString("clientId");
1406
+ const clientSecret = envConfig.getString("clientSecret");
1407
+ const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1408
+ const metadataUrl = envConfig.getString("metadataUrl");
1409
+ const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
1410
+ const scope = envConfig.getOptionalString("scope");
1411
+ const prompt = envConfig.getOptionalString("prompt");
1412
+ const catalogIdentityClient = new CatalogIdentityClient({
1413
+ catalogApi,
1414
+ tokenIssuer
1415
+ });
1416
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
1417
+ profile: {
1418
+ displayName: userinfo.name,
1419
+ email: userinfo.email,
1420
+ picture: userinfo.picture
1421
+ }
1422
+ });
1423
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oAuth2DefaultSignInResolver;
1424
+ const signInResolver = (info) => signInResolverFn(info, {
1425
+ catalogIdentityClient,
1426
+ tokenIssuer,
1427
+ logger
1428
+ });
1429
+ const provider = new OidcAuthProvider({
1430
+ clientId,
1431
+ clientSecret,
1432
+ callbackUrl,
1433
+ tokenSignedResponseAlg,
1434
+ metadataUrl,
1435
+ scope,
1436
+ prompt,
1437
+ signInResolver,
1438
+ authHandler,
1439
+ logger,
1440
+ tokenIssuer,
1441
+ catalogIdentityClient
1442
+ });
1443
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1444
+ disableRefresh: false,
1445
+ providerId,
1446
+ tokenIssuer
1447
+ });
1448
+ });
1449
+ };
1450
+
1270
1451
  class OktaAuthProvider {
1271
1452
  constructor(options) {
1272
1453
  this._store = {
@@ -1310,14 +1491,14 @@ class OktaAuthProvider {
1310
1491
  });
1311
1492
  }
1312
1493
  async handler(req) {
1313
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
1494
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1314
1495
  return {
1315
1496
  response: await this.handleResult(result),
1316
1497
  refreshToken: privateInfo.refreshToken
1317
1498
  };
1318
1499
  }
1319
1500
  async refresh(req) {
1320
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1501
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1321
1502
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1322
1503
  return this.handleResult({
1323
1504
  fullProfile,
@@ -1327,7 +1508,7 @@ class OktaAuthProvider {
1327
1508
  });
1328
1509
  }
1329
1510
  async handleResult(result) {
1330
- const {profile} = await this._authHandler(result);
1511
+ const { profile } = await this._authHandler(result);
1331
1512
  const response = {
1332
1513
  providerInfo: {
1333
1514
  idToken: result.params.id_token,
@@ -1351,7 +1532,7 @@ class OktaAuthProvider {
1351
1532
  }
1352
1533
  }
1353
1534
  const oktaEmailSignInResolver = async (info, ctx) => {
1354
- const {profile} = info;
1535
+ const { profile } = info;
1355
1536
  if (!profile.email) {
1356
1537
  throw new Error("Okta profile contained no email");
1357
1538
  }
@@ -1361,19 +1542,19 @@ const oktaEmailSignInResolver = async (info, ctx) => {
1361
1542
  }
1362
1543
  });
1363
1544
  const claims = getEntityClaims(entity);
1364
- const token = await ctx.tokenIssuer.issueToken({claims});
1365
- return {id: entity.metadata.name, entity, token};
1545
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1546
+ return { id: entity.metadata.name, entity, token };
1366
1547
  };
1367
1548
  const oktaDefaultSignInResolver = async (info, ctx) => {
1368
- const {profile} = info;
1549
+ const { profile } = info;
1369
1550
  if (!profile.email) {
1370
1551
  throw new Error("Okta profile contained no email");
1371
1552
  }
1372
1553
  const userId = profile.email.split("@")[0];
1373
1554
  const token = await ctx.tokenIssuer.issueToken({
1374
- claims: {sub: userId, ent: [`user:default/${userId}`]}
1555
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
1375
1556
  });
1376
- return {id: userId, token};
1557
+ return { id: userId, token };
1377
1558
  };
1378
1559
  const createOktaProvider = (_options) => {
1379
1560
  return ({
@@ -1396,7 +1577,7 @@ const createOktaProvider = (_options) => {
1396
1577
  catalogApi,
1397
1578
  tokenIssuer
1398
1579
  });
1399
- const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({fullProfile, params}) => ({
1580
+ const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
1400
1581
  profile: makeProfileInfo(fullProfile, params.id_token)
1401
1582
  });
1402
1583
  const signInResolverFn = (_b = (_a = _options == null ? void 0 : _options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oktaDefaultSignInResolver;
@@ -1456,14 +1637,14 @@ class BitbucketAuthProvider {
1456
1637
  });
1457
1638
  }
1458
1639
  async handler(req) {
1459
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
1640
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1460
1641
  return {
1461
1642
  response: await this.handleResult(result),
1462
1643
  refreshToken: privateInfo.refreshToken
1463
1644
  };
1464
1645
  }
1465
1646
  async refresh(req) {
1466
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1647
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1467
1648
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1468
1649
  return this.handleResult({
1469
1650
  fullProfile,
@@ -1474,7 +1655,7 @@ class BitbucketAuthProvider {
1474
1655
  }
1475
1656
  async handleResult(result) {
1476
1657
  result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
1477
- const {profile} = await this.authHandler(result);
1658
+ const { profile } = await this.authHandler(result);
1478
1659
  const response = {
1479
1660
  providerInfo: {
1480
1661
  idToken: result.params.id_token,
@@ -1498,7 +1679,7 @@ class BitbucketAuthProvider {
1498
1679
  }
1499
1680
  }
1500
1681
  const bitbucketUsernameSignInResolver = async (info, ctx) => {
1501
- const {result} = info;
1682
+ const { result } = info;
1502
1683
  if (!result.fullProfile.username) {
1503
1684
  throw new Error("Bitbucket profile contained no Username");
1504
1685
  }
@@ -1508,11 +1689,11 @@ const bitbucketUsernameSignInResolver = async (info, ctx) => {
1508
1689
  }
1509
1690
  });
1510
1691
  const claims = getEntityClaims(entity);
1511
- const token = await ctx.tokenIssuer.issueToken({claims});
1512
- return {id: entity.metadata.name, entity, token};
1692
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1693
+ return { id: entity.metadata.name, entity, token };
1513
1694
  };
1514
1695
  const bitbucketUserIdSignInResolver = async (info, ctx) => {
1515
- const {result} = info;
1696
+ const { result } = info;
1516
1697
  if (!result.fullProfile.id) {
1517
1698
  throw new Error("Bitbucket profile contained no User ID");
1518
1699
  }
@@ -1522,8 +1703,8 @@ const bitbucketUserIdSignInResolver = async (info, ctx) => {
1522
1703
  }
1523
1704
  });
1524
1705
  const claims = getEntityClaims(entity);
1525
- const token = await ctx.tokenIssuer.issueToken({claims});
1526
- return {id: entity.metadata.name, entity, token};
1706
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1707
+ return { id: entity.metadata.name, entity, token };
1527
1708
  };
1528
1709
  const createBitbucketProvider = (options) => {
1529
1710
  return ({
@@ -1542,7 +1723,7 @@ const createBitbucketProvider = (options) => {
1542
1723
  catalogApi,
1543
1724
  tokenIssuer
1544
1725
  });
1545
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile, params}) => ({
1726
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1546
1727
  profile: makeProfileInfo(fullProfile, params.id_token)
1547
1728
  });
1548
1729
  const provider = new BitbucketAuthProvider({
@@ -1564,7 +1745,7 @@ const createBitbucketProvider = (options) => {
1564
1745
  };
1565
1746
 
1566
1747
  const defaultScopes = ["offline_access", "read:me"];
1567
- class AtlassianStrategy extends OAuth2Strategy__default['default'] {
1748
+ class AtlassianStrategy extends OAuth2Strategy__default["default"] {
1568
1749
  constructor(options, verify) {
1569
1750
  if (!options.scope) {
1570
1751
  throw new TypeError("Atlassian requires a scope option");
@@ -1574,7 +1755,7 @@ class AtlassianStrategy extends OAuth2Strategy__default['default'] {
1574
1755
  ...options,
1575
1756
  authorizationURL: `https://auth.atlassian.com/authorize`,
1576
1757
  tokenURL: `https://auth.atlassian.com/oauth/token`,
1577
- scope: Array.from(new Set([...defaultScopes, ...scopes]))
1758
+ scope: Array.from(/* @__PURE__ */ new Set([...defaultScopes, ...scopes]))
1578
1759
  };
1579
1760
  super(optionsWithURLs, verify);
1580
1761
  this.profileURL = "https://api.atlassian.com/me";
@@ -1611,8 +1792,8 @@ class AtlassianStrategy extends OAuth2Strategy__default['default'] {
1611
1792
  provider: "atlassian",
1612
1793
  username: resp.nickname,
1613
1794
  displayName: resp.name,
1614
- emails: [{value: resp.email}],
1615
- photos: [{value: resp.picture}]
1795
+ emails: [{ value: resp.email }],
1796
+ photos: [{ value: resp.picture }]
1616
1797
  };
1617
1798
  }
1618
1799
  }
@@ -1651,14 +1832,14 @@ class AtlassianAuthProvider {
1651
1832
  }
1652
1833
  async handler(req) {
1653
1834
  var _a;
1654
- const {result} = await executeFrameHandlerStrategy(req, this._strategy);
1835
+ const { result } = await executeFrameHandlerStrategy(req, this._strategy);
1655
1836
  return {
1656
1837
  response: await this.handleResult(result),
1657
1838
  refreshToken: (_a = result.refreshToken) != null ? _a : ""
1658
1839
  };
1659
1840
  }
1660
1841
  async handleResult(result) {
1661
- const {profile} = await this.authHandler(result);
1842
+ const { profile } = await this.authHandler(result);
1662
1843
  const response = {
1663
1844
  providerInfo: {
1664
1845
  idToken: result.params.id_token,
@@ -1749,7 +1930,7 @@ class AwsAlbAuthProvider {
1749
1930
  this.tokenIssuer = options.tokenIssuer;
1750
1931
  this.catalogIdentityClient = options.catalogIdentityClient;
1751
1932
  this.logger = options.logger;
1752
- this.keyCache = new NodeCache__default['default']({stdTTL: 3600});
1933
+ this.keyCache = new NodeCache__default["default"]({ stdTTL: 3600 });
1753
1934
  }
1754
1935
  frameHandler() {
1755
1936
  return Promise.resolve(void 0);
@@ -1793,8 +1974,8 @@ class AwsAlbAuthProvider {
1793
1974
  familyName: claims.family_name,
1794
1975
  givenName: claims.given_name
1795
1976
  },
1796
- emails: [{value: claims.email.toLowerCase()}],
1797
- photos: [{value: claims.picture}]
1977
+ emails: [{ value: claims.email.toLowerCase() }],
1978
+ photos: [{ value: claims.picture }]
1798
1979
  };
1799
1980
  return {
1800
1981
  fullProfile,
@@ -1806,7 +1987,7 @@ class AwsAlbAuthProvider {
1806
1987
  }
1807
1988
  }
1808
1989
  async handleResult(result) {
1809
- const {profile} = await this.authHandler(result);
1990
+ const { profile } = await this.authHandler(result);
1810
1991
  const backstageIdentity = await this.signInResolver({
1811
1992
  result,
1812
1993
  profile
@@ -1820,7 +2001,7 @@ class AwsAlbAuthProvider {
1820
2001
  accessToken: result.accessToken,
1821
2002
  expiresInSeconds: result.expiresInSeconds
1822
2003
  },
1823
- backstageIdentity,
2004
+ backstageIdentity: prepareBackstageIdentityResponse(backstageIdentity),
1824
2005
  profile
1825
2006
  };
1826
2007
  }
@@ -1829,14 +2010,14 @@ class AwsAlbAuthProvider {
1829
2010
  if (optionalCacheKey) {
1830
2011
  return crypto__namespace.createPublicKey(optionalCacheKey);
1831
2012
  }
1832
- const keyText = await fetch__default['default'](`https://public-keys.auth.elb.${this.region}.amazonaws.com/${keyId}`).then((response) => response.text());
2013
+ const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${this.region}.amazonaws.com/${keyId}`).then((response) => response.text());
1833
2014
  const keyValue = crypto__namespace.createPublicKey(keyText);
1834
- this.keyCache.set(keyId, keyValue.export({format: "pem", type: "spki"}));
2015
+ this.keyCache.set(keyId, keyValue.export({ format: "pem", type: "spki" }));
1835
2016
  return keyValue;
1836
2017
  }
1837
2018
  }
1838
2019
  const createAwsAlbProvider = (options) => {
1839
- return ({config, tokenIssuer, catalogApi, logger}) => {
2020
+ return ({ config, tokenIssuer, catalogApi, logger }) => {
1840
2021
  const region = config.getString("region");
1841
2022
  const issuer = config.getOptionalString("iss");
1842
2023
  if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
@@ -1846,7 +2027,7 @@ const createAwsAlbProvider = (options) => {
1846
2027
  catalogApi,
1847
2028
  tokenIssuer
1848
2029
  });
1849
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile}) => ({
2030
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1850
2031
  profile: makeProfileInfo(fullProfile)
1851
2032
  });
1852
2033
  const signInResolver = options == null ? void 0 : options.signIn.resolver;
@@ -1862,182 +2043,98 @@ const createAwsAlbProvider = (options) => {
1862
2043
  };
1863
2044
  };
1864
2045
 
1865
- class OidcAuthProvider {
1866
- constructor(options) {
1867
- this.implementation = this.setupStrategy(options);
1868
- this.scope = options.scope;
1869
- this.prompt = options.prompt;
1870
- }
1871
- async start(req) {
1872
- const {strategy} = await this.implementation;
1873
- const options = {
1874
- accessType: "offline",
1875
- scope: req.scope || this.scope || "openid profile email",
1876
- state: encodeState(req.state)
1877
- };
1878
- const prompt = this.prompt || "none";
1879
- if (prompt !== "auto") {
1880
- options.prompt = prompt;
1881
- }
1882
- return await executeRedirectStrategy(req, strategy, options);
1883
- }
1884
- async handler(req) {
1885
- const {strategy} = await this.implementation;
1886
- const strategyResponse = await executeFrameHandlerStrategy(req, strategy);
1887
- const {
1888
- result: {userinfo, tokenset},
1889
- privateInfo
1890
- } = strategyResponse;
1891
- const identityResponse = await this.populateIdentity({
1892
- profile: {
1893
- displayName: userinfo.name,
1894
- email: userinfo.email,
1895
- picture: userinfo.picture
1896
- },
1897
- providerInfo: {
1898
- idToken: tokenset.id_token,
1899
- accessToken: tokenset.access_token || "",
1900
- scope: tokenset.scope || "",
1901
- expiresInSeconds: tokenset.expires_in
1902
- }
1903
- });
1904
- return {
1905
- response: identityResponse,
1906
- refreshToken: privateInfo.refreshToken
1907
- };
1908
- }
1909
- async refresh(req) {
1910
- const {client} = await this.implementation;
1911
- const tokenset = await client.refresh(req.refreshToken);
1912
- if (!tokenset.access_token) {
1913
- throw new Error("Refresh failed");
1914
- }
1915
- const profile = await client.userinfo(tokenset.access_token);
1916
- return this.populateIdentity({
1917
- providerInfo: {
1918
- accessToken: tokenset.access_token,
1919
- refreshToken: tokenset.refresh_token,
1920
- expiresInSeconds: tokenset.expires_in,
1921
- idToken: tokenset.id_token,
1922
- scope: tokenset.scope || ""
1923
- },
1924
- profile
1925
- });
1926
- }
1927
- async setupStrategy(options) {
1928
- const issuer = await openidClient.Issuer.discover(options.metadataUrl);
1929
- const client = new issuer.Client({
1930
- client_id: options.clientId,
1931
- client_secret: options.clientSecret,
1932
- redirect_uris: [options.callbackUrl],
1933
- response_types: ["code"],
1934
- id_token_signed_response_alg: options.tokenSignedResponseAlg || "RS256",
1935
- scope: options.scope || ""
1936
- });
1937
- const strategy = new openidClient.Strategy({
1938
- client,
1939
- passReqToCallback: false
1940
- }, (tokenset, userinfo, done) => {
1941
- if (typeof done !== "function") {
1942
- throw new Error("OIDC IdP must provide a userinfo_endpoint in the metadata response");
1943
- }
1944
- done(void 0, {tokenset, userinfo}, {
1945
- refreshToken: tokenset.refresh_token
1946
- });
1947
- });
1948
- strategy.error = console.error;
1949
- return {strategy, client};
1950
- }
1951
- async populateIdentity(response) {
1952
- const {profile} = response;
1953
- if (!profile.email) {
1954
- throw new Error("Profile does not contain an email");
1955
- }
1956
- const id = profile.email.split("@")[0];
1957
- return {...response, backstageIdentity: {id}};
1958
- }
1959
- }
1960
- const createOidcProvider = (_options) => {
1961
- return ({providerId, globalConfig, config, tokenIssuer}) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1962
- const clientId = envConfig.getString("clientId");
1963
- const clientSecret = envConfig.getString("clientSecret");
1964
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1965
- const metadataUrl = envConfig.getString("metadataUrl");
1966
- const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
1967
- const scope = envConfig.getOptionalString("scope");
1968
- const prompt = envConfig.getOptionalString("prompt");
1969
- const provider = new OidcAuthProvider({
1970
- clientId,
1971
- clientSecret,
1972
- callbackUrl,
1973
- tokenSignedResponseAlg,
1974
- metadataUrl,
1975
- scope,
1976
- prompt
1977
- });
1978
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1979
- disableRefresh: false,
1980
- providerId,
1981
- tokenIssuer
1982
- });
1983
- });
1984
- };
1985
-
1986
2046
  class SamlAuthProvider {
1987
2047
  constructor(options) {
1988
2048
  this.appUrl = options.appUrl;
2049
+ this.signInResolver = options.signInResolver;
2050
+ this.authHandler = options.authHandler;
1989
2051
  this.tokenIssuer = options.tokenIssuer;
1990
- this.strategy = new passportSaml.Strategy({...options}, (fullProfile, done) => {
1991
- done(void 0, {fullProfile});
2052
+ this.catalogIdentityClient = options.catalogIdentityClient;
2053
+ this.logger = options.logger;
2054
+ this.strategy = new passportSaml.Strategy({ ...options }, (fullProfile, done) => {
2055
+ done(void 0, { fullProfile });
1992
2056
  });
1993
2057
  }
1994
2058
  async start(req, res) {
1995
- const {url} = await executeRedirectStrategy(req, this.strategy, {});
2059
+ const { url } = await executeRedirectStrategy(req, this.strategy, {});
1996
2060
  res.redirect(url);
1997
2061
  }
1998
2062
  async frameHandler(req, res) {
1999
2063
  try {
2000
- const {result} = await executeFrameHandlerStrategy(req, this.strategy);
2001
- const id = result.fullProfile.nameID;
2002
- const idToken = await this.tokenIssuer.issueToken({
2003
- claims: {sub: id}
2004
- });
2064
+ const { result } = await executeFrameHandlerStrategy(req, this.strategy);
2065
+ const { profile } = await this.authHandler(result);
2066
+ const response = {
2067
+ profile,
2068
+ providerInfo: {}
2069
+ };
2070
+ if (this.signInResolver) {
2071
+ const signInResponse = await this.signInResolver({
2072
+ result,
2073
+ profile
2074
+ }, {
2075
+ tokenIssuer: this.tokenIssuer,
2076
+ catalogIdentityClient: this.catalogIdentityClient,
2077
+ logger: this.logger
2078
+ });
2079
+ response.backstageIdentity = prepareBackstageIdentityResponse(signInResponse);
2080
+ }
2005
2081
  return postMessageResponse(res, this.appUrl, {
2006
2082
  type: "authorization_response",
2007
- response: {
2008
- profile: {
2009
- email: result.fullProfile.email,
2010
- displayName: result.fullProfile.displayName
2011
- },
2012
- providerInfo: {},
2013
- backstageIdentity: {id, idToken}
2014
- }
2083
+ response
2015
2084
  });
2016
2085
  } catch (error) {
2017
- const {name, message} = errors.isError(error) ? error : new Error("Encountered invalid error");
2086
+ const { name, message } = errors.isError(error) ? error : new Error("Encountered invalid error");
2018
2087
  return postMessageResponse(res, this.appUrl, {
2019
2088
  type: "authorization_response",
2020
- error: {name, message}
2089
+ error: { name, message }
2021
2090
  });
2022
2091
  }
2023
2092
  }
2024
2093
  async logout(_req, res) {
2025
- res.send("noop");
2026
- }
2027
- identifyEnv() {
2028
- return void 0;
2094
+ res.end();
2029
2095
  }
2030
2096
  }
2031
- const createSamlProvider = (_options) => {
2032
- return ({providerId, globalConfig, config, tokenIssuer}) => {
2033
- const opts = {
2097
+ const samlDefaultSignInResolver = async (info, ctx) => {
2098
+ const id = info.result.fullProfile.nameID;
2099
+ const token = await ctx.tokenIssuer.issueToken({
2100
+ claims: { sub: id }
2101
+ });
2102
+ return { id, token };
2103
+ };
2104
+ const createSamlProvider = (options) => {
2105
+ return ({
2106
+ providerId,
2107
+ globalConfig,
2108
+ config,
2109
+ tokenIssuer,
2110
+ catalogApi,
2111
+ logger
2112
+ }) => {
2113
+ var _a, _b;
2114
+ const catalogIdentityClient = new CatalogIdentityClient({
2115
+ catalogApi,
2116
+ tokenIssuer
2117
+ });
2118
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2119
+ profile: {
2120
+ email: fullProfile.email,
2121
+ displayName: fullProfile.displayName
2122
+ }
2123
+ });
2124
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : samlDefaultSignInResolver;
2125
+ const signInResolver = (info) => signInResolverFn(info, {
2126
+ catalogIdentityClient,
2127
+ tokenIssuer,
2128
+ logger
2129
+ });
2130
+ return new SamlAuthProvider({
2034
2131
  callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
2035
2132
  entryPoint: config.getString("entryPoint"),
2036
2133
  logoutUrl: config.getOptionalString("logoutUrl"),
2037
2134
  audience: config.getOptionalString("audience"),
2038
2135
  issuer: config.getString("issuer"),
2039
2136
  cert: config.getString("cert"),
2040
- privateCert: config.getOptionalString("privateKey"),
2137
+ privateKey: config.getOptionalString("privateKey"),
2041
2138
  authnContext: config.getOptionalStringArray("authnContext"),
2042
2139
  identifierFormat: config.getOptionalString("identifierFormat"),
2043
2140
  decryptionPvk: config.getOptionalString("decryptionPvk"),
@@ -2045,13 +2142,16 @@ const createSamlProvider = (_options) => {
2045
2142
  digestAlgorithm: config.getOptionalString("digestAlgorithm"),
2046
2143
  acceptedClockSkewMs: config.getOptionalNumber("acceptedClockSkewMs"),
2047
2144
  tokenIssuer,
2048
- appUrl: globalConfig.appUrl
2049
- };
2050
- return new SamlAuthProvider(opts);
2145
+ appUrl: globalConfig.appUrl,
2146
+ authHandler,
2147
+ signInResolver,
2148
+ logger,
2149
+ catalogIdentityClient
2150
+ });
2051
2151
  };
2052
2152
  };
2053
2153
 
2054
- class Auth0Strategy extends OAuth2Strategy__default['default'] {
2154
+ class Auth0Strategy extends OAuth2Strategy__default["default"] {
2055
2155
  constructor(options, verify) {
2056
2156
  const optionsWithURLs = {
2057
2157
  ...options,
@@ -2092,7 +2192,7 @@ class Auth0AuthProvider {
2092
2192
  });
2093
2193
  }
2094
2194
  async handler(req) {
2095
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
2195
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
2096
2196
  const profile = makeProfileInfo(result.fullProfile, result.params.id_token);
2097
2197
  return {
2098
2198
  response: await this.populateIdentity({
@@ -2108,7 +2208,7 @@ class Auth0AuthProvider {
2108
2208
  };
2109
2209
  }
2110
2210
  async refresh(req) {
2111
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2211
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2112
2212
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2113
2213
  const profile = makeProfileInfo(fullProfile, params.id_token);
2114
2214
  return this.populateIdentity({
@@ -2122,16 +2222,16 @@ class Auth0AuthProvider {
2122
2222
  });
2123
2223
  }
2124
2224
  async populateIdentity(response) {
2125
- const {profile} = response;
2225
+ const { profile } = response;
2126
2226
  if (!profile.email) {
2127
2227
  throw new Error("Profile does not contain an email");
2128
2228
  }
2129
2229
  const id = profile.email.split("@")[0];
2130
- return {...response, backstageIdentity: {id}};
2230
+ return { ...response, backstageIdentity: { id, token: "" } };
2131
2231
  }
2132
2232
  }
2133
2233
  const createAuth0Provider = (_options) => {
2134
- return ({providerId, globalConfig, config, tokenIssuer}) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2234
+ return ({ providerId, globalConfig, config, tokenIssuer }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2135
2235
  const clientId = envConfig.getString("clientId");
2136
2236
  const clientSecret = envConfig.getString("clientSecret");
2137
2237
  const domain = envConfig.getString("domain");
@@ -2178,7 +2278,7 @@ class OneLoginProvider {
2178
2278
  });
2179
2279
  }
2180
2280
  async handler(req) {
2181
- const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
2281
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
2182
2282
  const profile = makeProfileInfo(result.fullProfile, result.params.id_token);
2183
2283
  return {
2184
2284
  response: await this.populateIdentity({
@@ -2194,7 +2294,7 @@ class OneLoginProvider {
2194
2294
  };
2195
2295
  }
2196
2296
  async refresh(req) {
2197
- const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2297
+ const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2198
2298
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2199
2299
  const profile = makeProfileInfo(fullProfile, params.id_token);
2200
2300
  return this.populateIdentity({
@@ -2208,16 +2308,16 @@ class OneLoginProvider {
2208
2308
  });
2209
2309
  }
2210
2310
  async populateIdentity(response) {
2211
- const {profile} = response;
2311
+ const { profile } = response;
2212
2312
  if (!profile.email) {
2213
2313
  throw new Error("OIDC profile contained no email");
2214
2314
  }
2215
2315
  const id = profile.email.split("@")[0];
2216
- return {...response, backstageIdentity: {id}};
2316
+ return { ...response, backstageIdentity: { id, token: "" } };
2217
2317
  }
2218
2318
  }
2219
2319
  const createOneLoginProvider = (_options) => {
2220
- return ({providerId, globalConfig, config, tokenIssuer}) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2320
+ return ({ providerId, globalConfig, config, tokenIssuer }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2221
2321
  const clientId = envConfig.getString("clientId");
2222
2322
  const clientSecret = envConfig.getString("clientSecret");
2223
2323
  const issuer = envConfig.getString("issuer");
@@ -2253,8 +2353,8 @@ const factories = {
2253
2353
  };
2254
2354
 
2255
2355
  function createOidcRouter(options) {
2256
- const {baseUrl, tokenIssuer} = options;
2257
- const router = Router__default['default']();
2356
+ const { baseUrl, tokenIssuer } = options;
2357
+ const router = Router__default["default"]();
2258
2358
  const config = {
2259
2359
  issuer: baseUrl,
2260
2360
  token_endpoint: `${baseUrl}/v1/token`,
@@ -2272,8 +2372,8 @@ function createOidcRouter(options) {
2272
2372
  res.json(config);
2273
2373
  });
2274
2374
  router.get("/.well-known/jwks.json", async (_req, res) => {
2275
- const {keys} = await tokenIssuer.listPublicKeys();
2276
- res.json({keys});
2375
+ const { keys } = await tokenIssuer.listPublicKeys();
2376
+ res.json({ keys });
2277
2377
  });
2278
2378
  router.get("/v1/token", (_req, res) => {
2279
2379
  res.status(501).send("Not Implemented");
@@ -2293,21 +2393,30 @@ class IdentityClient {
2293
2393
  this.keyStoreUpdated = 0;
2294
2394
  }
2295
2395
  async authenticate(token) {
2396
+ var _a;
2296
2397
  if (!token) {
2297
- throw new Error("No token specified");
2398
+ throw new errors.AuthenticationError("No token specified");
2298
2399
  }
2299
2400
  const key = await this.getKey(token);
2300
2401
  if (!key) {
2301
- throw new Error("No signing key matching token found");
2402
+ throw new errors.AuthenticationError("No signing key matching token found");
2302
2403
  }
2303
2404
  const decoded = jose.JWT.IdToken.verify(token, key, {
2304
2405
  algorithms: ["ES256"],
2305
2406
  audience: "backstage",
2306
2407
  issuer: this.issuer
2307
2408
  });
2409
+ if (!decoded.sub) {
2410
+ throw new errors.AuthenticationError("No user sub found in token");
2411
+ }
2308
2412
  const user = {
2309
2413
  id: decoded.sub,
2310
- idToken: token
2414
+ token,
2415
+ identity: {
2416
+ type: "user",
2417
+ userEntityRef: decoded.sub,
2418
+ ownershipEntityRefs: (_a = decoded.ent) != null ? _a : []
2419
+ }
2311
2420
  };
2312
2421
  return user;
2313
2422
  }
@@ -2319,19 +2428,19 @@ class IdentityClient {
2319
2428
  return matches == null ? void 0 : matches[1];
2320
2429
  }
2321
2430
  async getKey(rawJwtToken) {
2322
- const {header, payload} = jose.JWT.decode(rawJwtToken, {
2431
+ const { header, payload } = jose.JWT.decode(rawJwtToken, {
2323
2432
  complete: true
2324
2433
  });
2325
- const keyStoreHasKey = !!this.keyStore.get({kid: header.kid});
2434
+ const keyStoreHasKey = !!this.keyStore.get({ kid: header.kid });
2326
2435
  const issuedAfterLastRefresh = (payload == null ? void 0 : payload.iat) && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;
2327
2436
  if (!keyStoreHasKey && issuedAfterLastRefresh) {
2328
2437
  await this.refreshKeyStore();
2329
2438
  }
2330
- return this.keyStore.get({kid: header.kid});
2439
+ return this.keyStore.get({ kid: header.kid });
2331
2440
  }
2332
2441
  async listPublicKeys() {
2333
2442
  const url = `${await this.discovery.getBaseUrl("auth")}/.well-known/jwks.json`;
2334
- const response = await fetch__default['default'](url);
2443
+ const response = await fetch__default["default"](url);
2335
2444
  if (!response.ok) {
2336
2445
  const payload = await response.text();
2337
2446
  const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
@@ -2367,13 +2476,13 @@ class TokenFactory {
2367
2476
  const iat = Math.floor(Date.now() / MS_IN_S);
2368
2477
  const exp = iat + this.keyDurationSeconds;
2369
2478
  this.logger.info(`Issuing token for ${sub}, with entities ${ent != null ? ent : []}`);
2370
- return jose.JWS.sign({iss, sub, aud, iat, exp, ent}, key, {
2479
+ return jose.JWS.sign({ iss, sub, aud, iat, exp, ent }, key, {
2371
2480
  alg: key.alg,
2372
2481
  kid: key.kid
2373
2482
  });
2374
2483
  }
2375
2484
  async listPublicKeys() {
2376
- const {items: keys} = await this.keyStore.listKeys();
2485
+ const { items: keys } = await this.keyStore.listKeys();
2377
2486
  const validKeys = [];
2378
2487
  const expiredKeys = [];
2379
2488
  for (const key of keys) {
@@ -2387,13 +2496,13 @@ class TokenFactory {
2387
2496
  }
2388
2497
  }
2389
2498
  if (expiredKeys.length > 0) {
2390
- const kids = expiredKeys.map(({key}) => key.kid);
2499
+ const kids = expiredKeys.map(({ key }) => key.kid);
2391
2500
  this.logger.info(`Removing expired signing keys, '${kids.join("', '")}'`);
2392
2501
  this.keyStore.removeKeys(kids).catch((error) => {
2393
2502
  this.logger.error(`Failed to remove expired keys, ${error}`);
2394
2503
  });
2395
2504
  }
2396
- return {keys: validKeys.map(({key}) => key)};
2505
+ return { keys: validKeys.map(({ key }) => key) };
2397
2506
  }
2398
2507
  async getKey() {
2399
2508
  if (this.privateKeyPromise) {
@@ -2431,7 +2540,7 @@ class TokenFactory {
2431
2540
  const migrationsDir = backendCommon.resolvePackagePath("@backstage/plugin-auth-backend", "migrations");
2432
2541
  const TABLE = "signing_keys";
2433
2542
  const parseDate = (date) => {
2434
- const parsedDate = typeof date === "string" ? luxon.DateTime.fromSQL(date, {zone: "UTC"}) : luxon.DateTime.fromJSDate(date);
2543
+ const parsedDate = typeof date === "string" ? luxon.DateTime.fromSQL(date, { zone: "UTC" }) : luxon.DateTime.fromJSDate(date);
2435
2544
  if (!parsedDate.isValid) {
2436
2545
  throw new Error(`Failed to parse date, reason: ${parsedDate.invalidReason}, explanation: ${parsedDate.invalidExplanation}`);
2437
2546
  }
@@ -2439,7 +2548,7 @@ const parseDate = (date) => {
2439
2548
  };
2440
2549
  class DatabaseKeyStore {
2441
2550
  static async create(options) {
2442
- const {database} = options;
2551
+ const { database } = options;
2443
2552
  await database.migrate.latest({
2444
2553
  directory: migrationsDir
2445
2554
  });
@@ -2470,7 +2579,7 @@ class DatabaseKeyStore {
2470
2579
 
2471
2580
  class MemoryKeyStore {
2472
2581
  constructor() {
2473
- this.keys = new Map();
2582
+ this.keys = /* @__PURE__ */ new Map();
2474
2583
  }
2475
2584
  async addKey(key) {
2476
2585
  this.keys.set(key.kid, {
@@ -2485,7 +2594,7 @@ class MemoryKeyStore {
2485
2594
  }
2486
2595
  async listKeys() {
2487
2596
  return {
2488
- items: Array.from(this.keys).map(([, {createdAt, key: keyStr}]) => ({
2597
+ items: Array.from(this.keys).map(([, { createdAt, key: keyStr }]) => ({
2489
2598
  createdAt,
2490
2599
  key: JSON.parse(keyStr)
2491
2600
  }))
@@ -2502,7 +2611,7 @@ class FirestoreKeyStore {
2502
2611
  this.timeout = timeout;
2503
2612
  }
2504
2613
  static async create(settings) {
2505
- const {path, timeout, ...firestoreSettings} = settings != null ? settings : {};
2614
+ const { path, timeout, ...firestoreSettings } = settings != null ? settings : {};
2506
2615
  const database = new firestore.Firestore(firestoreSettings);
2507
2616
  return new FirestoreKeyStore(database, path != null ? path : DEFAULT_DOCUMENT_PATH, timeout != null ? timeout : DEFAULT_TIMEOUT_MS);
2508
2617
  }
@@ -2550,7 +2659,7 @@ class FirestoreKeyStore {
2550
2659
  class KeyStores {
2551
2660
  static async fromConfig(config, options) {
2552
2661
  var _a;
2553
- const {logger, database} = options != null ? options : {};
2662
+ const { logger, database } = options != null ? options : {};
2554
2663
  const ks = config.getOptionalConfig("auth.keyStore");
2555
2664
  const provider = (_a = ks == null ? void 0 : ks.getOptionalString("provider")) != null ? _a : "database";
2556
2665
  logger == null ? void 0 : logger.info(`Configuring "${provider}" as KeyStore provider`);
@@ -2583,36 +2692,31 @@ class KeyStores {
2583
2692
  }
2584
2693
  }
2585
2694
 
2586
- async function createRouter({
2587
- logger,
2588
- config,
2589
- discovery,
2590
- database,
2591
- providerFactories
2592
- }) {
2593
- const router = Router__default['default']();
2695
+ async function createRouter(options) {
2696
+ const { logger, config, discovery, database, providerFactories } = options;
2697
+ const router = Router__default["default"]();
2594
2698
  const appUrl = config.getString("app.baseUrl");
2595
2699
  const authUrl = await discovery.getExternalBaseUrl("auth");
2596
- const keyStore = await KeyStores.fromConfig(config, {logger, database});
2700
+ const keyStore = await KeyStores.fromConfig(config, { logger, database });
2597
2701
  const keyDurationSeconds = 3600;
2598
2702
  const tokenIssuer = new TokenFactory({
2599
2703
  issuer: authUrl,
2600
2704
  keyStore,
2601
2705
  keyDurationSeconds,
2602
- logger: logger.child({component: "token-factory"})
2706
+ logger: logger.child({ component: "token-factory" })
2603
2707
  });
2604
- const catalogApi = new catalogClient.CatalogClient({discoveryApi: discovery});
2708
+ const catalogApi = new catalogClient.CatalogClient({ discoveryApi: discovery });
2605
2709
  const secret = config.getOptionalString("auth.session.secret");
2606
2710
  if (secret) {
2607
- router.use(cookieParser__default['default'](secret));
2608
- router.use(session__default['default']({secret, saveUninitialized: false, resave: false}));
2609
- router.use(passport__default['default'].initialize());
2610
- router.use(passport__default['default'].session());
2711
+ router.use(cookieParser__default["default"](secret));
2712
+ router.use(session__default["default"]({ secret, saveUninitialized: false, resave: false }));
2713
+ router.use(passport__default["default"].initialize());
2714
+ router.use(passport__default["default"].session());
2611
2715
  } else {
2612
- router.use(cookieParser__default['default']());
2716
+ router.use(cookieParser__default["default"]());
2613
2717
  }
2614
- router.use(express__default['default'].urlencoded({extended: false}));
2615
- router.use(express__default['default'].json());
2718
+ router.use(express__default["default"].urlencoded({ extended: false }));
2719
+ router.use(express__default["default"].json());
2616
2720
  const allProviderFactories = {
2617
2721
  ...factories,
2618
2722
  ...providerFactories
@@ -2626,14 +2730,14 @@ async function createRouter({
2626
2730
  try {
2627
2731
  const provider = providerFactory({
2628
2732
  providerId,
2629
- globalConfig: {baseUrl: authUrl, appUrl, isOriginAllowed},
2733
+ globalConfig: { baseUrl: authUrl, appUrl, isOriginAllowed },
2630
2734
  config: providersConfig.getConfig(providerId),
2631
2735
  logger,
2632
2736
  tokenIssuer,
2633
2737
  discovery,
2634
2738
  catalogApi
2635
2739
  });
2636
- const r = Router__default['default']();
2740
+ const r = Router__default["default"]();
2637
2741
  r.get("/start", provider.start.bind(provider));
2638
2742
  r.get("/handler/frame", provider.frameHandler.bind(provider));
2639
2743
  r.post("/handler/frame", provider.frameHandler.bind(provider));
@@ -2665,7 +2769,7 @@ async function createRouter({
2665
2769
  baseUrl: authUrl
2666
2770
  }));
2667
2771
  router.use("/:provider/", (req) => {
2668
- const {provider} = req.params;
2772
+ const { provider } = req.params;
2669
2773
  throw new errors.NotFoundError(`Unknown auth provider '${provider}'`);
2670
2774
  });
2671
2775
  return router;
@@ -2673,9 +2777,9 @@ async function createRouter({
2673
2777
  function createOriginFilter(config) {
2674
2778
  var _a;
2675
2779
  const appUrl = config.getString("app.baseUrl");
2676
- const {origin: appOrigin} = new URL(appUrl);
2780
+ const { origin: appOrigin } = new URL(appUrl);
2677
2781
  const allowedOrigins = config.getOptionalStringArray("auth.experimentalExtraAllowedOrigins");
2678
- const allowedOriginPatterns = (_a = allowedOrigins == null ? void 0 : allowedOrigins.map((pattern) => new minimatch.Minimatch(pattern, {nocase: true, noglobstar: true}))) != null ? _a : [];
2782
+ const allowedOriginPatterns = (_a = allowedOrigins == null ? void 0 : allowedOrigins.map((pattern) => new minimatch.Minimatch(pattern, { nocase: true, noglobstar: true }))) != null ? _a : [];
2679
2783
  return (origin) => {
2680
2784
  if (origin === appOrigin) {
2681
2785
  return true;
@@ -2684,6 +2788,7 @@ function createOriginFilter(config) {
2684
2788
  };
2685
2789
  }
2686
2790
 
2791
+ exports.CatalogIdentityClient = CatalogIdentityClient;
2687
2792
  exports.IdentityClient = IdentityClient;
2688
2793
  exports.OAuthAdapter = OAuthAdapter;
2689
2794
  exports.OAuthEnvironmentHandler = OAuthEnvironmentHandler;
@@ -2697,16 +2802,20 @@ exports.createGitlabProvider = createGitlabProvider;
2697
2802
  exports.createGoogleProvider = createGoogleProvider;
2698
2803
  exports.createMicrosoftProvider = createMicrosoftProvider;
2699
2804
  exports.createOAuth2Provider = createOAuth2Provider;
2805
+ exports.createOidcProvider = createOidcProvider;
2700
2806
  exports.createOktaProvider = createOktaProvider;
2701
2807
  exports.createOriginFilter = createOriginFilter;
2702
2808
  exports.createRouter = createRouter;
2809
+ exports.createSamlProvider = createSamlProvider;
2703
2810
  exports.defaultAuthProviderFactories = factories;
2704
2811
  exports.encodeState = encodeState;
2705
2812
  exports.ensuresXRequestedWith = ensuresXRequestedWith;
2813
+ exports.getEntityClaims = getEntityClaims;
2706
2814
  exports.googleEmailSignInResolver = googleEmailSignInResolver;
2707
2815
  exports.microsoftEmailSignInResolver = microsoftEmailSignInResolver;
2708
2816
  exports.oktaEmailSignInResolver = oktaEmailSignInResolver;
2709
2817
  exports.postMessageResponse = postMessageResponse;
2818
+ exports.prepareBackstageIdentityResponse = prepareBackstageIdentityResponse;
2710
2819
  exports.readState = readState;
2711
2820
  exports.verifyNonce = verifyNonce;
2712
2821
  //# sourceMappingURL=index.cjs.js.map