@backstage/plugin-auth-backend 0.7.0 → 0.9.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
@@ -149,6 +149,16 @@ const verifyNonce = (req, providerId) => {
149
149
  throw new Error("Invalid nonce");
150
150
  }
151
151
  };
152
+ const getCookieConfig = (authUrl, providerId) => {
153
+ const { hostname: cookieDomain, pathname, protocol } = authUrl;
154
+ const secure = protocol === "https:";
155
+ const cookiePath = pathname.endsWith(`${providerId}/handler/frame`) ? pathname.slice(0, -"/handler/frame".length) : `${pathname}/${providerId}`;
156
+ return {
157
+ cookieDomain,
158
+ cookiePath,
159
+ secure
160
+ };
161
+ };
152
162
 
153
163
  class OAuthEnvironmentHandler {
154
164
  constructor(handlers) {
@@ -271,56 +281,48 @@ class OAuthAdapter {
271
281
  this.setNonceCookie = (res, nonce) => {
272
282
  res.cookie(`${this.options.providerId}-nonce`, nonce, {
273
283
  maxAge: TEN_MINUTES_MS,
274
- secure: this.options.secure,
275
- sameSite: "lax",
276
- domain: this.options.cookieDomain,
277
- path: `${this.options.cookiePath}/handler`,
278
- httpOnly: true
284
+ ...this.baseCookieOptions,
285
+ path: `${this.options.cookiePath}/handler`
279
286
  });
280
287
  };
281
- this.setScopesCookie = (res, scope) => {
282
- res.cookie(`${this.options.providerId}-scope`, scope, {
283
- maxAge: TEN_MINUTES_MS,
284
- secure: this.options.secure,
285
- sameSite: "lax",
286
- domain: this.options.cookieDomain,
287
- path: `${this.options.cookiePath}/handler`,
288
- httpOnly: true
288
+ this.setGrantedScopeCookie = (res, scope) => {
289
+ res.cookie(`${this.options.providerId}-granted-scope`, scope, {
290
+ maxAge: THOUSAND_DAYS_MS,
291
+ ...this.baseCookieOptions
289
292
  });
290
293
  };
291
- this.getScopesFromCookie = (req, providerId) => {
292
- return req.cookies[`${providerId}-scope`];
294
+ this.getGrantedScopeFromCookie = (req) => {
295
+ return req.cookies[`${this.options.providerId}-granted-scope`];
293
296
  };
294
297
  this.setRefreshTokenCookie = (res, refreshToken) => {
295
298
  res.cookie(`${this.options.providerId}-refresh-token`, refreshToken, {
296
299
  maxAge: THOUSAND_DAYS_MS,
297
- secure: this.options.secure,
298
- sameSite: "lax",
299
- domain: this.options.cookieDomain,
300
- path: this.options.cookiePath,
301
- httpOnly: true
300
+ ...this.baseCookieOptions
302
301
  });
303
302
  };
304
303
  this.removeRefreshTokenCookie = (res) => {
305
304
  res.cookie(`${this.options.providerId}-refresh-token`, "", {
306
305
  maxAge: 0,
307
- secure: this.options.secure,
308
- sameSite: "lax",
309
- domain: this.options.cookieDomain,
310
- path: this.options.cookiePath,
311
- httpOnly: true
306
+ ...this.baseCookieOptions
312
307
  });
313
308
  };
309
+ this.baseCookieOptions = {
310
+ httpOnly: true,
311
+ sameSite: "lax",
312
+ secure: this.options.secure,
313
+ path: this.options.cookiePath,
314
+ domain: this.options.cookieDomain
315
+ };
314
316
  }
315
317
  static fromConfig(config, handlers, options) {
318
+ var _a;
316
319
  const { origin: appOrigin } = new url.URL(config.appUrl);
317
- const secure = config.baseUrl.startsWith("https://");
318
- const url$1 = new url.URL(config.baseUrl);
319
- const cookiePath = `${url$1.pathname}/${options.providerId}`;
320
+ const authUrl = new url.URL((_a = options.callbackUrl) != null ? _a : config.baseUrl);
321
+ const { cookieDomain, cookiePath, secure } = getCookieConfig(authUrl, options.providerId);
320
322
  return new OAuthAdapter(handlers, {
321
323
  ...options,
322
324
  appOrigin,
323
- cookieDomain: url$1.hostname,
325
+ cookieDomain,
324
326
  cookiePath,
325
327
  secure,
326
328
  isOriginAllowed: config.isOriginAllowed
@@ -334,12 +336,12 @@ class OAuthAdapter {
334
336
  if (!env) {
335
337
  throw new errors.InputError("No env provided in request query parameters");
336
338
  }
337
- if (this.options.persistScopes) {
338
- this.setScopesCookie(res, scope);
339
- }
340
339
  const nonce = crypto__default["default"].randomBytes(16).toString("base64");
341
340
  this.setNonceCookie(res, nonce);
342
341
  const state = { nonce, env, origin };
342
+ if (this.options.persistScopes) {
343
+ state.scope = scope;
344
+ }
343
345
  const forwardReq = Object.assign(req, { scope, state });
344
346
  const { url, status } = await this.handlers.start(forwardReq);
345
347
  res.statusCode = status || 302;
@@ -364,9 +366,9 @@ class OAuthAdapter {
364
366
  }
365
367
  verifyNonce(req, this.options.providerId);
366
368
  const { response, refreshToken } = await this.handlers.handler(req);
367
- if (this.options.persistScopes) {
368
- const grantedScopes = this.getScopesFromCookie(req, this.options.providerId);
369
- response.providerInfo.scope = grantedScopes;
369
+ if (this.options.persistScopes && state.scope) {
370
+ this.setGrantedScopeCookie(res, state.scope);
371
+ response.providerInfo.scope = state.scope;
370
372
  }
371
373
  if (refreshToken && !this.options.disableRefresh) {
372
374
  this.setRefreshTokenCookie(res, refreshToken);
@@ -404,7 +406,10 @@ class OAuthAdapter {
404
406
  if (!refreshToken) {
405
407
  throw new errors.InputError("Missing session cookie");
406
408
  }
407
- const scope = (_b = (_a = req.query.scope) == null ? void 0 : _a.toString()) != null ? _b : "";
409
+ let scope = (_b = (_a = req.query.scope) == null ? void 0 : _a.toString()) != null ? _b : "";
410
+ if (this.options.persistScopes) {
411
+ scope = this.getGrantedScopeFromCookie(req);
412
+ }
408
413
  const forwardReq = Object.assign(req, { scope, refreshToken });
409
414
  const { response, refreshToken: newRefreshToken } = await this.handlers.refresh(forwardReq);
410
415
  const backstageIdentity = await this.populateIdentity(response.backstageIdentity);
@@ -550,7 +555,7 @@ const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) =>
550
555
  class CatalogIdentityClient {
551
556
  constructor(options) {
552
557
  this.catalogApi = options.catalogApi;
553
- this.tokenIssuer = options.tokenIssuer;
558
+ this.tokenManager = options.tokenManager;
554
559
  }
555
560
  async findUser(query) {
556
561
  const filter = {
@@ -559,9 +564,7 @@ class CatalogIdentityClient {
559
564
  for (const [key, value] of Object.entries(query.annotations)) {
560
565
  filter[`metadata.annotations.${key}`] = value;
561
566
  }
562
- const token = await this.tokenIssuer.issueToken({
563
- claims: { sub: "backstage.io/auth-backend" }
564
- });
567
+ const { token } = await this.tokenManager.getToken();
565
568
  const { items } = await this.catalogApi.getEntities({ filter }, { token });
566
569
  if (items.length !== 1) {
567
570
  if (items.length > 1) {
@@ -591,7 +594,8 @@ class CatalogIdentityClient {
591
594
  "metadata.namespace": ref.namespace,
592
595
  "metadata.name": ref.name
593
596
  }));
594
- const entities = await this.catalogApi.getEntities({ filter }).then((r) => r.items);
597
+ const { token } = await this.tokenManager.getToken();
598
+ const entities = await this.catalogApi.getEntities({ filter }, { token }).then((r) => r.items);
595
599
  if (entityRefs.length !== entities.length) {
596
600
  const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
597
601
  const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
@@ -701,6 +705,7 @@ const createAtlassianProvider = (options) => {
701
705
  globalConfig,
702
706
  config,
703
707
  tokenIssuer,
708
+ tokenManager,
704
709
  catalogApi,
705
710
  logger
706
711
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -708,10 +713,11 @@ const createAtlassianProvider = (options) => {
708
713
  const clientId = envConfig.getString("clientId");
709
714
  const clientSecret = envConfig.getString("clientSecret");
710
715
  const scopes = envConfig.getString("scopes");
711
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
716
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
717
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
712
718
  const catalogIdentityClient = new CatalogIdentityClient({
713
719
  catalogApi,
714
- tokenIssuer
720
+ tokenManager
715
721
  });
716
722
  const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
717
723
  const provider = new AtlassianAuthProvider({
@@ -728,7 +734,8 @@ const createAtlassianProvider = (options) => {
728
734
  return OAuthAdapter.fromConfig(globalConfig, provider, {
729
735
  disableRefresh: true,
730
736
  providerId,
731
- tokenIssuer
737
+ tokenIssuer,
738
+ callbackUrl
732
739
  });
733
740
  });
734
741
  };
@@ -836,6 +843,7 @@ const createAuth0Provider = (options) => {
836
843
  globalConfig,
837
844
  config,
838
845
  tokenIssuer,
846
+ tokenManager,
839
847
  catalogApi,
840
848
  logger
841
849
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -843,10 +851,11 @@ const createAuth0Provider = (options) => {
843
851
  const clientId = envConfig.getString("clientId");
844
852
  const clientSecret = envConfig.getString("clientSecret");
845
853
  const domain = envConfig.getString("domain");
846
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
854
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
855
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
847
856
  const catalogIdentityClient = new CatalogIdentityClient({
848
857
  catalogApi,
849
- tokenIssuer
858
+ tokenManager
850
859
  });
851
860
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
852
861
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -866,7 +875,8 @@ const createAuth0Provider = (options) => {
866
875
  return OAuthAdapter.fromConfig(globalConfig, provider, {
867
876
  disableRefresh: true,
868
877
  providerId,
869
- tokenIssuer
878
+ tokenIssuer,
879
+ callbackUrl
870
880
  });
871
881
  });
872
882
  };
@@ -974,7 +984,7 @@ class AwsAlbAuthProvider {
974
984
  }
975
985
  }
976
986
  const createAwsAlbProvider = (options) => {
977
- return ({ config, tokenIssuer, catalogApi, logger }) => {
987
+ return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
978
988
  const region = config.getString("region");
979
989
  const issuer = config.getOptionalString("iss");
980
990
  if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
@@ -982,7 +992,7 @@ const createAwsAlbProvider = (options) => {
982
992
  }
983
993
  const catalogIdentityClient = new CatalogIdentityClient({
984
994
  catalogApi,
985
- tokenIssuer
995
+ tokenManager
986
996
  });
987
997
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
988
998
  profile: makeProfileInfo(fullProfile)
@@ -1110,16 +1120,18 @@ const createBitbucketProvider = (options) => {
1110
1120
  globalConfig,
1111
1121
  config,
1112
1122
  tokenIssuer,
1123
+ tokenManager,
1113
1124
  catalogApi,
1114
1125
  logger
1115
1126
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1116
1127
  var _a;
1117
1128
  const clientId = envConfig.getString("clientId");
1118
1129
  const clientSecret = envConfig.getString("clientSecret");
1119
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1130
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1131
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1120
1132
  const catalogIdentityClient = new CatalogIdentityClient({
1121
1133
  catalogApi,
1122
- tokenIssuer
1134
+ tokenManager
1123
1135
  });
1124
1136
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1125
1137
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -1137,11 +1149,14 @@ const createBitbucketProvider = (options) => {
1137
1149
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1138
1150
  disableRefresh: false,
1139
1151
  providerId,
1140
- tokenIssuer
1152
+ tokenIssuer,
1153
+ callbackUrl
1141
1154
  });
1142
1155
  });
1143
1156
  };
1144
1157
 
1158
+ const ACCESS_TOKEN_PREFIX = "access-token.";
1159
+ const BACKSTAGE_SESSION_EXPIRATION = 3600;
1145
1160
  class GithubAuthProvider {
1146
1161
  constructor(options) {
1147
1162
  this.signInResolver = options.signInResolver;
@@ -1169,21 +1184,43 @@ class GithubAuthProvider {
1169
1184
  }
1170
1185
  async handler(req) {
1171
1186
  const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1187
+ let refreshToken = privateInfo.refreshToken;
1188
+ if (!refreshToken && !result.params.expires_in) {
1189
+ refreshToken = ACCESS_TOKEN_PREFIX + result.accessToken;
1190
+ }
1172
1191
  return {
1173
1192
  response: await this.handleResult(result),
1174
- refreshToken: privateInfo.refreshToken
1193
+ refreshToken
1175
1194
  };
1176
1195
  }
1177
1196
  async refresh(req) {
1178
- const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1179
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1197
+ const { scope, refreshToken } = req;
1198
+ if (refreshToken == null ? void 0 : refreshToken.startsWith(ACCESS_TOKEN_PREFIX)) {
1199
+ const accessToken = refreshToken.slice(ACCESS_TOKEN_PREFIX.length);
1200
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken).catch((error) => {
1201
+ var _a;
1202
+ if (((_a = error.oauthError) == null ? void 0 : _a.statusCode) === 401) {
1203
+ throw new Error("Invalid access token");
1204
+ }
1205
+ throw error;
1206
+ });
1207
+ return {
1208
+ response: await this.handleResult({
1209
+ fullProfile,
1210
+ params: { scope },
1211
+ accessToken
1212
+ }),
1213
+ refreshToken
1214
+ };
1215
+ }
1216
+ const result = await executeRefreshTokenStrategy(this._strategy, refreshToken, scope);
1180
1217
  return {
1181
1218
  response: await this.handleResult({
1182
- fullProfile,
1183
- params,
1184
- accessToken
1219
+ fullProfile: await executeFetchUserProfileStrategy(this._strategy, result.accessToken),
1220
+ params: { ...result.params, scope },
1221
+ accessToken: result.accessToken
1185
1222
  }),
1186
- refreshToken
1223
+ refreshToken: result.refreshToken
1187
1224
  };
1188
1225
  }
1189
1226
  async handleResult(result) {
@@ -1194,21 +1231,28 @@ class GithubAuthProvider {
1194
1231
  };
1195
1232
  const { profile } = await this.authHandler(result, context);
1196
1233
  const expiresInStr = result.params.expires_in;
1197
- const response = {
1234
+ let expiresInSeconds = expiresInStr === void 0 ? void 0 : Number(expiresInStr);
1235
+ let backstageIdentity = void 0;
1236
+ if (this.signInResolver) {
1237
+ backstageIdentity = await this.signInResolver({
1238
+ result,
1239
+ profile
1240
+ }, context);
1241
+ if (expiresInSeconds) {
1242
+ expiresInSeconds = Math.min(expiresInSeconds, BACKSTAGE_SESSION_EXPIRATION);
1243
+ } else {
1244
+ expiresInSeconds = BACKSTAGE_SESSION_EXPIRATION;
1245
+ }
1246
+ }
1247
+ return {
1248
+ backstageIdentity,
1198
1249
  providerInfo: {
1199
1250
  accessToken: result.accessToken,
1200
1251
  scope: result.params.scope,
1201
- expiresInSeconds: expiresInStr === void 0 ? void 0 : Number(expiresInStr)
1252
+ expiresInSeconds
1202
1253
  },
1203
1254
  profile
1204
1255
  };
1205
- if (this.signInResolver) {
1206
- response.backstageIdentity = await this.signInResolver({
1207
- result,
1208
- profile
1209
- }, context);
1210
- }
1211
- return response;
1212
1256
  }
1213
1257
  }
1214
1258
  const githubDefaultSignInResolver = async (info, ctx) => {
@@ -1228,6 +1272,7 @@ const createGithubProvider = (options) => {
1228
1272
  globalConfig,
1229
1273
  config,
1230
1274
  tokenIssuer,
1275
+ tokenManager,
1231
1276
  catalogApi,
1232
1277
  logger
1233
1278
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -1242,7 +1287,7 @@ const createGithubProvider = (options) => {
1242
1287
  const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1243
1288
  const catalogIdentityClient = new CatalogIdentityClient({
1244
1289
  catalogApi,
1245
- tokenIssuer
1290
+ tokenManager
1246
1291
  });
1247
1292
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1248
1293
  profile: makeProfileInfo(fullProfile)
@@ -1273,7 +1318,8 @@ const createGithubProvider = (options) => {
1273
1318
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1274
1319
  persistScopes: true,
1275
1320
  providerId,
1276
- tokenIssuer
1321
+ tokenIssuer,
1322
+ callbackUrl
1277
1323
  });
1278
1324
  });
1279
1325
  };
@@ -1369,6 +1415,7 @@ const createGitlabProvider = (options) => {
1369
1415
  globalConfig,
1370
1416
  config,
1371
1417
  tokenIssuer,
1418
+ tokenManager,
1372
1419
  catalogApi,
1373
1420
  logger
1374
1421
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -1377,10 +1424,11 @@ const createGitlabProvider = (options) => {
1377
1424
  const clientSecret = envConfig.getString("clientSecret");
1378
1425
  const audience = envConfig.getOptionalString("audience");
1379
1426
  const baseUrl = audience || "https://gitlab.com";
1380
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1427
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1428
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1381
1429
  const catalogIdentityClient = new CatalogIdentityClient({
1382
1430
  catalogApi,
1383
- tokenIssuer
1431
+ tokenManager
1384
1432
  });
1385
1433
  const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
1386
1434
  const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : gitlabDefaultSignInResolver;
@@ -1403,7 +1451,8 @@ const createGitlabProvider = (options) => {
1403
1451
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1404
1452
  disableRefresh: false,
1405
1453
  providerId,
1406
- tokenIssuer
1454
+ tokenIssuer,
1455
+ callbackUrl
1407
1456
  });
1408
1457
  });
1409
1458
  };
@@ -1515,7 +1564,7 @@ const googleDefaultSignInResolver = async (info, ctx) => {
1515
1564
  userId = profile.email.split("@")[0];
1516
1565
  }
1517
1566
  const token = await ctx.tokenIssuer.issueToken({
1518
- claims: { sub: userId, ent: [`user:default/${userId}`] }
1567
+ claims: { sub: `user:default/${userId}`, ent: [`user:default/${userId}`] }
1519
1568
  });
1520
1569
  return { id: userId, token };
1521
1570
  };
@@ -1525,16 +1574,18 @@ const createGoogleProvider = (options) => {
1525
1574
  globalConfig,
1526
1575
  config,
1527
1576
  tokenIssuer,
1577
+ tokenManager,
1528
1578
  catalogApi,
1529
1579
  logger
1530
1580
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1531
1581
  var _a, _b;
1532
1582
  const clientId = envConfig.getString("clientId");
1533
1583
  const clientSecret = envConfig.getString("clientSecret");
1534
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1584
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1585
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1535
1586
  const catalogIdentityClient = new CatalogIdentityClient({
1536
1587
  catalogApi,
1537
- tokenIssuer
1588
+ tokenManager
1538
1589
  });
1539
1590
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1540
1591
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -1558,7 +1609,8 @@ const createGoogleProvider = (options) => {
1558
1609
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1559
1610
  disableRefresh: false,
1560
1611
  providerId,
1561
- tokenIssuer
1612
+ tokenIssuer,
1613
+ callbackUrl
1562
1614
  });
1563
1615
  });
1564
1616
  };
@@ -1682,6 +1734,7 @@ const createMicrosoftProvider = (options) => {
1682
1734
  globalConfig,
1683
1735
  config,
1684
1736
  tokenIssuer,
1737
+ tokenManager,
1685
1738
  catalogApi,
1686
1739
  logger
1687
1740
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -1689,12 +1742,13 @@ const createMicrosoftProvider = (options) => {
1689
1742
  const clientId = envConfig.getString("clientId");
1690
1743
  const clientSecret = envConfig.getString("clientSecret");
1691
1744
  const tenantId = envConfig.getString("tenantId");
1692
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1745
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1746
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1693
1747
  const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1694
1748
  const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1695
1749
  const catalogIdentityClient = new CatalogIdentityClient({
1696
1750
  catalogApi,
1697
- tokenIssuer
1751
+ tokenManager
1698
1752
  });
1699
1753
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1700
1754
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -1720,7 +1774,8 @@ const createMicrosoftProvider = (options) => {
1720
1774
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1721
1775
  disableRefresh: false,
1722
1776
  providerId,
1723
- tokenIssuer
1777
+ tokenIssuer,
1778
+ callbackUrl
1724
1779
  });
1725
1780
  });
1726
1781
  };
@@ -1827,13 +1882,15 @@ const createOAuth2Provider = (options) => {
1827
1882
  globalConfig,
1828
1883
  config,
1829
1884
  tokenIssuer,
1885
+ tokenManager,
1830
1886
  catalogApi,
1831
1887
  logger
1832
1888
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1833
1889
  var _a, _b, _c;
1834
1890
  const clientId = envConfig.getString("clientId");
1835
1891
  const clientSecret = envConfig.getString("clientSecret");
1836
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1892
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1893
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1837
1894
  const authorizationUrl = envConfig.getString("authorizationUrl");
1838
1895
  const tokenUrl = envConfig.getString("tokenUrl");
1839
1896
  const scope = envConfig.getOptionalString("scope");
@@ -1841,7 +1898,7 @@ const createOAuth2Provider = (options) => {
1841
1898
  const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1842
1899
  const catalogIdentityClient = new CatalogIdentityClient({
1843
1900
  catalogApi,
1844
- tokenIssuer
1901
+ tokenManager
1845
1902
  });
1846
1903
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1847
1904
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -1869,7 +1926,8 @@ const createOAuth2Provider = (options) => {
1869
1926
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1870
1927
  disableRefresh,
1871
1928
  providerId,
1872
- tokenIssuer
1929
+ tokenIssuer,
1930
+ callbackUrl
1873
1931
  });
1874
1932
  });
1875
1933
  };
@@ -2272,12 +2330,12 @@ class Oauth2ProxyAuthProvider {
2272
2330
  };
2273
2331
  }
2274
2332
  }
2275
- const createOauth2ProxyProvider = (options) => ({ catalogApi, logger, tokenIssuer }) => {
2333
+ const createOauth2ProxyProvider = (options) => ({ catalogApi, logger, tokenIssuer, tokenManager }) => {
2276
2334
  const signInResolver = options.signIn.resolver;
2277
2335
  const authHandler = options.authHandler;
2278
2336
  const catalogIdentityClient = new CatalogIdentityClient({
2279
2337
  catalogApi,
2280
- tokenIssuer
2338
+ tokenManager
2281
2339
  });
2282
2340
  return new Oauth2ProxyAuthProvider({
2283
2341
  logger,
@@ -2388,7 +2446,10 @@ const oAuth2DefaultSignInResolver = async (info, ctx) => {
2388
2446
  }
2389
2447
  const userId = profile.email.split("@")[0];
2390
2448
  const token = await ctx.tokenIssuer.issueToken({
2391
- claims: { sub: userId, ent: [`user:default/${userId}`] }
2449
+ claims: {
2450
+ sub: `user:default/${userId}`,
2451
+ ent: [`user:default/${userId}`]
2452
+ }
2392
2453
  });
2393
2454
  return { id: userId, token };
2394
2455
  };
@@ -2398,20 +2459,22 @@ const createOidcProvider = (options) => {
2398
2459
  globalConfig,
2399
2460
  config,
2400
2461
  tokenIssuer,
2462
+ tokenManager,
2401
2463
  catalogApi,
2402
2464
  logger
2403
2465
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2404
2466
  var _a, _b;
2405
2467
  const clientId = envConfig.getString("clientId");
2406
2468
  const clientSecret = envConfig.getString("clientSecret");
2407
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2469
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2470
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2408
2471
  const metadataUrl = envConfig.getString("metadataUrl");
2409
2472
  const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
2410
2473
  const scope = envConfig.getOptionalString("scope");
2411
2474
  const prompt = envConfig.getOptionalString("prompt");
2412
2475
  const catalogIdentityClient = new CatalogIdentityClient({
2413
2476
  catalogApi,
2414
- tokenIssuer
2477
+ tokenManager
2415
2478
  });
2416
2479
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
2417
2480
  profile: {
@@ -2443,7 +2506,8 @@ const createOidcProvider = (options) => {
2443
2506
  return OAuthAdapter.fromConfig(globalConfig, provider, {
2444
2507
  disableRefresh: false,
2445
2508
  providerId,
2446
- tokenIssuer
2509
+ tokenIssuer,
2510
+ callbackUrl
2447
2511
  });
2448
2512
  });
2449
2513
  };
@@ -2565,6 +2629,7 @@ const createOktaProvider = (_options) => {
2565
2629
  globalConfig,
2566
2630
  config,
2567
2631
  tokenIssuer,
2632
+ tokenManager,
2568
2633
  catalogApi,
2569
2634
  logger
2570
2635
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -2572,13 +2637,14 @@ const createOktaProvider = (_options) => {
2572
2637
  const clientId = envConfig.getString("clientId");
2573
2638
  const clientSecret = envConfig.getString("clientSecret");
2574
2639
  const audience = envConfig.getString("audience");
2575
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2640
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2641
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2576
2642
  if (!audience.startsWith("https://")) {
2577
2643
  throw new Error("URL for 'audience' must start with 'https://'.");
2578
2644
  }
2579
2645
  const catalogIdentityClient = new CatalogIdentityClient({
2580
2646
  catalogApi,
2581
- tokenIssuer
2647
+ tokenManager
2582
2648
  });
2583
2649
  const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
2584
2650
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -2603,7 +2669,8 @@ const createOktaProvider = (_options) => {
2603
2669
  return OAuthAdapter.fromConfig(globalConfig, provider, {
2604
2670
  disableRefresh: false,
2605
2671
  providerId,
2606
- tokenIssuer
2672
+ tokenIssuer,
2673
+ callbackUrl
2607
2674
  });
2608
2675
  });
2609
2676
  };
@@ -2698,6 +2765,7 @@ const createOneLoginProvider = (options) => {
2698
2765
  globalConfig,
2699
2766
  config,
2700
2767
  tokenIssuer,
2768
+ tokenManager,
2701
2769
  catalogApi,
2702
2770
  logger
2703
2771
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
@@ -2705,10 +2773,11 @@ const createOneLoginProvider = (options) => {
2705
2773
  const clientId = envConfig.getString("clientId");
2706
2774
  const clientSecret = envConfig.getString("clientSecret");
2707
2775
  const issuer = envConfig.getString("issuer");
2708
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2776
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2777
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2709
2778
  const catalogIdentityClient = new CatalogIdentityClient({
2710
2779
  catalogApi,
2711
- tokenIssuer
2780
+ tokenManager
2712
2781
  });
2713
2782
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
2714
2783
  profile: makeProfileInfo(fullProfile, params.id_token)
@@ -2728,7 +2797,8 @@ const createOneLoginProvider = (options) => {
2728
2797
  return OAuthAdapter.fromConfig(globalConfig, provider, {
2729
2798
  disableRefresh: false,
2730
2799
  providerId,
2731
- tokenIssuer
2800
+ tokenIssuer,
2801
+ callbackUrl
2732
2802
  });
2733
2803
  });
2734
2804
  };
@@ -2798,13 +2868,14 @@ const createSamlProvider = (options) => {
2798
2868
  globalConfig,
2799
2869
  config,
2800
2870
  tokenIssuer,
2871
+ tokenManager,
2801
2872
  catalogApi,
2802
2873
  logger
2803
2874
  }) => {
2804
2875
  var _a, _b;
2805
2876
  const catalogIdentityClient = new CatalogIdentityClient({
2806
2877
  catalogApi,
2807
- tokenIssuer
2878
+ tokenManager
2808
2879
  });
2809
2880
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2810
2881
  profile: {
@@ -2912,7 +2983,7 @@ class GcpIapProvider {
2912
2983
  }
2913
2984
  }
2914
2985
  function createGcpIapProvider(options) {
2915
- return ({ config, tokenIssuer, catalogApi, logger }) => {
2986
+ return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
2916
2987
  var _a;
2917
2988
  const audience = config.getString("audience");
2918
2989
  const authHandler = (_a = options.authHandler) != null ? _a : defaultAuthHandler;
@@ -2920,7 +2991,7 @@ function createGcpIapProvider(options) {
2920
2991
  const tokenValidator = createTokenValidator(audience);
2921
2992
  const catalogIdentityClient = new CatalogIdentityClient({
2922
2993
  catalogApi,
2923
- tokenIssuer
2994
+ tokenManager
2924
2995
  });
2925
2996
  return new GcpIapProvider({
2926
2997
  authHandler,
@@ -2950,7 +3021,14 @@ const factories = {
2950
3021
  };
2951
3022
 
2952
3023
  async function createRouter(options) {
2953
- const { logger, config, discovery, database, providerFactories } = options;
3024
+ const {
3025
+ logger,
3026
+ config,
3027
+ discovery,
3028
+ database,
3029
+ tokenManager,
3030
+ providerFactories
3031
+ } = options;
2954
3032
  const router = Router__default["default"]();
2955
3033
  const appUrl = config.getString("app.baseUrl");
2956
3034
  const authUrl = await discovery.getExternalBaseUrl("auth");
@@ -2996,6 +3074,7 @@ async function createRouter(options) {
2996
3074
  globalConfig: { baseUrl: authUrl, appUrl, isOriginAllowed },
2997
3075
  config: providersConfig.getConfig(providerId),
2998
3076
  logger,
3077
+ tokenManager,
2999
3078
  tokenIssuer,
3000
3079
  discovery,
3001
3080
  catalogApi