@backstage/plugin-auth-node 0.4.14-next.1 → 0.4.14-next.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @backstage/plugin-auth-node
2
2
 
3
+ ## 0.4.14-next.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 798ec37: Updated scope management for OAuth providers, where the `createOAuthAuthenticator` now accepts a new collection of `scopes` options:
8
+
9
+ - `scopes.persist` - Whether scopes should be persisted, replaces the `shouldPersistScopes` option.
10
+ - `scopes.required` - A list of required scopes that will always be requested.
11
+ - `scopes.transform` - A function that can be used to transform the scopes before they are requested.
12
+
13
+ The `createOAuthProviderFactory` has also received a new `additionalScopes` option, and will also read `additionalScopes` from the auth provider configuration. Both of these can be used to add additional scopes that should always be requested.
14
+
15
+ A significant change under the hood that this new scope management brings is that providers that persist scopes will now always merge the already granted scopes with the requested ones. The previous behavior was that the full authorization flow would not include existing scopes, while the refresh flow would only include the existing scopes.
16
+
17
+ - d44a20a: Added additional plugin metadata to `package.json`.
18
+ - Updated dependencies
19
+ - @backstage/backend-plugin-api@0.6.19-next.3
20
+ - @backstage/backend-common@0.23.0-next.3
21
+ - @backstage/catalog-client@1.6.5
22
+ - @backstage/catalog-model@1.5.0
23
+ - @backstage/config@1.2.0
24
+ - @backstage/errors@1.2.4
25
+ - @backstage/types@1.1.1
26
+
27
+ ## 0.4.14-next.2
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies
32
+ - @backstage/backend-plugin-api@0.6.19-next.2
33
+ - @backstage/backend-common@0.23.0-next.2
34
+ - @backstage/catalog-client@1.6.5
35
+ - @backstage/catalog-model@1.5.0
36
+ - @backstage/config@1.2.0
37
+ - @backstage/errors@1.2.4
38
+ - @backstage/types@1.1.1
39
+
3
40
  ## 0.4.14-next.1
4
41
 
5
42
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -284,6 +284,12 @@ class OAuthCookieManager {
284
284
  ...this.getConfig(origin)
285
285
  });
286
286
  }
287
+ removeGrantedScopes(res, origin) {
288
+ res.cookie(this.grantedScopeCookie, "", {
289
+ maxAge: 0,
290
+ ...this.getConfig(origin)
291
+ });
292
+ }
287
293
  setGrantedScopes(res, scope, origin) {
288
294
  res.cookie(this.grantedScopeCookie, scope, {
289
295
  maxAge: THOUSAND_DAYS_MS,
@@ -301,6 +307,90 @@ class OAuthCookieManager {
301
307
  }
302
308
  }
303
309
 
310
+ function reqRes(req) {
311
+ const res = req.res;
312
+ if (!res) {
313
+ throw new Error("No response object found in request");
314
+ }
315
+ return res;
316
+ }
317
+ const defaultTransform = ({ requested, granted, required, additional }) => {
318
+ return [...requested, ...granted, ...required, ...additional];
319
+ };
320
+ function splitScope(scope) {
321
+ if (!scope) {
322
+ return [];
323
+ }
324
+ return scope.split(/[\s|,]/).filter(Boolean);
325
+ }
326
+ class CookieScopeManager {
327
+ constructor(scopeTransform, cookieManager) {
328
+ this.scopeTransform = scopeTransform;
329
+ this.cookieManager = cookieManager;
330
+ }
331
+ static create(options) {
332
+ const { authenticator, config } = options;
333
+ const shouldPersistScopes = authenticator.scopes?.persist ?? authenticator.shouldPersistScopes ?? false;
334
+ const configScopes = typeof config?.getOptional("additionalScopes") === "string" ? splitScope(config.getString("additionalScopes")) : config?.getOptionalStringArray("additionalScopes") ?? [];
335
+ const transform = authenticator?.scopes?.transform ?? defaultTransform;
336
+ const additional = [...configScopes, ...options.additionalScopes ?? []];
337
+ const required = authenticator?.scopes?.required ?? [];
338
+ return new CookieScopeManager(
339
+ (requested, granted) => Array.from(
340
+ new Set(transform({ required, additional, requested, granted }))
341
+ ).join(" "),
342
+ shouldPersistScopes ? options.cookieManager : void 0
343
+ );
344
+ }
345
+ async start(req) {
346
+ const requestScope = splitScope(req.query.scope?.toString());
347
+ const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));
348
+ const scope = this.scopeTransform(requestScope, grantedScope);
349
+ if (this.cookieManager) {
350
+ return {
351
+ scope,
352
+ scopeState: { scope }
353
+ };
354
+ }
355
+ return { scope };
356
+ }
357
+ async handleCallback(req, ctx) {
358
+ if (!this.cookieManager) {
359
+ return Array.from(splitScope(ctx.result.session.scope)).join(" ");
360
+ }
361
+ const scope = ctx.state.scope;
362
+ if (scope === void 0) {
363
+ throw new errors.AuthenticationError("No scope found in OAuth state");
364
+ }
365
+ this.cookieManager.setGrantedScopes(reqRes(req), scope, ctx.origin);
366
+ return scope;
367
+ }
368
+ async clear(req) {
369
+ if (this.cookieManager) {
370
+ this.cookieManager.removeGrantedScopes(reqRes(req), req.get("origin"));
371
+ }
372
+ }
373
+ async refresh(req) {
374
+ const requestScope = splitScope(req.query.scope?.toString());
375
+ const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));
376
+ const scope = this.scopeTransform(requestScope, grantedScope);
377
+ return {
378
+ scope,
379
+ commit: async (result) => {
380
+ if (this.cookieManager) {
381
+ this.cookieManager.setGrantedScopes(
382
+ reqRes(req),
383
+ scope,
384
+ req.get("origin")
385
+ );
386
+ return scope;
387
+ }
388
+ return Array.from(splitScope(result.session.scope)).join(" ");
389
+ }
390
+ };
391
+ }
392
+ }
393
+
304
394
  function createOAuthRouteHandlers(options) {
305
395
  const {
306
396
  authenticator,
@@ -325,9 +415,14 @@ function createOAuthRouteHandlers(options) {
325
415
  providerId,
326
416
  cookieConfigurer
327
417
  });
418
+ const scopeManager = CookieScopeManager.create({
419
+ config,
420
+ authenticator,
421
+ cookieManager,
422
+ additionalScopes: options.additionalScopes
423
+ });
328
424
  return {
329
425
  async start(req, res) {
330
- const scope = req.query.scope?.toString() ?? "";
331
426
  const env = req.query.env?.toString();
332
427
  const origin = req.query.origin?.toString();
333
428
  const redirectUrl = req.query.redirectUrl?.toString();
@@ -337,14 +432,15 @@ function createOAuthRouteHandlers(options) {
337
432
  }
338
433
  const nonce = crypto__default.default.randomBytes(16).toString("base64");
339
434
  cookieManager.setNonce(res, nonce, origin);
340
- const state = { nonce, env, origin, redirectUrl, flow };
341
- if (authenticator.shouldPersistScopes && scope) {
342
- state.scope = scope;
343
- }
435
+ const { scope, scopeState } = await scopeManager.start(req);
436
+ const state = { nonce, env, origin, redirectUrl, flow, ...scopeState };
344
437
  const { state: transformedState } = await stateTransform(state, { req });
345
- const encodedState = encodeOAuthState(transformedState);
346
438
  const { url, status } = await options.authenticator.start(
347
- { req, scope, state: encodedState },
439
+ {
440
+ req,
441
+ scope,
442
+ state: encodeOAuthState(transformedState)
443
+ },
348
444
  authenticatorCtx
349
445
  );
350
446
  res.statusCode = status || 302;
@@ -353,17 +449,17 @@ function createOAuthRouteHandlers(options) {
353
449
  res.end();
354
450
  },
355
451
  async frameHandler(req, res) {
356
- let appOrigin = defaultAppOrigin;
452
+ let origin = defaultAppOrigin;
357
453
  try {
358
454
  const state = decodeOAuthState(req.query.state?.toString() ?? "");
359
455
  if (state.origin) {
360
456
  try {
361
- appOrigin = new url.URL(state.origin).origin;
457
+ origin = new url.URL(state.origin).origin;
362
458
  } catch {
363
459
  throw new errors.NotAllowedError("App origin is invalid, failed to parse");
364
460
  }
365
- if (!isOriginAllowed(appOrigin)) {
366
- throw new errors.NotAllowedError(`Origin '${appOrigin}' is not allowed`);
461
+ if (!isOriginAllowed(origin)) {
462
+ throw new errors.NotAllowedError(`Origin '${origin}' is not allowed`);
367
463
  }
368
464
  }
369
465
  const cookieNonce = cookieManager.getNonce(req);
@@ -379,31 +475,29 @@ function createOAuthRouteHandlers(options) {
379
475
  authenticatorCtx
380
476
  );
381
477
  const { profile } = await profileTransform(result, resolverContext);
478
+ const signInResult = signInResolver && await signInResolver({ profile, result }, resolverContext);
479
+ const grantedScopes = await scopeManager.handleCallback(req, {
480
+ result,
481
+ state,
482
+ origin
483
+ });
382
484
  const response = {
383
485
  profile,
384
486
  providerInfo: {
385
487
  idToken: result.session.idToken,
386
488
  accessToken: result.session.accessToken,
387
- scope: result.session.scope,
489
+ scope: grantedScopes,
388
490
  expiresInSeconds: result.session.expiresInSeconds
491
+ },
492
+ ...signInResult && {
493
+ backstageIdentity: prepareBackstageIdentityResponse(signInResult)
389
494
  }
390
495
  };
391
- if (signInResolver) {
392
- const identity = await signInResolver(
393
- { profile, result },
394
- resolverContext
395
- );
396
- response.backstageIdentity = prepareBackstageIdentityResponse(identity);
397
- }
398
- if (authenticator.shouldPersistScopes && state.scope) {
399
- cookieManager.setGrantedScopes(res, state.scope, appOrigin);
400
- response.providerInfo.scope = state.scope;
401
- }
402
496
  if (result.session.refreshToken) {
403
497
  cookieManager.setRefreshToken(
404
498
  res,
405
499
  result.session.refreshToken,
406
- appOrigin
500
+ origin
407
501
  );
408
502
  }
409
503
  if (state.flow === "redirect") {
@@ -415,13 +509,13 @@ function createOAuthRouteHandlers(options) {
415
509
  res.redirect(state.redirectUrl);
416
510
  return;
417
511
  }
418
- sendWebMessageResponse(res, appOrigin, {
512
+ sendWebMessageResponse(res, origin, {
419
513
  type: "authorization_response",
420
514
  response
421
515
  });
422
516
  } catch (error) {
423
517
  const { name, message } = errors.isError(error) ? error : new Error("Encountered invalid error");
424
- sendWebMessageResponse(res, appOrigin, {
518
+ sendWebMessageResponse(res, origin, {
425
519
  type: "authorization_response",
426
520
  error: { name, message }
427
521
  });
@@ -436,6 +530,7 @@ function createOAuthRouteHandlers(options) {
436
530
  await authenticator.logout({ req, refreshToken }, authenticatorCtx);
437
531
  }
438
532
  cookieManager.removeRefreshToken(res, req.get("origin"));
533
+ await scopeManager.clear(req);
439
534
  res.status(200).end();
440
535
  },
441
536
  async refresh(req, res) {
@@ -447,14 +542,12 @@ function createOAuthRouteHandlers(options) {
447
542
  if (!refreshToken) {
448
543
  throw new errors.InputError("Missing session cookie");
449
544
  }
450
- let scope = req.query.scope?.toString() ?? "";
451
- if (authenticator.shouldPersistScopes) {
452
- scope = cookieManager.getGrantedScopes(req);
453
- }
545
+ const scopeRefresh = await scopeManager.refresh(req);
454
546
  const result = await authenticator.refresh(
455
- { req, scope, refreshToken },
547
+ { req, scope: scopeRefresh.scope, refreshToken },
456
548
  authenticatorCtx
457
549
  );
550
+ const grantedScope = await scopeRefresh.commit(result);
458
551
  const { profile } = await profileTransform(result, resolverContext);
459
552
  const newRefreshToken = result.session.refreshToken;
460
553
  if (newRefreshToken && newRefreshToken !== refreshToken) {
@@ -469,7 +562,7 @@ function createOAuthRouteHandlers(options) {
469
562
  providerInfo: {
470
563
  idToken: result.session.idToken,
471
564
  accessToken: result.session.accessToken,
472
- scope: authenticator.shouldPersistScopes ? scope : result.session.scope,
565
+ scope: grantedScope,
473
566
  expiresInSeconds: result.session.expiresInSeconds
474
567
  }
475
568
  };
@@ -845,6 +938,7 @@ function createOAuthProviderFactory(options) {
845
938
  cookieConfigurer: ctx.cookieConfigurer,
846
939
  providerId: ctx.providerId,
847
940
  resolverContext: ctx.resolverContext,
941
+ additionalScopes: options.additionalScopes,
848
942
  stateTransform: options.stateTransform,
849
943
  profileTransform: options.profileTransform,
850
944
  signInResolver
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/extensions/AuthProvidersExtensionPoint.ts","../src/extensions/AuthOwnershipResolutionExtensionPoint.ts","../src/flow/sendWebMessageResponse.ts","../src/identity/prepareBackstageIdentityResponse.ts","../src/identity/getBearerTokenFromAuthorizationHeader.ts","../src/identity/DefaultIdentityClient.ts","../src/identity/IdentityClient.ts","../src/oauth/state.ts","../src/oauth/OAuthCookieManager.ts","../src/oauth/createOAuthRouteHandlers.ts","../src/passport/PassportHelpers.ts","../src/oauth/PassportOAuthAuthenticatorHelper.ts","../src/oauth/OAuthEnvironmentHandler.ts","../src/sign-in/createSignInResolverFactory.ts","../src/sign-in/readDeclarativeSignInResolver.ts","../src/sign-in/commonSignInResolvers.ts","../src/oauth/createOAuthProviderFactory.ts","../src/oauth/types.ts","../src/proxy/types.ts","../src/proxy/createProxyRouteHandlers.ts","../src/proxy/createProxyAuthProviderFactory.ts","../src/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { AuthProviderFactory } from '../types';\n\n/** @public */\nexport interface AuthProviderRegistrationOptions {\n providerId: string;\n factory: AuthProviderFactory;\n}\n\n/** @public */\nexport interface AuthProvidersExtensionPoint {\n registerProvider(options: AuthProviderRegistrationOptions): void;\n}\n\n/** @public */\nexport const authProvidersExtensionPoint =\n createExtensionPoint<AuthProvidersExtensionPoint>({\n id: 'auth.providers',\n });\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AuthOwnershipResolver } from '../types';\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\n\n/** @public */\nexport interface AuthOwnershipResolutionExtensionPoint {\n setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;\n}\n\n/** @public */\nexport const authOwnershipResolutionExtensionPoint =\n createExtensionPoint<AuthOwnershipResolutionExtensionPoint>({\n id: 'auth.ownershipResolution',\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Response } from 'express';\nimport crypto from 'crypto';\nimport { ClientAuthResponse } from '../types';\nimport { serializeError } from '@backstage/errors';\n\n/**\n * Payload sent as a post message after the auth request is complete.\n * If successful then has a valid payload with Auth information else contains an error.\n *\n * @public\n */\nexport type WebMessageResponse =\n | {\n type: 'authorization_response';\n response: ClientAuthResponse<unknown>;\n }\n | {\n type: 'authorization_response';\n error: Error;\n };\n\n/** @internal */\nexport function safelyEncodeURIComponent(value: string): string {\n // Note the g at the end of the regex; all occurrences of single quotes must\n // be replaced, which encodeURIComponent does not do itself by default\n return encodeURIComponent(value).replace(/'/g, '%27');\n}\n\n/** @public */\nexport function sendWebMessageResponse(\n res: Response,\n appOrigin: string,\n response: WebMessageResponse,\n): void {\n const jsonData = JSON.stringify(response, (_, value) => {\n if (value instanceof Error) {\n return serializeError(value);\n }\n return value;\n });\n const base64Data = safelyEncodeURIComponent(jsonData);\n const base64Origin = safelyEncodeURIComponent(appOrigin);\n\n // NOTE: It is absolutely imperative that we use the safe encoder above, to\n // be sure that the js code below does not allow the injection of malicious\n // data.\n\n // TODO: Make target app origin configurable globally\n\n //\n // postMessage fails silently if the targetOrigin is disallowed.\n // So 2 postMessages are sent from the popup to the parent window.\n // First, the origin being used to post the actual authorization response is\n // shared with the parent window with a postMessage with targetOrigin '*'.\n // Second, the actual authorization response is sent with the app origin\n // as the targetOrigin.\n // If the first message was received but the actual auth response was\n // never received, the event listener can conclude that targetOrigin\n // was disallowed, indicating potential misconfiguration.\n //\n const script = `\n var authResponse = decodeURIComponent('${base64Data}');\n var origin = decodeURIComponent('${base64Origin}');\n var originInfo = {'type': 'config_info', 'targetOrigin': origin};\n (window.opener || window.parent).postMessage(originInfo, '*');\n (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);\n setTimeout(() => {\n window.close();\n }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)\n `;\n const hash = crypto.createHash('sha256').update(script).digest('base64');\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('X-Frame-Options', 'sameorigin');\n res.setHeader('Content-Security-Policy', `script-src 'sha256-${hash}'`);\n res.end(`<html><body><script>${script}</script></body></html>`);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport {\n BackstageIdentityResponse,\n BackstageSignInResult,\n} from '@backstage/plugin-auth-node';\n\nfunction parseJwtPayload(token: string) {\n const [_header, payload, _signature] = token.split('.');\n return JSON.parse(Buffer.from(payload, 'base64').toString());\n}\n\n/**\n * Parses a Backstage-issued token and decorates the\n * {@link @backstage/plugin-auth-node#BackstageIdentityResponse} with identity information sourced from the\n * token.\n *\n * @public\n */\nexport function prepareBackstageIdentityResponse(\n result: BackstageSignInResult,\n): BackstageIdentityResponse {\n if (!result.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n const { sub, ent = [], exp: expStr } = parseJwtPayload(result.token);\n if (!sub) {\n throw new InputError(\n `Identity response must return a token with subject claim`,\n );\n }\n\n const expAt = Number(expStr);\n\n // Default to 1 hour if no expiration is set, in particular to make testing simpler\n const exp = expAt ? Math.round(expAt - Date.now() / 1000) : undefined;\n if (exp && exp < 0) {\n throw new InputError(`Identity response must not return an expired token`);\n }\n\n return {\n ...result,\n expiresInSeconds: exp,\n identity: {\n type: 'user',\n userEntityRef: sub,\n ownershipEntityRefs: ent,\n },\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Parses the given authorization header and returns the bearer token, or\n * undefined if no bearer token is given.\n *\n * @remarks\n *\n * This function is explicitly built to tolerate bad inputs safely, so you may\n * call it directly with e.g. the output of `req.header('authorization')`\n * without first checking that it exists.\n *\n * @deprecated Use the `credentials` method of `HttpAuthService` from `@backstage/backend-plugin-api` instead\n * @public\n */\nexport function getBearerTokenFromAuthorizationHeader(\n authorizationHeader: unknown,\n): string | undefined {\n if (typeof authorizationHeader !== 'string') {\n return undefined;\n }\n const matches = authorizationHeader.match(/^Bearer[ ]+(\\S+)$/i);\n return matches?.[1];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n jwtVerify,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\nimport { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';\nimport { IdentityApi, IdentityApiGetIdentityRequest } from './IdentityApi';\nimport { BackstageIdentityResponse } from '../types';\n\nconst CLOCK_MARGIN_S = 10;\n\n/**\n * An identity client options object which allows extra configurations\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport type IdentityClientOptions = {\n discovery: PluginEndpointDiscovery;\n issuer?: string;\n\n /** JWS \"alg\" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithms?: string[];\n};\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport class DefaultIdentityClient implements IdentityApi {\n private readonly discovery: PluginEndpointDiscovery;\n private readonly issuer?: string;\n private readonly algorithms?: string[];\n private keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;\n private keyStoreUpdated: number = 0;\n\n /**\n * Create a new {@link DefaultIdentityClient} instance.\n */\n static create(options: IdentityClientOptions): DefaultIdentityClient {\n return new DefaultIdentityClient(options);\n }\n\n private constructor(options: IdentityClientOptions) {\n this.discovery = options.discovery;\n this.issuer = options.issuer;\n this.algorithms = options.hasOwnProperty('algorithms')\n ? options.algorithms\n : ['ES256'];\n }\n\n async getIdentity(options: IdentityApiGetIdentityRequest) {\n const {\n request: { headers },\n } = options;\n if (!headers.authorization) {\n return undefined;\n }\n try {\n return await this.authenticate(\n getBearerTokenFromAuthorizationHeader(headers.authorization),\n );\n } catch (e) {\n throw new AuthenticationError(e.message);\n }\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use getIdentity instead of authenticate to retrieve the user\n * identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise<BackstageIdentityResponse> {\n // Extract token from header\n if (!token) {\n throw new AuthenticationError('No token specified');\n }\n\n // Verify token claims and signature\n // Note: Claims must match those set by TokenFactory when issuing tokens\n // Note: verify throws if verification fails\n // Check if the keystore needs to be updated\n await this.refreshKeyStore(token);\n if (!this.keyStore) {\n throw new AuthenticationError('No keystore exists');\n }\n const decoded = await jwtVerify(token, this.keyStore, {\n algorithms: this.algorithms,\n audience: 'backstage',\n issuer: this.issuer,\n });\n // Verified, return the matching user as BackstageIdentity\n // TODO: Settle internal user format/properties\n if (!decoded.payload.sub) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n const user: BackstageIdentityResponse = {\n token,\n identity: {\n type: 'user',\n userEntityRef: decoded.payload.sub,\n ownershipEntityRefs: decoded.payload.ent\n ? (decoded.payload.ent as string[])\n : [],\n },\n };\n return user;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n private async refreshKeyStore(rawJwtToken: string): Promise<void> {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const url = await this.discovery.getBaseUrl('auth');\n const endpoint = new URL(`${url}/.well-known/jwks.json`);\n this.keyStore = createRemoteJWKSet(endpoint);\n this.keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultIdentityClient,\n IdentityClientOptions,\n} from './DefaultIdentityClient';\nimport { BackstageIdentityResponse } from '../types';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @public\n * @experimental This is not a stable API yet\n * @deprecated Please migrate to the DefaultIdentityClient.\n */\nexport class IdentityClient {\n private readonly defaultIdentityClient: DefaultIdentityClient;\n static create(options: IdentityClientOptions): IdentityClient {\n return new IdentityClient(DefaultIdentityClient.create(options));\n }\n\n private constructor(defaultIdentityClient: DefaultIdentityClient) {\n this.defaultIdentityClient = defaultIdentityClient;\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use IdentityApi#getIdentity instead of authenticate\n * to retrieve the user identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise<BackstageIdentityResponse> {\n return await this.defaultIdentityClient.authenticate(token);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport pickBy from 'lodash/pickBy';\nimport { Request } from 'express';\nimport { NotAllowedError } from '@backstage/errors';\n\n/**\n * A type for the serialized value in the `state` parameter of the OAuth authorization flow\n * @public\n */\nexport type OAuthState = {\n nonce: string;\n env: string;\n origin?: string;\n scope?: string;\n redirectUrl?: string;\n flow?: string;\n audience?: string;\n};\n\n/** @public */\nexport type OAuthStateTransform = (\n state: OAuthState,\n context: { req: Request },\n) => Promise<{ state: OAuthState }>;\n\n/** @public */\nexport function encodeOAuthState(state: OAuthState): string {\n const stateString = new URLSearchParams(\n pickBy<string>(state, value => value !== undefined),\n ).toString();\n\n return Buffer.from(stateString, 'utf-8').toString('hex');\n}\n\n/** @public */\nexport function decodeOAuthState(encodedState: string): OAuthState {\n const state = Object.fromEntries(\n new URLSearchParams(Buffer.from(encodedState, 'hex').toString('utf-8')),\n );\n if (!state.env || state.env?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing env');\n }\n if (!state.nonce || state.nonce?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing nonce');\n }\n\n return state as OAuthState;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { CookieConfigurer } from '../types';\n\nconst THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nconst TEN_MINUTES_MS = 600 * 1000;\n\nconst defaultCookieConfigurer: CookieConfigurer = ({\n callbackUrl,\n providerId,\n appOrigin,\n}) => {\n const { hostname: domain, pathname, protocol } = new URL(callbackUrl);\n const secure = protocol === 'https:';\n\n // For situations where the auth-backend is running on a\n // different domain than the app, we set the SameSite attribute\n // to 'none' to allow third-party access to the cookie, but\n // only if it's in a secure context (https).\n let sameSite: ReturnType<CookieConfigurer>['sameSite'] = 'lax';\n if (new URL(appOrigin).hostname !== domain && secure) {\n sameSite = 'none';\n }\n\n // If the provider supports callbackUrls, the pathname will\n // contain the complete path to the frame handler so we need\n // to slice off the trailing part of the path.\n const path = pathname.endsWith(`${providerId}/handler/frame`)\n ? pathname.slice(0, -'/handler/frame'.length)\n : `${pathname}/${providerId}`;\n\n return { domain, path, secure, sameSite };\n};\n\n/** @internal */\nexport class OAuthCookieManager {\n private readonly cookieConfigurer: CookieConfigurer;\n private readonly nonceCookie: string;\n private readonly refreshTokenCookie: string;\n private readonly grantedScopeCookie: string;\n\n constructor(\n private readonly options: {\n providerId: string;\n defaultAppOrigin: string;\n baseUrl: string;\n callbackUrl: string;\n cookieConfigurer?: CookieConfigurer;\n },\n ) {\n this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer;\n\n this.nonceCookie = `${options.providerId}-nonce`;\n this.refreshTokenCookie = `${options.providerId}-refresh-token`;\n this.grantedScopeCookie = `${options.providerId}-granted-scope`;\n }\n\n private getConfig(origin?: string, pathSuffix: string = '') {\n const cookieConfig = this.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.defaultAppOrigin,\n });\n return {\n httpOnly: true,\n sameSite: 'lax' as const,\n ...cookieConfig,\n path: cookieConfig.path + pathSuffix,\n };\n }\n\n setNonce(res: Response, nonce: string, origin?: string) {\n res.cookie(this.nonceCookie, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.getConfig(origin, '/handler'),\n });\n }\n\n setRefreshToken(res: Response, refreshToken: string, origin?: string) {\n res.cookie(this.refreshTokenCookie, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n removeRefreshToken(res: Response, origin?: string) {\n res.cookie(this.refreshTokenCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n setGrantedScopes(res: Response, scope: string, origin?: string) {\n res.cookie(this.grantedScopeCookie, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n getNonce(req: Request) {\n return req.cookies[this.nonceCookie];\n }\n\n getRefreshToken(req: Request) {\n return req.cookies[this.refreshTokenCookie];\n }\n\n getGrantedScopes(req: Request) {\n return req.cookies[this.grantedScopeCookie];\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport {\n encodeOAuthState,\n decodeOAuthState,\n OAuthStateTransform,\n OAuthState,\n} from './state';\nimport { sendWebMessageResponse } from '../flow';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n CookieConfigurer,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { Config } from '@backstage/config';\n\n/** @public */\nexport interface OAuthRouteHandlersOptions<TProfile> {\n authenticator: OAuthAuthenticator<any, TProfile>;\n appUrl: string;\n baseUrl: string;\n isOriginAllowed: (origin: string) => boolean;\n providerId: string;\n config: Config;\n resolverContext: AuthResolverContext;\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n cookieConfigurer?: CookieConfigurer;\n signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;\n}\n\n/** @internal */\ntype ClientOAuthResponse = ClientAuthResponse<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * (Optional) Id token issued for the signed in user.\n */\n idToken?: string;\n /**\n * Expiry of the access token in seconds.\n */\n expiresInSeconds?: number;\n /**\n * Scopes granted for the access token.\n */\n scope: string;\n}>;\n\n/** @public */\nexport function createOAuthRouteHandlers<TProfile>(\n options: OAuthRouteHandlersOptions<TProfile>,\n): AuthProviderRouteHandlers {\n const {\n authenticator,\n config,\n baseUrl,\n appUrl,\n providerId,\n isOriginAllowed,\n cookieConfigurer,\n resolverContext,\n signInResolver,\n } = options;\n\n const defaultAppOrigin = new URL(appUrl).origin;\n const callbackUrl =\n config.getOptionalString('callbackUrl') ??\n `${baseUrl}/${providerId}/handler/frame`;\n\n const stateTransform = options.stateTransform ?? (state => ({ state }));\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config, callbackUrl });\n const cookieManager = new OAuthCookieManager({\n baseUrl,\n callbackUrl,\n defaultAppOrigin,\n providerId,\n cookieConfigurer,\n });\n\n return {\n async start(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n // retrieve scopes from request\n const scope = req.query.scope?.toString() ?? '';\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n cookieManager.setNonce(res, nonce, origin);\n\n const state: OAuthState = { nonce, env, origin, redirectUrl, flow };\n\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n if (authenticator.shouldPersistScopes && scope) {\n state.scope = scope;\n }\n\n const { state: transformedState } = await stateTransform(state, { req });\n const encodedState = encodeOAuthState(transformedState);\n\n const { url, status } = await options.authenticator.start(\n { req, scope, state: encodedState },\n authenticatorCtx,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n },\n\n async frameHandler(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n let appOrigin = defaultAppOrigin;\n\n try {\n const state = decodeOAuthState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n appOrigin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!isOriginAllowed(appOrigin)) {\n throw new NotAllowedError(`Origin '${appOrigin}' is not allowed`);\n }\n }\n\n // The same nonce is passed through cookie and state, and they must match\n const cookieNonce = cookieManager.getNonce(req);\n const stateNonce = state.nonce;\n if (!cookieNonce) {\n throw new NotAllowedError('Auth response is missing cookie nonce');\n }\n if (cookieNonce !== stateNonce) {\n throw new NotAllowedError('Invalid nonce');\n }\n\n const result = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n const { profile } = await profileTransform(result, resolverContext);\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: result.session.scope,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n };\n\n if (signInResolver) {\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n response.backstageIdentity =\n prepareBackstageIdentityResponse(identity);\n }\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n if (authenticator.shouldPersistScopes && state.scope) {\n cookieManager.setGrantedScopes(res, state.scope, appOrigin);\n response.providerInfo.scope = state.scope;\n }\n\n if (result.session.refreshToken) {\n // set new refresh token\n cookieManager.setRefreshToken(\n res,\n result.session.refreshToken,\n appOrigin,\n );\n }\n\n // When using the redirect flow we rely on refresh token we just\n // acquired to get a new session once we're back in the app.\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return;\n }\n\n // post message back to popup if successful\n sendWebMessageResponse(res, appOrigin, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n sendWebMessageResponse(res, appOrigin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n },\n\n async logout(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (authenticator.logout) {\n const refreshToken = cookieManager.getRefreshToken(req);\n await authenticator.logout({ req, refreshToken }, authenticatorCtx);\n }\n\n // remove refresh token cookie if it is set\n cookieManager.removeRefreshToken(res, req.get('origin'));\n\n res.status(200).end();\n },\n\n async refresh(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n try {\n const refreshToken = cookieManager.getRefreshToken(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n let scope = req.query.scope?.toString() ?? '';\n if (authenticator.shouldPersistScopes) {\n scope = cookieManager.getGrantedScopes(req);\n }\n\n const result = await authenticator.refresh(\n { req, scope, refreshToken },\n authenticatorCtx,\n );\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const newRefreshToken = result.session.refreshToken;\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n cookieManager.setRefreshToken(\n res,\n newRefreshToken,\n req.get('origin'),\n );\n }\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: authenticator.shouldPersistScopes\n ? scope\n : result.session.scope,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n };\n\n if (signInResolver) {\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n response.backstageIdentity =\n prepareBackstageIdentityResponse(identity);\n }\n\n res.status(200).json(response);\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request } from 'express';\nimport { decodeJwt } from 'jose';\nimport { Strategy } from 'passport';\nimport { PassportProfile } from './types';\nimport { ProfileInfo } from '../types';\n\n// Re-declared here to avoid direct dependency on passport-oauth2\n/** @internal */\ninterface InternalOAuthError extends Error {\n oauthError?: {\n data?: string;\n };\n}\n\n/** @public */\nexport class PassportHelpers {\n private constructor() {}\n\n static transformProfile = (\n profile: PassportProfile,\n idToken?: string,\n ): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n };\n\n static async executeRedirectStrategy(\n req: Request,\n providerStrategy: Strategy,\n options: Record<string, string>,\n ): Promise<{\n /**\n * URL to redirect to\n */\n url: string;\n /**\n * Status code to use for the redirect\n */\n status?: number;\n }> {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n }\n\n static async executeFrameHandlerStrategy<TResult, TPrivateInfo = never>(\n req: Request,\n providerStrategy: Strategy,\n options?: Record<string, string>,\n ): Promise<{ result: TResult; privateInfo: TPrivateInfo }> {\n return new Promise((resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n });\n }\n\n static async executeRefreshTokenStrategy(\n providerStrategy: Strategy,\n refreshToken: string,\n scope: string,\n ): Promise<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n }> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(\n new Error(`Failed to refresh access token ${err.toString()}`),\n );\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n }\n\n static async executeFetchUserProfileStrategy(\n providerStrategy: Strategy,\n accessToken: string,\n ): Promise<PassportProfile> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as {\n userProfile(accessToken: string, callback: Function): void;\n };\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Strategy } from 'passport';\nimport {\n PassportDoneCallback,\n PassportHelpers,\n PassportProfile,\n} from '../passport';\nimport { ProfileTransform } from '../types';\nimport {\n OAuthAuthenticatorAuthenticateInput,\n OAuthAuthenticatorRefreshInput,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorStartInput,\n} from './types';\n\n/** @public */\nexport type PassportOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n id_token?: string;\n scope: string;\n token_type?: string;\n expires_in: number;\n };\n accessToken: string;\n};\n\n/** @public */\nexport type PassportOAuthPrivateInfo = {\n refreshToken?: string;\n};\n\n/** @public */\nexport type PassportOAuthDoneCallback = PassportDoneCallback<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n>;\n\n/** @public */\nexport class PassportOAuthAuthenticatorHelper {\n static defaultProfileTransform: ProfileTransform<\n OAuthAuthenticatorResult<PassportProfile>\n > = async input => ({\n profile: PassportHelpers.transformProfile(\n input.fullProfile ?? {},\n input.session.idToken,\n ),\n });\n\n static from(strategy: Strategy) {\n return new PassportOAuthAuthenticatorHelper(strategy);\n }\n\n readonly #strategy: Strategy;\n\n private constructor(strategy: Strategy) {\n this.#strategy = strategy;\n }\n\n async start(\n input: OAuthAuthenticatorStartInput,\n options: Record<string, string>,\n ): Promise<{ url: string; status?: number }> {\n return PassportHelpers.executeRedirectStrategy(input.req, this.#strategy, {\n scope: input.scope,\n state: input.state,\n ...options,\n });\n }\n\n async authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ): Promise<OAuthAuthenticatorResult<PassportProfile>> {\n const { result, privateInfo } =\n await PassportHelpers.executeFrameHandlerStrategy<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n >(input.req, this.#strategy);\n\n return {\n fullProfile: result.fullProfile as PassportProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: privateInfo.refreshToken,\n },\n };\n }\n\n async refresh(\n input: OAuthAuthenticatorRefreshInput,\n ): Promise<OAuthAuthenticatorResult<PassportProfile>> {\n const result = await PassportHelpers.executeRefreshTokenStrategy(\n this.#strategy,\n input.refreshToken,\n input.scope,\n );\n const fullProfile = await this.fetchProfile(result.accessToken);\n return {\n fullProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: result.refreshToken,\n },\n };\n }\n\n async fetchProfile(accessToken: string): Promise<PassportProfile> {\n const profile = await PassportHelpers.executeFetchUserProfileStrategy(\n this.#strategy,\n accessToken,\n );\n return profile;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { AuthProviderRouteHandlers } from '../types';\nimport { decodeOAuthState } from './state';\n\n/** @public */\nexport class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {\n static mapConfig(\n config: Config,\n factoryFunc: (envConfig: Config) => AuthProviderRouteHandlers,\n ) {\n const envs = config.keys();\n const handlers = new Map<string, AuthProviderRouteHandlers>();\n\n for (const env of envs) {\n const envConfig = config.getConfig(env);\n const handler = factoryFunc(envConfig);\n handlers.set(env, handler);\n }\n\n return new OAuthEnvironmentHandler(handlers);\n }\n\n constructor(\n private readonly handlers: Map<string, AuthProviderRouteHandlers>,\n ) {}\n\n async start(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.start(req, res);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.frameHandler(req, res);\n }\n\n async refresh(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.refresh?.(req, res);\n }\n\n async logout(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.logout?.(req, res);\n }\n\n private getEnvFromRequest(req: express.Request): string | undefined {\n const reqEnv = req.query.env?.toString();\n if (reqEnv) {\n return reqEnv;\n }\n const stateParams = req.query.state?.toString();\n if (!stateParams) {\n return undefined;\n }\n const { env } = decodeOAuthState(stateParams);\n return env;\n }\n\n private getProviderForEnv(req: express.Request): AuthProviderRouteHandlers {\n const env: string | undefined = this.getEnvFromRequest(req);\n\n if (!env) {\n throw new InputError(`Must specify 'env' query to select environment`);\n }\n\n const handler = this.handlers.get(env);\n if (!handler) {\n throw new NotFoundError(\n `No configuration available for the '${env}' environment of this provider.`,\n );\n }\n\n return handler;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ZodSchema, ZodTypeDef } from 'zod';\nimport { SignInResolver } from '../types';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { JsonObject } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\n\n/** @public */\nexport interface SignInResolverFactory<TAuthResult, TOptions> {\n (\n ...options: undefined extends TOptions\n ? [options?: TOptions]\n : [options: TOptions]\n ): SignInResolver<TAuthResult>;\n optionsJsonSchema?: JsonObject;\n}\n\n/** @public */\nexport interface SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n> {\n optionsSchema?: ZodSchema<TOptionsOutput, ZodTypeDef, TOptionsInput>;\n create(options: TOptionsOutput): SignInResolver<TAuthResult>;\n}\n\n/** @public */\nexport function createSignInResolverFactory<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n>(\n options: SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput\n >,\n): SignInResolverFactory<TAuthResult, TOptionsInput> {\n const { optionsSchema } = options;\n if (!optionsSchema) {\n return (resolverOptions?: TOptionsInput) => {\n if (resolverOptions) {\n throw new InputError('sign-in resolver does not accept options');\n }\n return options.create(undefined as TOptionsOutput);\n };\n }\n const factory = (\n ...[resolverOptions]: undefined extends TOptionsInput\n ? [options?: TOptionsInput]\n : [options: TOptionsInput]\n ) => {\n const parsedOptions = optionsSchema.parse(resolverOptions);\n return options.create(parsedOptions);\n };\n\n factory.optionsJsonSchema = zodToJsonSchema(optionsSchema) as JsonObject;\n return factory;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { SignInResolver } from '../types';\nimport { SignInResolverFactory } from './createSignInResolverFactory';\n\n/** @public */\nexport interface ReadDeclarativeSignInResolverOptions<TAuthResult> {\n config: Config;\n signInResolverFactories: {\n [name in string]: SignInResolverFactory<TAuthResult, unknown>;\n };\n}\n\n/** @public */\nexport function readDeclarativeSignInResolver<TAuthResult>(\n options: ReadDeclarativeSignInResolverOptions<TAuthResult>,\n): SignInResolver<TAuthResult> | undefined {\n const resolvers =\n options.config\n .getOptionalConfigArray('signIn.resolvers')\n ?.map(resolverConfig => {\n const resolverName = resolverConfig.getString('resolver');\n if (!Object.hasOwn(options.signInResolverFactories, resolverName)) {\n throw new Error(\n `Sign-in resolver '${resolverName}' is not available`,\n );\n }\n const resolver = options.signInResolverFactories[resolverName];\n const { resolver: _ignored, ...resolverOptions } =\n resolverConfig.get<JsonObject>();\n\n return resolver(\n Object.keys(resolverOptions).length > 0 ? resolverOptions : undefined,\n );\n }) ?? [];\n\n if (resolvers.length === 0) {\n return undefined;\n }\n\n return async (profile, context) => {\n for (const resolver of resolvers) {\n try {\n return await resolver(profile, context);\n } catch (error) {\n if (error?.name === 'NotFoundError') {\n continue;\n }\n throw error;\n }\n }\n\n throw new Error('Failed to sign-in, unable to resolve user identity');\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createSignInResolverFactory } from './createSignInResolverFactory';\n\n/**\n * A collection of common sign-in resolvers that work with any auth provider.\n *\n * @public\n */\nexport namespace commonSignInResolvers {\n /**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\n export const emailMatchingUserEntityProfileEmail =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n };\n },\n });\n\n /**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\n export const emailLocalPartMatchingUserEntityName =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n };\n },\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readDeclarativeSignInResolver } from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler';\nimport { createOAuthRouteHandlers } from './createOAuthRouteHandlers';\nimport { OAuthStateTransform } from './state';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { SignInResolverFactory } from '../sign-in/createSignInResolverFactory';\n\n/** @public */\nexport function createOAuthProviderFactory<TProfile>(options: {\n authenticator: OAuthAuthenticator<unknown, TProfile>;\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;\n signInResolverFactories?: {\n [name in string]: SignInResolverFactory<\n OAuthAuthenticatorResult<TProfile>,\n unknown\n >;\n };\n}): AuthProviderFactory {\n return ctx => {\n return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: envConfig,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n return createOAuthRouteHandlers<TProfile>({\n authenticator: options.authenticator,\n appUrl: ctx.appUrl,\n baseUrl: ctx.baseUrl,\n config: envConfig,\n isOriginAllowed: ctx.isOriginAllowed,\n cookieConfigurer: ctx.cookieConfigurer,\n providerId: ctx.providerId,\n resolverContext: ctx.resolverContext,\n stateTransform: options.stateTransform,\n profileTransform: options.profileTransform,\n signInResolver,\n });\n });\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface OAuthSession {\n accessToken: string;\n tokenType: string;\n idToken?: string;\n scope: string;\n expiresInSeconds?: number;\n refreshToken?: string;\n refreshTokenExpiresInSeconds?: number;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorStartInput {\n scope: string;\n state: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorAuthenticateInput {\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorRefreshInput {\n scope: string;\n refreshToken: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorLogoutInput {\n accessToken?: string;\n refreshToken?: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorResult<TProfile> {\n fullProfile: TProfile;\n session: OAuthSession;\n}\n\n/** @public */\nexport interface OAuthAuthenticator<TContext, TProfile> {\n defaultProfileTransform: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n shouldPersistScopes?: boolean;\n initialize(ctx: { callbackUrl: string; config: Config }): TContext;\n start(\n input: OAuthAuthenticatorStartInput,\n ctx: TContext,\n ): Promise<{ url: string; status?: number }>;\n authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ctx: TContext,\n ): Promise<OAuthAuthenticatorResult<TProfile>>;\n refresh(\n input: OAuthAuthenticatorRefreshInput,\n ctx: TContext,\n ): Promise<OAuthAuthenticatorResult<TProfile>>;\n logout?(input: OAuthAuthenticatorLogoutInput, ctx: TContext): Promise<void>;\n}\n\n/** @public */\nexport function createOAuthAuthenticator<TContext, TProfile>(\n authenticator: OAuthAuthenticator<TContext, TProfile>,\n): OAuthAuthenticator<TContext, TProfile> {\n return authenticator;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface ProxyAuthenticator<\n TContext,\n TResult,\n TProviderInfo = undefined,\n> {\n defaultProfileTransform: ProfileTransform<TResult>;\n initialize(ctx: { config: Config }): TContext;\n authenticate(\n options: { req: Request },\n ctx: TContext,\n ): Promise<{ result: TResult; providerInfo?: TProviderInfo }>;\n}\n\n/** @public */\nexport function createProxyAuthenticator<TContext, TResult, TProviderInfo>(\n authenticator: ProxyAuthenticator<TContext, TResult, TProviderInfo>,\n): ProxyAuthenticator<TContext, TResult, TProviderInfo> {\n return authenticator;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { Config } from '@backstage/config';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { ProxyAuthenticator } from './types';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { NotImplementedError } from '@backstage/errors';\n\n/** @public */\nexport interface ProxyAuthRouteHandlersOptions<TResult> {\n authenticator: ProxyAuthenticator<any, TResult, unknown>;\n config: Config;\n resolverContext: AuthResolverContext;\n signInResolver: SignInResolver<TResult>;\n profileTransform?: ProfileTransform<TResult>;\n}\n\n/** @public */\nexport function createProxyAuthRouteHandlers<TResult>(\n options: ProxyAuthRouteHandlersOptions<TResult>,\n): AuthProviderRouteHandlers {\n const { authenticator, config, resolverContext, signInResolver } = options;\n\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config });\n\n return {\n async start(): Promise<void> {\n throw new NotImplementedError('Not implemented');\n },\n\n async frameHandler(): Promise<void> {\n throw new NotImplementedError('Not implemented');\n },\n\n async refresh(this: never, req: Request, res: Response): Promise<void> {\n const { result, providerInfo } = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n\n const response: ClientAuthResponse<unknown> = {\n profile,\n providerInfo,\n backstageIdentity: prepareBackstageIdentityResponse(identity),\n };\n\n res.status(200).json(response);\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readDeclarativeSignInResolver,\n SignInResolverFactory,\n} from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { createProxyAuthRouteHandlers } from './createProxyRouteHandlers';\nimport { ProxyAuthenticator } from './types';\n\n/** @public */\nexport function createProxyAuthProviderFactory<TResult>(options: {\n authenticator: ProxyAuthenticator<unknown, TResult, unknown>;\n profileTransform?: ProfileTransform<TResult>;\n signInResolver?: SignInResolver<TResult>;\n signInResolverFactories?: Record<\n string,\n SignInResolverFactory<TResult, unknown>\n >;\n}): AuthProviderFactory {\n return ctx => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: ctx.config,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n if (!signInResolver) {\n throw new Error(\n `No sign-in resolver configured for proxy auth provider '${ctx.providerId}'`,\n );\n }\n\n return createProxyAuthRouteHandlers<TResult>({\n signInResolver,\n config: ctx.config,\n authenticator: options.authenticator,\n resolverContext: ctx.resolverContext,\n profileTransform: options.profileTransform,\n });\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { Request, Response } from 'express';\n\n/**\n * A representation of a successful Backstage sign-in.\n *\n * Compared to the {@link BackstageIdentityResponse} this type omits\n * the decoded identity information embedded in the token.\n *\n * @public\n */\nexport interface BackstageSignInResult {\n /**\n * The token used to authenticate the user within Backstage.\n */\n token: string;\n}\n\n/**\n * Response object containing the {@link BackstageUserIdentity} and the token\n * from the authentication provider.\n *\n * @public\n */\nexport interface BackstageIdentityResponse extends BackstageSignInResult {\n /**\n * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire.\n */\n expiresInSeconds?: number;\n\n /**\n * A plaintext description of the identity that is encapsulated within the token.\n */\n identity: BackstageUserIdentity;\n}\n\n/**\n * User identity information within Backstage.\n *\n * @public\n */\nexport type BackstageUserIdentity = {\n /**\n * The type of identity that this structure represents. In the frontend app\n * this will currently always be 'user'.\n */\n type: 'user';\n\n /**\n * The entityRef of the user in the catalog.\n * For example User:default/sandra\n */\n userEntityRef: string;\n\n /**\n * The user and group entities that the user claims ownership through\n */\n ownershipEntityRefs: string[];\n};\n\n/**\n * A query for a single user in the catalog.\n *\n * If `entityRef` is used, the default kind is `'User'`.\n *\n * If `annotations` are used, all annotations must be present and\n * match the provided value exactly. Only entities of kind `'User'` will be considered.\n *\n * If `filter` are used, only entities of kind `'User'` will be considered unless it is explicitly specified differently in the filter.\n *\n * Regardless of the query method, the query must match exactly one entity\n * in the catalog, or an error will be thrown.\n *\n * @public\n */\nexport type AuthResolverCatalogUserQuery =\n | {\n entityRef:\n | string\n | {\n kind?: string;\n namespace?: string;\n name: string;\n };\n }\n | {\n annotations: Record<string, string>;\n }\n | {\n filter: EntityFilterQuery;\n };\n\n/**\n * Parameters used to issue new Backstage Tokens\n *\n * @public\n */\nexport type TokenParams = {\n /**\n * The claims that will be embedded within the token. At a minimum, this should include\n * the subject claim, `sub`. It is common to also list entity ownership relations in the\n * `ent` list. Additional claims may also be added at the developer's discretion except\n * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`,\n * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future\n * without listing the change as a \"breaking change\".\n */\n claims: {\n /** The token subject, i.e. User ID */\n sub: string;\n /** A list of entity references that the user claims ownership through */\n ent?: string[];\n } & Record<string, JsonValue>;\n};\n\n/**\n * The context that is used for auth processing.\n *\n * @public\n */\nexport type AuthResolverContext = {\n /**\n * Issues a Backstage token using the provided parameters.\n */\n issueToken(params: TokenParams): Promise<{ token: string }>;\n\n /**\n * Finds a single user in the catalog using the provided query.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n findCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<{ entity: Entity }>;\n\n /**\n * Finds a single user in the catalog using the provided query, and then\n * issues an identity for that user using default ownership resolution.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n signInWithCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<BackstageSignInResult>;\n};\n\n/**\n * Resolver interface for resolving the ownership entity references for entity\n *\n * @public\n */\nexport interface AuthOwnershipResolver {\n resolveOwnershipEntityRefs(\n entity: Entity,\n ): Promise<{ ownershipEntityRefs: string[] }>;\n}\n\n/**\n * Any Auth provider needs to implement this interface which handles the routes in the\n * auth backend. Any auth API requests from the frontend reaches these methods.\n *\n * The routes in the auth backend API are tied to these methods like below\n *\n * `/auth/[provider]/start -> start`\n * `/auth/[provider]/handler/frame -> frameHandler`\n * `/auth/[provider]/refresh -> refresh`\n * `/auth/[provider]/logout -> logout`\n *\n * @public\n */\nexport interface AuthProviderRouteHandlers {\n /**\n * Handles the start route of the API. This initiates a sign in request with an auth provider.\n *\n * Request\n * - scopes for the auth request (Optional)\n * Response\n * - redirect to the auth provider for the user to sign in or consent.\n * - sets a nonce cookie and also pass the nonce as 'state' query parameter in the redirect request\n */\n start(req: Request, res: Response): Promise<void>;\n\n /**\n * Once the user signs in or consents in the OAuth screen, the auth provider redirects to the\n * callbackURL which is handled by this method.\n *\n * Request\n * - to contain a nonce cookie and a 'state' query parameter\n * Response\n * - postMessage to the window with a payload that contains accessToken, expiryInSeconds?, idToken? and scope.\n * - sets a refresh token cookie if the auth provider supports refresh tokens\n */\n frameHandler(req: Request, res: Response): Promise<void>;\n\n /**\n * (Optional) If the auth provider supports refresh tokens then this method handles\n * requests to get a new access token.\n *\n * Other types of providers may also use this method to implement its own logic to create new sessions\n * upon request. For example, this can be used to create a new session for a provider that handles requests\n * from an authenticating proxy.\n *\n * Request\n * - to contain a refresh token cookie and scope (Optional) query parameter.\n * Response\n * - payload with accessToken, expiryInSeconds?, idToken?, scope and user profile information.\n */\n refresh?(req: Request, res: Response): Promise<void>;\n\n /**\n * (Optional) Handles sign out requests\n *\n * Response\n * - removes the refresh token cookie\n */\n logout?(req: Request, res: Response): Promise<void>;\n}\n\n/**\n * @public\n * @deprecated Use top-level properties passed to `AuthProviderFactory` instead\n */\nexport type AuthProviderConfig = {\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n};\n\n/** @public */\nexport type AuthProviderFactory = (options: {\n providerId: string;\n /** @deprecated Use top-level properties instead */\n globalConfig: AuthProviderConfig;\n config: Config;\n logger: LoggerService;\n resolverContext: AuthResolverContext;\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n}) => AuthProviderRouteHandlers;\n\n/** @public */\nexport type ClientAuthResponse<TProviderInfo> = {\n providerInfo: TProviderInfo;\n profile: ProfileInfo;\n backstageIdentity?: BackstageIdentityResponse;\n};\n\n/**\n * Type of sign in information context. Includes the profile information and\n * authentication result which contains auth related information.\n *\n * @public\n */\nexport type SignInInfo<TAuthResult> = {\n /**\n * The simple profile passed down for use in the frontend.\n */\n profile: ProfileInfo;\n\n /**\n * The authentication result that was received from the authentication\n * provider.\n */\n result: TAuthResult;\n};\n\n/**\n * Describes the function which handles the result of a successful\n * authentication. Must return a valid {@link @backstage/plugin-auth-node#BackstageSignInResult}.\n *\n * @public\n */\nexport type SignInResolver<TAuthResult> = (\n info: SignInInfo<TAuthResult>,\n context: AuthResolverContext,\n) => Promise<BackstageSignInResult>;\n\n/**\n * Describes the function that transforms the result of a successful\n * authentication into a {@link ProfileInfo} object.\n *\n * This function may optionally throw an error in order to reject authentication.\n *\n * @public\n */\nexport type ProfileTransform<TResult> = (\n result: TResult,\n context: AuthResolverContext,\n) => Promise<{ profile: ProfileInfo }>;\n\n/**\n * Used to display login information to user, i.e. sidebar popup.\n *\n * It is also temporarily used as the profile of the signed-in user's Backstage\n * identity, but we want to replace that with data from identity and/org catalog\n * service\n *\n * @public\n */\nexport type ProfileInfo = {\n /**\n * Email ID of the signed in user.\n */\n email?: string;\n /**\n * Display name that can be presented to the signed in user.\n */\n displayName?: string;\n /**\n * URL to an image that can be used as the display image or avatar of the\n * signed in user.\n */\n picture?: string;\n};\n\n/**\n * The callback used to resolve the cookie configuration for auth providers that use cookies.\n * @public\n */\nexport type CookieConfigurer = (ctx: {\n /** ID of the auth provider that this configuration applies to */\n providerId: string;\n /** The externally reachable base URL of the auth-backend plugin */\n baseUrl: string;\n /** The configured callback URL of the auth provider */\n callbackUrl: string;\n /** The origin URL of the app */\n appOrigin: string;\n}) => {\n domain: string;\n path: string;\n secure: boolean;\n sameSite?: 'none' | 'lax' | 'strict';\n};\n\n/**\n * Core properties of various token types.\n *\n * @public\n */\nexport const tokenTypes = Object.freeze({\n user: Object.freeze({\n typParam: 'vnd.backstage.user',\n audClaim: 'backstage',\n }),\n limitedUser: Object.freeze({\n typParam: 'vnd.backstage.limited-user',\n }),\n plugin: Object.freeze({\n typParam: 'vnd.backstage.plugin',\n }),\n});\n"],"names":["createExtensionPoint","serializeError","crypto","InputError","AuthenticationError","jwtVerify","decodeJwt","decodeProtectedHeader","createRemoteJWKSet","pickBy","NotAllowedError","URL","isError","NotFoundError","zodToJsonSchema","commonSignInResolvers","NotImplementedError"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/extensions/AuthProvidersExtensionPoint.ts","../src/extensions/AuthOwnershipResolutionExtensionPoint.ts","../src/flow/sendWebMessageResponse.ts","../src/identity/prepareBackstageIdentityResponse.ts","../src/identity/getBearerTokenFromAuthorizationHeader.ts","../src/identity/DefaultIdentityClient.ts","../src/identity/IdentityClient.ts","../src/oauth/state.ts","../src/oauth/OAuthCookieManager.ts","../src/oauth/CookieScopeManager.ts","../src/oauth/createOAuthRouteHandlers.ts","../src/passport/PassportHelpers.ts","../src/oauth/PassportOAuthAuthenticatorHelper.ts","../src/oauth/OAuthEnvironmentHandler.ts","../src/sign-in/createSignInResolverFactory.ts","../src/sign-in/readDeclarativeSignInResolver.ts","../src/sign-in/commonSignInResolvers.ts","../src/oauth/createOAuthProviderFactory.ts","../src/oauth/types.ts","../src/proxy/types.ts","../src/proxy/createProxyRouteHandlers.ts","../src/proxy/createProxyAuthProviderFactory.ts","../src/types.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\nimport { AuthProviderFactory } from '../types';\n\n/** @public */\nexport interface AuthProviderRegistrationOptions {\n providerId: string;\n factory: AuthProviderFactory;\n}\n\n/** @public */\nexport interface AuthProvidersExtensionPoint {\n registerProvider(options: AuthProviderRegistrationOptions): void;\n}\n\n/** @public */\nexport const authProvidersExtensionPoint =\n createExtensionPoint<AuthProvidersExtensionPoint>({\n id: 'auth.providers',\n });\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { AuthOwnershipResolver } from '../types';\nimport { createExtensionPoint } from '@backstage/backend-plugin-api';\n\n/** @public */\nexport interface AuthOwnershipResolutionExtensionPoint {\n setAuthOwnershipResolver(ownershipResolver: AuthOwnershipResolver): void;\n}\n\n/** @public */\nexport const authOwnershipResolutionExtensionPoint =\n createExtensionPoint<AuthOwnershipResolutionExtensionPoint>({\n id: 'auth.ownershipResolution',\n });\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Response } from 'express';\nimport crypto from 'crypto';\nimport { ClientAuthResponse } from '../types';\nimport { serializeError } from '@backstage/errors';\n\n/**\n * Payload sent as a post message after the auth request is complete.\n * If successful then has a valid payload with Auth information else contains an error.\n *\n * @public\n */\nexport type WebMessageResponse =\n | {\n type: 'authorization_response';\n response: ClientAuthResponse<unknown>;\n }\n | {\n type: 'authorization_response';\n error: Error;\n };\n\n/** @internal */\nexport function safelyEncodeURIComponent(value: string): string {\n // Note the g at the end of the regex; all occurrences of single quotes must\n // be replaced, which encodeURIComponent does not do itself by default\n return encodeURIComponent(value).replace(/'/g, '%27');\n}\n\n/** @public */\nexport function sendWebMessageResponse(\n res: Response,\n appOrigin: string,\n response: WebMessageResponse,\n): void {\n const jsonData = JSON.stringify(response, (_, value) => {\n if (value instanceof Error) {\n return serializeError(value);\n }\n return value;\n });\n const base64Data = safelyEncodeURIComponent(jsonData);\n const base64Origin = safelyEncodeURIComponent(appOrigin);\n\n // NOTE: It is absolutely imperative that we use the safe encoder above, to\n // be sure that the js code below does not allow the injection of malicious\n // data.\n\n // TODO: Make target app origin configurable globally\n\n //\n // postMessage fails silently if the targetOrigin is disallowed.\n // So 2 postMessages are sent from the popup to the parent window.\n // First, the origin being used to post the actual authorization response is\n // shared with the parent window with a postMessage with targetOrigin '*'.\n // Second, the actual authorization response is sent with the app origin\n // as the targetOrigin.\n // If the first message was received but the actual auth response was\n // never received, the event listener can conclude that targetOrigin\n // was disallowed, indicating potential misconfiguration.\n //\n const script = `\n var authResponse = decodeURIComponent('${base64Data}');\n var origin = decodeURIComponent('${base64Origin}');\n var originInfo = {'type': 'config_info', 'targetOrigin': origin};\n (window.opener || window.parent).postMessage(originInfo, '*');\n (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);\n setTimeout(() => {\n window.close();\n }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)\n `;\n const hash = crypto.createHash('sha256').update(script).digest('base64');\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('X-Frame-Options', 'sameorigin');\n res.setHeader('Content-Security-Policy', `script-src 'sha256-${hash}'`);\n res.end(`<html><body><script>${script}</script></body></html>`);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport {\n BackstageIdentityResponse,\n BackstageSignInResult,\n} from '@backstage/plugin-auth-node';\n\nfunction parseJwtPayload(token: string) {\n const [_header, payload, _signature] = token.split('.');\n return JSON.parse(Buffer.from(payload, 'base64').toString());\n}\n\n/**\n * Parses a Backstage-issued token and decorates the\n * {@link @backstage/plugin-auth-node#BackstageIdentityResponse} with identity information sourced from the\n * token.\n *\n * @public\n */\nexport function prepareBackstageIdentityResponse(\n result: BackstageSignInResult,\n): BackstageIdentityResponse {\n if (!result.token) {\n throw new InputError(`Identity response must return a token`);\n }\n\n const { sub, ent = [], exp: expStr } = parseJwtPayload(result.token);\n if (!sub) {\n throw new InputError(\n `Identity response must return a token with subject claim`,\n );\n }\n\n const expAt = Number(expStr);\n\n // Default to 1 hour if no expiration is set, in particular to make testing simpler\n const exp = expAt ? Math.round(expAt - Date.now() / 1000) : undefined;\n if (exp && exp < 0) {\n throw new InputError(`Identity response must not return an expired token`);\n }\n\n return {\n ...result,\n expiresInSeconds: exp,\n identity: {\n type: 'user',\n userEntityRef: sub,\n ownershipEntityRefs: ent,\n },\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Parses the given authorization header and returns the bearer token, or\n * undefined if no bearer token is given.\n *\n * @remarks\n *\n * This function is explicitly built to tolerate bad inputs safely, so you may\n * call it directly with e.g. the output of `req.header('authorization')`\n * without first checking that it exists.\n *\n * @deprecated Use the `credentials` method of `HttpAuthService` from `@backstage/backend-plugin-api` instead\n * @public\n */\nexport function getBearerTokenFromAuthorizationHeader(\n authorizationHeader: unknown,\n): string | undefined {\n if (typeof authorizationHeader !== 'string') {\n return undefined;\n }\n const matches = authorizationHeader.match(/^Bearer[ ]+(\\S+)$/i);\n return matches?.[1];\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n jwtVerify,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\nimport { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';\nimport { IdentityApi, IdentityApiGetIdentityRequest } from './IdentityApi';\nimport { BackstageIdentityResponse } from '../types';\n\nconst CLOCK_MARGIN_S = 10;\n\n/**\n * An identity client options object which allows extra configurations\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport type IdentityClientOptions = {\n discovery: PluginEndpointDiscovery;\n issuer?: string;\n\n /** JWS \"alg\" (Algorithm) Header Parameter values. Defaults to an array containing just ES256.\n * More info on supported algorithms: https://github.com/panva/jose */\n algorithms?: string[];\n};\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @experimental This is not a stable API yet\n * @public\n */\nexport class DefaultIdentityClient implements IdentityApi {\n private readonly discovery: PluginEndpointDiscovery;\n private readonly issuer?: string;\n private readonly algorithms?: string[];\n private keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;\n private keyStoreUpdated: number = 0;\n\n /**\n * Create a new {@link DefaultIdentityClient} instance.\n */\n static create(options: IdentityClientOptions): DefaultIdentityClient {\n return new DefaultIdentityClient(options);\n }\n\n private constructor(options: IdentityClientOptions) {\n this.discovery = options.discovery;\n this.issuer = options.issuer;\n this.algorithms = options.hasOwnProperty('algorithms')\n ? options.algorithms\n : ['ES256'];\n }\n\n async getIdentity(options: IdentityApiGetIdentityRequest) {\n const {\n request: { headers },\n } = options;\n if (!headers.authorization) {\n return undefined;\n }\n try {\n return await this.authenticate(\n getBearerTokenFromAuthorizationHeader(headers.authorization),\n );\n } catch (e) {\n throw new AuthenticationError(e.message);\n }\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use getIdentity instead of authenticate to retrieve the user\n * identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise<BackstageIdentityResponse> {\n // Extract token from header\n if (!token) {\n throw new AuthenticationError('No token specified');\n }\n\n // Verify token claims and signature\n // Note: Claims must match those set by TokenFactory when issuing tokens\n // Note: verify throws if verification fails\n // Check if the keystore needs to be updated\n await this.refreshKeyStore(token);\n if (!this.keyStore) {\n throw new AuthenticationError('No keystore exists');\n }\n const decoded = await jwtVerify(token, this.keyStore, {\n algorithms: this.algorithms,\n audience: 'backstage',\n issuer: this.issuer,\n });\n // Verified, return the matching user as BackstageIdentity\n // TODO: Settle internal user format/properties\n if (!decoded.payload.sub) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n const user: BackstageIdentityResponse = {\n token,\n identity: {\n type: 'user',\n userEntityRef: decoded.payload.sub,\n ownershipEntityRefs: decoded.payload.ent\n ? (decoded.payload.ent as string[])\n : [],\n },\n };\n return user;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n private async refreshKeyStore(rawJwtToken: string): Promise<void> {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const url = await this.discovery.getBaseUrl('auth');\n const endpoint = new URL(`${url}/.well-known/jwks.json`);\n this.keyStore = createRemoteJWKSet(endpoint);\n this.keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultIdentityClient,\n IdentityClientOptions,\n} from './DefaultIdentityClient';\nimport { BackstageIdentityResponse } from '../types';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @public\n * @experimental This is not a stable API yet\n * @deprecated Please migrate to the DefaultIdentityClient.\n */\nexport class IdentityClient {\n private readonly defaultIdentityClient: DefaultIdentityClient;\n static create(options: IdentityClientOptions): IdentityClient {\n return new IdentityClient(DefaultIdentityClient.create(options));\n }\n\n private constructor(defaultIdentityClient: DefaultIdentityClient) {\n this.defaultIdentityClient = defaultIdentityClient;\n }\n\n /**\n * Verifies the given backstage identity token\n * Returns a BackstageIdentity (user) matching the token.\n * The method throws an error if verification fails.\n *\n * @deprecated You should start to use IdentityApi#getIdentity instead of authenticate\n * to retrieve the user identity.\n */\n async authenticate(\n token: string | undefined,\n ): Promise<BackstageIdentityResponse> {\n return await this.defaultIdentityClient.authenticate(token);\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport pickBy from 'lodash/pickBy';\nimport { Request } from 'express';\nimport { NotAllowedError } from '@backstage/errors';\n\n/**\n * A type for the serialized value in the `state` parameter of the OAuth authorization flow\n * @public\n */\nexport type OAuthState = {\n nonce: string;\n env: string;\n origin?: string;\n scope?: string;\n redirectUrl?: string;\n flow?: string;\n audience?: string;\n};\n\n/** @public */\nexport type OAuthStateTransform = (\n state: OAuthState,\n context: { req: Request },\n) => Promise<{ state: OAuthState }>;\n\n/** @public */\nexport function encodeOAuthState(state: OAuthState): string {\n const stateString = new URLSearchParams(\n pickBy<string>(state, value => value !== undefined),\n ).toString();\n\n return Buffer.from(stateString, 'utf-8').toString('hex');\n}\n\n/** @public */\nexport function decodeOAuthState(encodedState: string): OAuthState {\n const state = Object.fromEntries(\n new URLSearchParams(Buffer.from(encodedState, 'hex').toString('utf-8')),\n );\n if (!state.env || state.env?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing env');\n }\n if (!state.nonce || state.nonce?.length === 0) {\n throw new NotAllowedError('OAuth state is invalid, missing nonce');\n }\n\n return state as OAuthState;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { CookieConfigurer } from '../types';\n\nconst THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000;\nconst TEN_MINUTES_MS = 600 * 1000;\n\nconst defaultCookieConfigurer: CookieConfigurer = ({\n callbackUrl,\n providerId,\n appOrigin,\n}) => {\n const { hostname: domain, pathname, protocol } = new URL(callbackUrl);\n const secure = protocol === 'https:';\n\n // For situations where the auth-backend is running on a\n // different domain than the app, we set the SameSite attribute\n // to 'none' to allow third-party access to the cookie, but\n // only if it's in a secure context (https).\n let sameSite: ReturnType<CookieConfigurer>['sameSite'] = 'lax';\n if (new URL(appOrigin).hostname !== domain && secure) {\n sameSite = 'none';\n }\n\n // If the provider supports callbackUrls, the pathname will\n // contain the complete path to the frame handler so we need\n // to slice off the trailing part of the path.\n const path = pathname.endsWith(`${providerId}/handler/frame`)\n ? pathname.slice(0, -'/handler/frame'.length)\n : `${pathname}/${providerId}`;\n\n return { domain, path, secure, sameSite };\n};\n\n/** @internal */\nexport class OAuthCookieManager {\n private readonly cookieConfigurer: CookieConfigurer;\n private readonly nonceCookie: string;\n private readonly refreshTokenCookie: string;\n private readonly grantedScopeCookie: string;\n\n constructor(\n private readonly options: {\n providerId: string;\n defaultAppOrigin: string;\n baseUrl: string;\n callbackUrl: string;\n cookieConfigurer?: CookieConfigurer;\n },\n ) {\n this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer;\n\n this.nonceCookie = `${options.providerId}-nonce`;\n this.refreshTokenCookie = `${options.providerId}-refresh-token`;\n this.grantedScopeCookie = `${options.providerId}-granted-scope`;\n }\n\n private getConfig(origin?: string, pathSuffix: string = '') {\n const cookieConfig = this.cookieConfigurer({\n providerId: this.options.providerId,\n baseUrl: this.options.baseUrl,\n callbackUrl: this.options.callbackUrl,\n appOrigin: origin ?? this.options.defaultAppOrigin,\n });\n return {\n httpOnly: true,\n sameSite: 'lax' as const,\n ...cookieConfig,\n path: cookieConfig.path + pathSuffix,\n };\n }\n\n setNonce(res: Response, nonce: string, origin?: string) {\n res.cookie(this.nonceCookie, nonce, {\n maxAge: TEN_MINUTES_MS,\n ...this.getConfig(origin, '/handler'),\n });\n }\n\n setRefreshToken(res: Response, refreshToken: string, origin?: string) {\n res.cookie(this.refreshTokenCookie, refreshToken, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n removeRefreshToken(res: Response, origin?: string) {\n res.cookie(this.refreshTokenCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n removeGrantedScopes(res: Response, origin?: string) {\n res.cookie(this.grantedScopeCookie, '', {\n maxAge: 0,\n ...this.getConfig(origin),\n });\n }\n\n setGrantedScopes(res: Response, scope: string, origin?: string) {\n res.cookie(this.grantedScopeCookie, scope, {\n maxAge: THOUSAND_DAYS_MS,\n ...this.getConfig(origin),\n });\n }\n\n getNonce(req: Request): string | undefined {\n return req.cookies[this.nonceCookie];\n }\n\n getRefreshToken(req: Request): string | undefined {\n return req.cookies[this.refreshTokenCookie];\n }\n\n getGrantedScopes(req: Request): string | undefined {\n return req.cookies[this.grantedScopeCookie];\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport {\n OAuthAuthenticator,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorScopeOptions,\n} from './types';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport { OAuthState } from './state';\nimport { AuthenticationError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\n\nfunction reqRes(req: express.Request): express.Response {\n const res = req.res;\n if (!res) {\n throw new Error('No response object found in request');\n }\n return res;\n}\n\nconst defaultTransform: Required<OAuthAuthenticatorScopeOptions>['transform'] =\n ({ requested, granted, required, additional }) => {\n return [...requested, ...granted, ...required, ...additional];\n };\n\nfunction splitScope(scope?: string): Iterable<string> {\n if (!scope) {\n return [];\n }\n\n return scope.split(/[\\s|,]/).filter(Boolean);\n}\n\nexport class CookieScopeManager {\n static create(options: {\n config?: Config;\n additionalScopes?: string[];\n authenticator: OAuthAuthenticator<any, any>;\n cookieManager: OAuthCookieManager;\n }) {\n const { authenticator, config } = options;\n\n const shouldPersistScopes =\n authenticator.scopes?.persist ??\n authenticator.shouldPersistScopes ??\n false;\n\n const configScopes =\n typeof config?.getOptional('additionalScopes') === 'string'\n ? splitScope(config.getString('additionalScopes'))\n : config?.getOptionalStringArray('additionalScopes') ?? [];\n\n const transform = authenticator?.scopes?.transform ?? defaultTransform;\n const additional = [...configScopes, ...(options.additionalScopes ?? [])];\n const required = authenticator?.scopes?.required ?? [];\n\n return new CookieScopeManager(\n (requested, granted) =>\n Array.from(\n new Set(transform({ required, additional, requested, granted })),\n ).join(' '),\n shouldPersistScopes ? options.cookieManager : undefined,\n );\n }\n\n private constructor(\n private readonly scopeTransform: (\n requested: Iterable<string>,\n granted: Iterable<string>,\n ) => string,\n private readonly cookieManager?: OAuthCookieManager,\n ) {}\n\n async start(\n req: express.Request,\n ): Promise<{ scopeState?: Partial<OAuthState>; scope: string }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n if (this.cookieManager) {\n // If scopes are persisted then we pass them through the state so that we\n // can set the cookie on successful auth\n return {\n scope,\n scopeState: { scope },\n };\n }\n return { scope };\n }\n\n async handleCallback(\n req: express.Request,\n ctx: {\n result: OAuthAuthenticatorResult<any>;\n state: OAuthState;\n origin?: string;\n },\n ): Promise<string> {\n // If we are not persisting scopes we can forward the scope from the result\n if (!this.cookieManager) {\n return Array.from(splitScope(ctx.result.session.scope)).join(' ');\n }\n\n const scope = ctx.state.scope;\n if (scope === undefined) {\n throw new AuthenticationError('No scope found in OAuth state');\n }\n\n // Store the scope that we have been granted for this session. This is useful if\n // the provider does not return granted scopes on refresh or if they are normalized.\n this.cookieManager.setGrantedScopes(reqRes(req), scope, ctx.origin);\n\n return scope;\n }\n\n async clear(req: express.Request): Promise<void> {\n if (this.cookieManager) {\n this.cookieManager.removeGrantedScopes(reqRes(req), req.get('origin'));\n }\n }\n\n async refresh(req: express.Request): Promise<{\n scope: string;\n commit(result: OAuthAuthenticatorResult<any>): Promise<string>;\n }> {\n const requestScope = splitScope(req.query.scope?.toString());\n const grantedScope = splitScope(this.cookieManager?.getGrantedScopes(req));\n\n const scope = this.scopeTransform(requestScope, grantedScope);\n\n return {\n scope,\n commit: async result => {\n if (this.cookieManager) {\n this.cookieManager.setGrantedScopes(\n reqRes(req),\n scope,\n req.get('origin'),\n );\n return scope;\n }\n\n return Array.from(splitScope(result.session.scope)).join(' ');\n },\n };\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport crypto from 'crypto';\nimport { URL } from 'url';\nimport {\n AuthenticationError,\n InputError,\n isError,\n NotAllowedError,\n} from '@backstage/errors';\nimport {\n encodeOAuthState,\n decodeOAuthState,\n OAuthStateTransform,\n} from './state';\nimport { sendWebMessageResponse } from '../flow';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { OAuthCookieManager } from './OAuthCookieManager';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n CookieConfigurer,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { Config } from '@backstage/config';\nimport { CookieScopeManager } from './CookieScopeManager';\n\n/** @public */\nexport interface OAuthRouteHandlersOptions<TProfile> {\n authenticator: OAuthAuthenticator<any, TProfile>;\n appUrl: string;\n baseUrl: string;\n isOriginAllowed: (origin: string) => boolean;\n providerId: string;\n config: Config;\n resolverContext: AuthResolverContext;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n cookieConfigurer?: CookieConfigurer;\n signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;\n}\n\n/** @internal */\ntype ClientOAuthResponse = ClientAuthResponse<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * (Optional) Id token issued for the signed in user.\n */\n idToken?: string;\n /**\n * Expiry of the access token in seconds.\n */\n expiresInSeconds?: number;\n /**\n * Scopes granted for the access token.\n */\n scope: string;\n}>;\n\n/** @public */\nexport function createOAuthRouteHandlers<TProfile>(\n options: OAuthRouteHandlersOptions<TProfile>,\n): AuthProviderRouteHandlers {\n const {\n authenticator,\n config,\n baseUrl,\n appUrl,\n providerId,\n isOriginAllowed,\n cookieConfigurer,\n resolverContext,\n signInResolver,\n } = options;\n\n const defaultAppOrigin = new URL(appUrl).origin;\n const callbackUrl =\n config.getOptionalString('callbackUrl') ??\n `${baseUrl}/${providerId}/handler/frame`;\n\n const stateTransform = options.stateTransform ?? (state => ({ state }));\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config, callbackUrl });\n const cookieManager = new OAuthCookieManager({\n baseUrl,\n callbackUrl,\n defaultAppOrigin,\n providerId,\n cookieConfigurer,\n });\n\n const scopeManager = CookieScopeManager.create({\n config,\n authenticator,\n cookieManager,\n additionalScopes: options.additionalScopes,\n });\n\n return {\n async start(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n const env = req.query.env?.toString();\n const origin = req.query.origin?.toString();\n const redirectUrl = req.query.redirectUrl?.toString();\n const flow = req.query.flow?.toString();\n\n if (!env) {\n throw new InputError('No env provided in request query parameters');\n }\n\n const nonce = crypto.randomBytes(16).toString('base64');\n // set a nonce cookie before redirecting to oauth provider\n cookieManager.setNonce(res, nonce, origin);\n\n const { scope, scopeState } = await scopeManager.start(req);\n\n const state = { nonce, env, origin, redirectUrl, flow, ...scopeState };\n const { state: transformedState } = await stateTransform(state, { req });\n\n const { url, status } = await options.authenticator.start(\n {\n req,\n scope,\n state: encodeOAuthState(transformedState),\n },\n authenticatorCtx,\n );\n\n res.statusCode = status || 302;\n res.setHeader('Location', url);\n res.setHeader('Content-Length', '0');\n res.end();\n },\n\n async frameHandler(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n let origin = defaultAppOrigin;\n\n try {\n const state = decodeOAuthState(req.query.state?.toString() ?? '');\n\n if (state.origin) {\n try {\n origin = new URL(state.origin).origin;\n } catch {\n throw new NotAllowedError('App origin is invalid, failed to parse');\n }\n if (!isOriginAllowed(origin)) {\n throw new NotAllowedError(`Origin '${origin}' is not allowed`);\n }\n }\n\n // The same nonce is passed through cookie and state, and they must match\n const cookieNonce = cookieManager.getNonce(req);\n const stateNonce = state.nonce;\n if (!cookieNonce) {\n throw new NotAllowedError('Auth response is missing cookie nonce');\n }\n if (cookieNonce !== stateNonce) {\n throw new NotAllowedError('Invalid nonce');\n }\n\n const result = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n const { profile } = await profileTransform(result, resolverContext);\n\n const signInResult =\n signInResolver &&\n (await signInResolver({ profile, result }, resolverContext));\n\n const grantedScopes = await scopeManager.handleCallback(req, {\n result,\n state,\n origin,\n });\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScopes,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n ...(signInResult && {\n backstageIdentity: prepareBackstageIdentityResponse(signInResult),\n }),\n };\n\n if (result.session.refreshToken) {\n // set new refresh token\n cookieManager.setRefreshToken(\n res,\n result.session.refreshToken,\n origin,\n );\n }\n\n // When using the redirect flow we rely on refresh token we just\n // acquired to get a new session once we're back in the app.\n if (state.flow === 'redirect') {\n if (!state.redirectUrl) {\n throw new InputError(\n 'No redirectUrl provided in request query parameters',\n );\n }\n res.redirect(state.redirectUrl);\n return;\n }\n\n // post message back to popup if successful\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n response,\n });\n } catch (error) {\n const { name, message } = isError(error)\n ? error\n : new Error('Encountered invalid error'); // Being a bit safe and not forwarding the bad value\n // post error message back to popup if failure\n sendWebMessageResponse(res, origin, {\n type: 'authorization_response',\n error: { name, message },\n });\n }\n },\n\n async logout(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n if (authenticator.logout) {\n const refreshToken = cookieManager.getRefreshToken(req);\n await authenticator.logout({ req, refreshToken }, authenticatorCtx);\n }\n\n // remove refresh token cookie if it is set\n cookieManager.removeRefreshToken(res, req.get('origin'));\n\n // remove persisted scopes\n await scopeManager.clear(req);\n\n res.status(200).end();\n },\n\n async refresh(\n this: never,\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n // We use this as a lightweight CSRF protection\n if (req.header('X-Requested-With') !== 'XMLHttpRequest') {\n throw new AuthenticationError('Invalid X-Requested-With header');\n }\n\n try {\n const refreshToken = cookieManager.getRefreshToken(req);\n\n // throw error if refresh token is missing in the request\n if (!refreshToken) {\n throw new InputError('Missing session cookie');\n }\n\n const scopeRefresh = await scopeManager.refresh(req);\n\n const result = await authenticator.refresh(\n { req, scope: scopeRefresh.scope, refreshToken },\n authenticatorCtx,\n );\n\n const grantedScope = await scopeRefresh.commit(result);\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const newRefreshToken = result.session.refreshToken;\n if (newRefreshToken && newRefreshToken !== refreshToken) {\n cookieManager.setRefreshToken(\n res,\n newRefreshToken,\n req.get('origin'),\n );\n }\n\n const response: ClientOAuthResponse = {\n profile,\n providerInfo: {\n idToken: result.session.idToken,\n accessToken: result.session.accessToken,\n scope: grantedScope,\n expiresInSeconds: result.session.expiresInSeconds,\n },\n };\n\n if (signInResolver) {\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n response.backstageIdentity =\n prepareBackstageIdentityResponse(identity);\n }\n\n res.status(200).json(response);\n } catch (error) {\n throw new AuthenticationError('Refresh failed', error);\n }\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request } from 'express';\nimport { decodeJwt } from 'jose';\nimport { Strategy } from 'passport';\nimport { PassportProfile } from './types';\nimport { ProfileInfo } from '../types';\n\n// Re-declared here to avoid direct dependency on passport-oauth2\n/** @internal */\ninterface InternalOAuthError extends Error {\n oauthError?: {\n data?: string;\n };\n}\n\n/** @public */\nexport class PassportHelpers {\n private constructor() {}\n\n static transformProfile = (\n profile: PassportProfile,\n idToken?: string,\n ): ProfileInfo => {\n let email: string | undefined = undefined;\n if (profile.emails && profile.emails.length > 0) {\n const [firstEmail] = profile.emails;\n email = firstEmail.value;\n }\n\n let picture: string | undefined = undefined;\n if (profile.avatarUrl) {\n picture = profile.avatarUrl;\n } else if (profile.photos && profile.photos.length > 0) {\n const [firstPhoto] = profile.photos;\n picture = firstPhoto.value;\n }\n\n let displayName: string | undefined =\n profile.displayName ?? profile.username ?? profile.id;\n\n if ((!email || !picture || !displayName) && idToken) {\n try {\n const decoded = decodeJwt(idToken) as {\n email?: string;\n name?: string;\n picture?: string;\n };\n if (!email && decoded.email) {\n email = decoded.email;\n }\n if (!picture && decoded.picture) {\n picture = decoded.picture;\n }\n if (!displayName && decoded.name) {\n displayName = decoded.name;\n }\n } catch (e) {\n throw new Error(`Failed to parse id token and get profile info, ${e}`);\n }\n }\n\n return {\n email,\n picture,\n displayName,\n };\n };\n\n static async executeRedirectStrategy(\n req: Request,\n providerStrategy: Strategy,\n options: Record<string, string>,\n ): Promise<{\n /**\n * URL to redirect to\n */\n url: string;\n /**\n * Status code to use for the redirect\n */\n status?: number;\n }> {\n return new Promise(resolve => {\n const strategy = Object.create(providerStrategy);\n strategy.redirect = (url: string, status?: number) => {\n resolve({ url, status: status ?? undefined });\n };\n\n strategy.authenticate(req, { ...options });\n });\n }\n\n static async executeFrameHandlerStrategy<TResult, TPrivateInfo = never>(\n req: Request,\n providerStrategy: Strategy,\n options?: Record<string, string>,\n ): Promise<{ result: TResult; privateInfo: TPrivateInfo }> {\n return new Promise((resolve, reject) => {\n const strategy = Object.create(providerStrategy);\n strategy.success = (result: any, privateInfo: any) => {\n resolve({ result, privateInfo });\n };\n strategy.fail = (\n info: { type: 'success' | 'error'; message?: string },\n // _status: number,\n ) => {\n reject(new Error(`Authentication rejected, ${info.message ?? ''}`));\n };\n strategy.error = (error: InternalOAuthError) => {\n let message = `Authentication failed, ${error.message}`;\n\n if (error.oauthError?.data) {\n try {\n const errorData = JSON.parse(error.oauthError.data);\n\n if (errorData.message) {\n message += ` - ${errorData.message}`;\n }\n } catch (parseError) {\n message += ` - ${error.oauthError}`;\n }\n }\n\n reject(new Error(message));\n };\n strategy.redirect = () => {\n reject(new Error('Unexpected redirect'));\n };\n strategy.authenticate(req, { ...(options ?? {}) });\n });\n }\n\n static async executeRefreshTokenStrategy(\n providerStrategy: Strategy,\n refreshToken: string,\n scope: string,\n ): Promise<{\n /**\n * An access token issued for the signed in user.\n */\n accessToken: string;\n /**\n * Optionally, the server can issue a new Refresh Token for the user\n */\n refreshToken?: string;\n params: any;\n }> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as any;\n const OAuth2 = anyStrategy._oauth2.constructor;\n const oauth2 = new OAuth2(\n anyStrategy._oauth2._clientId,\n anyStrategy._oauth2._clientSecret,\n anyStrategy._oauth2._baseSite,\n anyStrategy._oauth2._authorizeUrl,\n anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,\n anyStrategy._oauth2._customHeaders,\n );\n\n oauth2.getOAuthAccessToken(\n refreshToken,\n {\n scope,\n grant_type: 'refresh_token',\n },\n (\n err: Error | null,\n accessToken: string,\n newRefreshToken: string,\n params: any,\n ) => {\n if (err) {\n reject(\n new Error(`Failed to refresh access token ${err.toString()}`),\n );\n }\n if (!accessToken) {\n reject(\n new Error(\n `Failed to refresh access token, no access token received`,\n ),\n );\n }\n\n resolve({\n accessToken,\n refreshToken: newRefreshToken,\n params,\n });\n },\n );\n });\n }\n\n static async executeFetchUserProfileStrategy(\n providerStrategy: Strategy,\n accessToken: string,\n ): Promise<PassportProfile> {\n return new Promise((resolve, reject) => {\n const anyStrategy = providerStrategy as unknown as {\n userProfile(accessToken: string, callback: Function): void;\n };\n anyStrategy.userProfile(\n accessToken,\n (error: Error, rawProfile: PassportProfile) => {\n if (error) {\n reject(error);\n } else {\n resolve(rawProfile);\n }\n },\n );\n });\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Strategy } from 'passport';\nimport {\n PassportDoneCallback,\n PassportHelpers,\n PassportProfile,\n} from '../passport';\nimport { ProfileTransform } from '../types';\nimport {\n OAuthAuthenticatorAuthenticateInput,\n OAuthAuthenticatorRefreshInput,\n OAuthAuthenticatorResult,\n OAuthAuthenticatorStartInput,\n} from './types';\n\n/** @public */\nexport type PassportOAuthResult = {\n fullProfile: PassportProfile;\n params: {\n id_token?: string;\n scope: string;\n token_type?: string;\n expires_in: number;\n };\n accessToken: string;\n};\n\n/** @public */\nexport type PassportOAuthPrivateInfo = {\n refreshToken?: string;\n};\n\n/** @public */\nexport type PassportOAuthDoneCallback = PassportDoneCallback<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n>;\n\n/** @public */\nexport class PassportOAuthAuthenticatorHelper {\n static defaultProfileTransform: ProfileTransform<\n OAuthAuthenticatorResult<PassportProfile>\n > = async input => ({\n profile: PassportHelpers.transformProfile(\n input.fullProfile ?? {},\n input.session.idToken,\n ),\n });\n\n static from(strategy: Strategy) {\n return new PassportOAuthAuthenticatorHelper(strategy);\n }\n\n readonly #strategy: Strategy;\n\n private constructor(strategy: Strategy) {\n this.#strategy = strategy;\n }\n\n async start(\n input: OAuthAuthenticatorStartInput,\n options: Record<string, string>,\n ): Promise<{ url: string; status?: number }> {\n return PassportHelpers.executeRedirectStrategy(input.req, this.#strategy, {\n scope: input.scope,\n state: input.state,\n ...options,\n });\n }\n\n async authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ): Promise<OAuthAuthenticatorResult<PassportProfile>> {\n const { result, privateInfo } =\n await PassportHelpers.executeFrameHandlerStrategy<\n PassportOAuthResult,\n PassportOAuthPrivateInfo\n >(input.req, this.#strategy);\n\n return {\n fullProfile: result.fullProfile as PassportProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: privateInfo.refreshToken,\n },\n };\n }\n\n async refresh(\n input: OAuthAuthenticatorRefreshInput,\n ): Promise<OAuthAuthenticatorResult<PassportProfile>> {\n const result = await PassportHelpers.executeRefreshTokenStrategy(\n this.#strategy,\n input.refreshToken,\n input.scope,\n );\n const fullProfile = await this.fetchProfile(result.accessToken);\n return {\n fullProfile,\n session: {\n accessToken: result.accessToken,\n tokenType: result.params.token_type ?? 'bearer',\n scope: result.params.scope,\n expiresInSeconds: result.params.expires_in,\n idToken: result.params.id_token,\n refreshToken: result.refreshToken,\n },\n };\n }\n\n async fetchProfile(accessToken: string): Promise<PassportProfile> {\n const profile = await PassportHelpers.executeFetchUserProfileStrategy(\n this.#strategy,\n accessToken,\n );\n return profile;\n }\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport { Config } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { AuthProviderRouteHandlers } from '../types';\nimport { decodeOAuthState } from './state';\n\n/** @public */\nexport class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {\n static mapConfig(\n config: Config,\n factoryFunc: (envConfig: Config) => AuthProviderRouteHandlers,\n ) {\n const envs = config.keys();\n const handlers = new Map<string, AuthProviderRouteHandlers>();\n\n for (const env of envs) {\n const envConfig = config.getConfig(env);\n const handler = factoryFunc(envConfig);\n handlers.set(env, handler);\n }\n\n return new OAuthEnvironmentHandler(handlers);\n }\n\n constructor(\n private readonly handlers: Map<string, AuthProviderRouteHandlers>,\n ) {}\n\n async start(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.start(req, res);\n }\n\n async frameHandler(\n req: express.Request,\n res: express.Response,\n ): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.frameHandler(req, res);\n }\n\n async refresh(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.refresh?.(req, res);\n }\n\n async logout(req: express.Request, res: express.Response): Promise<void> {\n const provider = this.getProviderForEnv(req);\n await provider.logout?.(req, res);\n }\n\n private getEnvFromRequest(req: express.Request): string | undefined {\n const reqEnv = req.query.env?.toString();\n if (reqEnv) {\n return reqEnv;\n }\n const stateParams = req.query.state?.toString();\n if (!stateParams) {\n return undefined;\n }\n const { env } = decodeOAuthState(stateParams);\n return env;\n }\n\n private getProviderForEnv(req: express.Request): AuthProviderRouteHandlers {\n const env: string | undefined = this.getEnvFromRequest(req);\n\n if (!env) {\n throw new InputError(`Must specify 'env' query to select environment`);\n }\n\n const handler = this.handlers.get(env);\n if (!handler) {\n throw new NotFoundError(\n `No configuration available for the '${env}' environment of this provider.`,\n );\n }\n\n return handler;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ZodSchema, ZodTypeDef } from 'zod';\nimport { SignInResolver } from '../types';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { JsonObject } from '@backstage/types';\nimport { InputError } from '@backstage/errors';\n\n/** @public */\nexport interface SignInResolverFactory<TAuthResult, TOptions> {\n (\n ...options: undefined extends TOptions\n ? [options?: TOptions]\n : [options: TOptions]\n ): SignInResolver<TAuthResult>;\n optionsJsonSchema?: JsonObject;\n}\n\n/** @public */\nexport interface SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n> {\n optionsSchema?: ZodSchema<TOptionsOutput, ZodTypeDef, TOptionsInput>;\n create(options: TOptionsOutput): SignInResolver<TAuthResult>;\n}\n\n/** @public */\nexport function createSignInResolverFactory<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput,\n>(\n options: SignInResolverFactoryOptions<\n TAuthResult,\n TOptionsOutput,\n TOptionsInput\n >,\n): SignInResolverFactory<TAuthResult, TOptionsInput> {\n const { optionsSchema } = options;\n if (!optionsSchema) {\n return (resolverOptions?: TOptionsInput) => {\n if (resolverOptions) {\n throw new InputError('sign-in resolver does not accept options');\n }\n return options.create(undefined as TOptionsOutput);\n };\n }\n const factory = (\n ...[resolverOptions]: undefined extends TOptionsInput\n ? [options?: TOptionsInput]\n : [options: TOptionsInput]\n ) => {\n const parsedOptions = optionsSchema.parse(resolverOptions);\n return options.create(parsedOptions);\n };\n\n factory.optionsJsonSchema = zodToJsonSchema(optionsSchema) as JsonObject;\n return factory;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { SignInResolver } from '../types';\nimport { SignInResolverFactory } from './createSignInResolverFactory';\n\n/** @public */\nexport interface ReadDeclarativeSignInResolverOptions<TAuthResult> {\n config: Config;\n signInResolverFactories: {\n [name in string]: SignInResolverFactory<TAuthResult, unknown>;\n };\n}\n\n/** @public */\nexport function readDeclarativeSignInResolver<TAuthResult>(\n options: ReadDeclarativeSignInResolverOptions<TAuthResult>,\n): SignInResolver<TAuthResult> | undefined {\n const resolvers =\n options.config\n .getOptionalConfigArray('signIn.resolvers')\n ?.map(resolverConfig => {\n const resolverName = resolverConfig.getString('resolver');\n if (!Object.hasOwn(options.signInResolverFactories, resolverName)) {\n throw new Error(\n `Sign-in resolver '${resolverName}' is not available`,\n );\n }\n const resolver = options.signInResolverFactories[resolverName];\n const { resolver: _ignored, ...resolverOptions } =\n resolverConfig.get<JsonObject>();\n\n return resolver(\n Object.keys(resolverOptions).length > 0 ? resolverOptions : undefined,\n );\n }) ?? [];\n\n if (resolvers.length === 0) {\n return undefined;\n }\n\n return async (profile, context) => {\n for (const resolver of resolvers) {\n try {\n return await resolver(profile, context);\n } catch (error) {\n if (error?.name === 'NotFoundError') {\n continue;\n }\n throw error;\n }\n }\n\n throw new Error('Failed to sign-in, unable to resolve user identity');\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createSignInResolverFactory } from './createSignInResolverFactory';\n\n/**\n * A collection of common sign-in resolvers that work with any auth provider.\n *\n * @public\n */\nexport namespace commonSignInResolvers {\n /**\n * A common sign-in resolver that looks up the user using their email address\n * as email of the entity.\n */\n export const emailMatchingUserEntityProfileEmail =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n\n return ctx.signInWithCatalogUser({\n filter: {\n 'spec.profile.email': profile.email,\n },\n });\n };\n },\n });\n\n /**\n * A common sign-in resolver that looks up the user using the local part of\n * their email address as the entity name.\n */\n export const emailLocalPartMatchingUserEntityName =\n createSignInResolverFactory({\n create() {\n return async (info, ctx) => {\n const { profile } = info;\n\n if (!profile.email) {\n throw new Error(\n 'Login failed, user profile does not contain an email',\n );\n }\n const [localPart] = profile.email.split('@');\n\n return ctx.signInWithCatalogUser({\n entityRef: { name: localPart },\n });\n };\n },\n });\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { readDeclarativeSignInResolver } from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler';\nimport { createOAuthRouteHandlers } from './createOAuthRouteHandlers';\nimport { OAuthStateTransform } from './state';\nimport { OAuthAuthenticator, OAuthAuthenticatorResult } from './types';\nimport { SignInResolverFactory } from '../sign-in/createSignInResolverFactory';\n\n/** @public */\nexport function createOAuthProviderFactory<TProfile>(options: {\n authenticator: OAuthAuthenticator<unknown, TProfile>;\n additionalScopes?: string[];\n stateTransform?: OAuthStateTransform;\n profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;\n signInResolverFactories?: {\n [name in string]: SignInResolverFactory<\n OAuthAuthenticatorResult<TProfile>,\n unknown\n >;\n };\n}): AuthProviderFactory {\n return ctx => {\n return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: envConfig,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n return createOAuthRouteHandlers<TProfile>({\n authenticator: options.authenticator,\n appUrl: ctx.appUrl,\n baseUrl: ctx.baseUrl,\n config: envConfig,\n isOriginAllowed: ctx.isOriginAllowed,\n cookieConfigurer: ctx.cookieConfigurer,\n providerId: ctx.providerId,\n resolverContext: ctx.resolverContext,\n additionalScopes: options.additionalScopes,\n stateTransform: options.stateTransform,\n profileTransform: options.profileTransform,\n signInResolver,\n });\n });\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface OAuthSession {\n accessToken: string;\n tokenType: string;\n idToken?: string;\n scope: string;\n expiresInSeconds?: number;\n refreshToken?: string;\n refreshTokenExpiresInSeconds?: number;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorScopeOptions {\n persist?: boolean;\n required?: string[];\n transform?: (options: {\n /** Scopes requested by the client */\n requested: Iterable<string>;\n /** Scopes which have already been granted */\n granted: Iterable<string>;\n /** Scopes that are required for the authenticator to function */\n required: Iterable<string>;\n /** Additional scopes added through configuration */\n additional: Iterable<string>;\n }) => Iterable<string>;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorStartInput {\n scope: string;\n state: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorAuthenticateInput {\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorRefreshInput {\n scope: string;\n refreshToken: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorLogoutInput {\n accessToken?: string;\n refreshToken?: string;\n req: Request;\n}\n\n/** @public */\nexport interface OAuthAuthenticatorResult<TProfile> {\n fullProfile: TProfile;\n session: OAuthSession;\n}\n\n/** @public */\nexport interface OAuthAuthenticator<TContext, TProfile> {\n defaultProfileTransform: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;\n /** @deprecated use `scopes.persist` instead */\n shouldPersistScopes?: boolean;\n scopes?: OAuthAuthenticatorScopeOptions;\n initialize(ctx: { callbackUrl: string; config: Config }): TContext;\n start(\n input: OAuthAuthenticatorStartInput,\n ctx: TContext,\n ): Promise<{ url: string; status?: number }>;\n authenticate(\n input: OAuthAuthenticatorAuthenticateInput,\n ctx: TContext,\n ): Promise<OAuthAuthenticatorResult<TProfile>>;\n refresh(\n input: OAuthAuthenticatorRefreshInput,\n ctx: TContext,\n ): Promise<OAuthAuthenticatorResult<TProfile>>;\n logout?(input: OAuthAuthenticatorLogoutInput, ctx: TContext): Promise<void>;\n}\n\n/** @public */\nexport function createOAuthAuthenticator<TContext, TProfile>(\n authenticator: OAuthAuthenticator<TContext, TProfile>,\n): OAuthAuthenticator<TContext, TProfile> {\n return authenticator;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Request } from 'express';\nimport { ProfileTransform } from '../types';\n\n/** @public */\nexport interface ProxyAuthenticator<\n TContext,\n TResult,\n TProviderInfo = undefined,\n> {\n defaultProfileTransform: ProfileTransform<TResult>;\n initialize(ctx: { config: Config }): TContext;\n authenticate(\n options: { req: Request },\n ctx: TContext,\n ): Promise<{ result: TResult; providerInfo?: TProviderInfo }>;\n}\n\n/** @public */\nexport function createProxyAuthenticator<TContext, TResult, TProviderInfo>(\n authenticator: ProxyAuthenticator<TContext, TResult, TProviderInfo>,\n): ProxyAuthenticator<TContext, TResult, TProviderInfo> {\n return authenticator;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Request, Response } from 'express';\nimport { Config } from '@backstage/config';\nimport {\n AuthProviderRouteHandlers,\n AuthResolverContext,\n ClientAuthResponse,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { ProxyAuthenticator } from './types';\nimport { prepareBackstageIdentityResponse } from '../identity';\nimport { NotImplementedError } from '@backstage/errors';\n\n/** @public */\nexport interface ProxyAuthRouteHandlersOptions<TResult> {\n authenticator: ProxyAuthenticator<any, TResult, unknown>;\n config: Config;\n resolverContext: AuthResolverContext;\n signInResolver: SignInResolver<TResult>;\n profileTransform?: ProfileTransform<TResult>;\n}\n\n/** @public */\nexport function createProxyAuthRouteHandlers<TResult>(\n options: ProxyAuthRouteHandlersOptions<TResult>,\n): AuthProviderRouteHandlers {\n const { authenticator, config, resolverContext, signInResolver } = options;\n\n const profileTransform =\n options.profileTransform ?? authenticator.defaultProfileTransform;\n const authenticatorCtx = authenticator.initialize({ config });\n\n return {\n async start(): Promise<void> {\n throw new NotImplementedError('Not implemented');\n },\n\n async frameHandler(): Promise<void> {\n throw new NotImplementedError('Not implemented');\n },\n\n async refresh(this: never, req: Request, res: Response): Promise<void> {\n const { result, providerInfo } = await authenticator.authenticate(\n { req },\n authenticatorCtx,\n );\n\n const { profile } = await profileTransform(result, resolverContext);\n\n const identity = await signInResolver(\n { profile, result },\n resolverContext,\n );\n\n const response: ClientAuthResponse<unknown> = {\n profile,\n providerInfo,\n backstageIdentity: prepareBackstageIdentityResponse(identity),\n };\n\n res.status(200).json(response);\n },\n };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readDeclarativeSignInResolver,\n SignInResolverFactory,\n} from '../sign-in';\nimport {\n AuthProviderFactory,\n ProfileTransform,\n SignInResolver,\n} from '../types';\nimport { createProxyAuthRouteHandlers } from './createProxyRouteHandlers';\nimport { ProxyAuthenticator } from './types';\n\n/** @public */\nexport function createProxyAuthProviderFactory<TResult>(options: {\n authenticator: ProxyAuthenticator<unknown, TResult, unknown>;\n profileTransform?: ProfileTransform<TResult>;\n signInResolver?: SignInResolver<TResult>;\n signInResolverFactories?: Record<\n string,\n SignInResolverFactory<TResult, unknown>\n >;\n}): AuthProviderFactory {\n return ctx => {\n const signInResolver =\n options.signInResolver ??\n readDeclarativeSignInResolver({\n config: ctx.config,\n signInResolverFactories: options.signInResolverFactories ?? {},\n });\n\n if (!signInResolver) {\n throw new Error(\n `No sign-in resolver configured for proxy auth provider '${ctx.providerId}'`,\n );\n }\n\n return createProxyAuthRouteHandlers<TResult>({\n signInResolver,\n config: ctx.config,\n authenticator: options.authenticator,\n resolverContext: ctx.resolverContext,\n profileTransform: options.profileTransform,\n });\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { EntityFilterQuery } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { Request, Response } from 'express';\n\n/**\n * A representation of a successful Backstage sign-in.\n *\n * Compared to the {@link BackstageIdentityResponse} this type omits\n * the decoded identity information embedded in the token.\n *\n * @public\n */\nexport interface BackstageSignInResult {\n /**\n * The token used to authenticate the user within Backstage.\n */\n token: string;\n}\n\n/**\n * Response object containing the {@link BackstageUserIdentity} and the token\n * from the authentication provider.\n *\n * @public\n */\nexport interface BackstageIdentityResponse extends BackstageSignInResult {\n /**\n * The number of seconds until the token expires. If not set, it can be assumed that the token does not expire.\n */\n expiresInSeconds?: number;\n\n /**\n * A plaintext description of the identity that is encapsulated within the token.\n */\n identity: BackstageUserIdentity;\n}\n\n/**\n * User identity information within Backstage.\n *\n * @public\n */\nexport type BackstageUserIdentity = {\n /**\n * The type of identity that this structure represents. In the frontend app\n * this will currently always be 'user'.\n */\n type: 'user';\n\n /**\n * The entityRef of the user in the catalog.\n * For example User:default/sandra\n */\n userEntityRef: string;\n\n /**\n * The user and group entities that the user claims ownership through\n */\n ownershipEntityRefs: string[];\n};\n\n/**\n * A query for a single user in the catalog.\n *\n * If `entityRef` is used, the default kind is `'User'`.\n *\n * If `annotations` are used, all annotations must be present and\n * match the provided value exactly. Only entities of kind `'User'` will be considered.\n *\n * If `filter` are used, only entities of kind `'User'` will be considered unless it is explicitly specified differently in the filter.\n *\n * Regardless of the query method, the query must match exactly one entity\n * in the catalog, or an error will be thrown.\n *\n * @public\n */\nexport type AuthResolverCatalogUserQuery =\n | {\n entityRef:\n | string\n | {\n kind?: string;\n namespace?: string;\n name: string;\n };\n }\n | {\n annotations: Record<string, string>;\n }\n | {\n filter: EntityFilterQuery;\n };\n\n/**\n * Parameters used to issue new Backstage Tokens\n *\n * @public\n */\nexport type TokenParams = {\n /**\n * The claims that will be embedded within the token. At a minimum, this should include\n * the subject claim, `sub`. It is common to also list entity ownership relations in the\n * `ent` list. Additional claims may also be added at the developer's discretion except\n * for the following list, which will be overwritten by the TokenIssuer: `iss`, `aud`,\n * `iat`, and `exp`. The Backstage team also maintains the right add new claims in the future\n * without listing the change as a \"breaking change\".\n */\n claims: {\n /** The token subject, i.e. User ID */\n sub: string;\n /** A list of entity references that the user claims ownership through */\n ent?: string[];\n } & Record<string, JsonValue>;\n};\n\n/**\n * The context that is used for auth processing.\n *\n * @public\n */\nexport type AuthResolverContext = {\n /**\n * Issues a Backstage token using the provided parameters.\n */\n issueToken(params: TokenParams): Promise<{ token: string }>;\n\n /**\n * Finds a single user in the catalog using the provided query.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n findCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<{ entity: Entity }>;\n\n /**\n * Finds a single user in the catalog using the provided query, and then\n * issues an identity for that user using default ownership resolution.\n *\n * See {@link AuthResolverCatalogUserQuery} for details.\n */\n signInWithCatalogUser(\n query: AuthResolverCatalogUserQuery,\n ): Promise<BackstageSignInResult>;\n};\n\n/**\n * Resolver interface for resolving the ownership entity references for entity\n *\n * @public\n */\nexport interface AuthOwnershipResolver {\n resolveOwnershipEntityRefs(\n entity: Entity,\n ): Promise<{ ownershipEntityRefs: string[] }>;\n}\n\n/**\n * Any Auth provider needs to implement this interface which handles the routes in the\n * auth backend. Any auth API requests from the frontend reaches these methods.\n *\n * The routes in the auth backend API are tied to these methods like below\n *\n * `/auth/[provider]/start -> start`\n * `/auth/[provider]/handler/frame -> frameHandler`\n * `/auth/[provider]/refresh -> refresh`\n * `/auth/[provider]/logout -> logout`\n *\n * @public\n */\nexport interface AuthProviderRouteHandlers {\n /**\n * Handles the start route of the API. This initiates a sign in request with an auth provider.\n *\n * Request\n * - scopes for the auth request (Optional)\n * Response\n * - redirect to the auth provider for the user to sign in or consent.\n * - sets a nonce cookie and also pass the nonce as 'state' query parameter in the redirect request\n */\n start(req: Request, res: Response): Promise<void>;\n\n /**\n * Once the user signs in or consents in the OAuth screen, the auth provider redirects to the\n * callbackURL which is handled by this method.\n *\n * Request\n * - to contain a nonce cookie and a 'state' query parameter\n * Response\n * - postMessage to the window with a payload that contains accessToken, expiryInSeconds?, idToken? and scope.\n * - sets a refresh token cookie if the auth provider supports refresh tokens\n */\n frameHandler(req: Request, res: Response): Promise<void>;\n\n /**\n * (Optional) If the auth provider supports refresh tokens then this method handles\n * requests to get a new access token.\n *\n * Other types of providers may also use this method to implement its own logic to create new sessions\n * upon request. For example, this can be used to create a new session for a provider that handles requests\n * from an authenticating proxy.\n *\n * Request\n * - to contain a refresh token cookie and scope (Optional) query parameter.\n * Response\n * - payload with accessToken, expiryInSeconds?, idToken?, scope and user profile information.\n */\n refresh?(req: Request, res: Response): Promise<void>;\n\n /**\n * (Optional) Handles sign out requests\n *\n * Response\n * - removes the refresh token cookie\n */\n logout?(req: Request, res: Response): Promise<void>;\n}\n\n/**\n * @public\n * @deprecated Use top-level properties passed to `AuthProviderFactory` instead\n */\nexport type AuthProviderConfig = {\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n};\n\n/** @public */\nexport type AuthProviderFactory = (options: {\n providerId: string;\n /** @deprecated Use top-level properties instead */\n globalConfig: AuthProviderConfig;\n config: Config;\n logger: LoggerService;\n resolverContext: AuthResolverContext;\n /**\n * The protocol://domain[:port] where the app is hosted. This is used to construct the\n * callbackURL to redirect to once the user signs in to the auth provider.\n */\n baseUrl: string;\n\n /**\n * The base URL of the app as provided by app.baseUrl\n */\n appUrl: string;\n\n /**\n * A function that is called to check whether an origin is allowed to receive the authentication result.\n */\n isOriginAllowed: (origin: string) => boolean;\n\n /**\n * The function used to resolve cookie configuration based on the auth provider options.\n */\n cookieConfigurer?: CookieConfigurer;\n}) => AuthProviderRouteHandlers;\n\n/** @public */\nexport type ClientAuthResponse<TProviderInfo> = {\n providerInfo: TProviderInfo;\n profile: ProfileInfo;\n backstageIdentity?: BackstageIdentityResponse;\n};\n\n/**\n * Type of sign in information context. Includes the profile information and\n * authentication result which contains auth related information.\n *\n * @public\n */\nexport type SignInInfo<TAuthResult> = {\n /**\n * The simple profile passed down for use in the frontend.\n */\n profile: ProfileInfo;\n\n /**\n * The authentication result that was received from the authentication\n * provider.\n */\n result: TAuthResult;\n};\n\n/**\n * Describes the function which handles the result of a successful\n * authentication. Must return a valid {@link @backstage/plugin-auth-node#BackstageSignInResult}.\n *\n * @public\n */\nexport type SignInResolver<TAuthResult> = (\n info: SignInInfo<TAuthResult>,\n context: AuthResolverContext,\n) => Promise<BackstageSignInResult>;\n\n/**\n * Describes the function that transforms the result of a successful\n * authentication into a {@link ProfileInfo} object.\n *\n * This function may optionally throw an error in order to reject authentication.\n *\n * @public\n */\nexport type ProfileTransform<TResult> = (\n result: TResult,\n context: AuthResolverContext,\n) => Promise<{ profile: ProfileInfo }>;\n\n/**\n * Used to display login information to user, i.e. sidebar popup.\n *\n * It is also temporarily used as the profile of the signed-in user's Backstage\n * identity, but we want to replace that with data from identity and/org catalog\n * service\n *\n * @public\n */\nexport type ProfileInfo = {\n /**\n * Email ID of the signed in user.\n */\n email?: string;\n /**\n * Display name that can be presented to the signed in user.\n */\n displayName?: string;\n /**\n * URL to an image that can be used as the display image or avatar of the\n * signed in user.\n */\n picture?: string;\n};\n\n/**\n * The callback used to resolve the cookie configuration for auth providers that use cookies.\n * @public\n */\nexport type CookieConfigurer = (ctx: {\n /** ID of the auth provider that this configuration applies to */\n providerId: string;\n /** The externally reachable base URL of the auth-backend plugin */\n baseUrl: string;\n /** The configured callback URL of the auth provider */\n callbackUrl: string;\n /** The origin URL of the app */\n appOrigin: string;\n}) => {\n domain: string;\n path: string;\n secure: boolean;\n sameSite?: 'none' | 'lax' | 'strict';\n};\n\n/**\n * Core properties of various token types.\n *\n * @public\n */\nexport const tokenTypes = Object.freeze({\n user: Object.freeze({\n typParam: 'vnd.backstage.user',\n audClaim: 'backstage',\n }),\n limitedUser: Object.freeze({\n typParam: 'vnd.backstage.limited-user',\n }),\n plugin: Object.freeze({\n typParam: 'vnd.backstage.plugin',\n }),\n});\n"],"names":["createExtensionPoint","serializeError","crypto","InputError","AuthenticationError","jwtVerify","decodeJwt","decodeProtectedHeader","createRemoteJWKSet","pickBy","NotAllowedError","URL","isError","NotFoundError","zodToJsonSchema","commonSignInResolvers","NotImplementedError"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -542,6 +542,21 @@ interface OAuthSession {
542
542
  refreshTokenExpiresInSeconds?: number;
543
543
  }
544
544
  /** @public */
545
+ interface OAuthAuthenticatorScopeOptions {
546
+ persist?: boolean;
547
+ required?: string[];
548
+ transform?: (options: {
549
+ /** Scopes requested by the client */
550
+ requested: Iterable<string>;
551
+ /** Scopes which have already been granted */
552
+ granted: Iterable<string>;
553
+ /** Scopes that are required for the authenticator to function */
554
+ required: Iterable<string>;
555
+ /** Additional scopes added through configuration */
556
+ additional: Iterable<string>;
557
+ }) => Iterable<string>;
558
+ }
559
+ /** @public */
545
560
  interface OAuthAuthenticatorStartInput {
546
561
  scope: string;
547
562
  state: string;
@@ -571,7 +586,9 @@ interface OAuthAuthenticatorResult<TProfile> {
571
586
  /** @public */
572
587
  interface OAuthAuthenticator<TContext, TProfile> {
573
588
  defaultProfileTransform: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;
589
+ /** @deprecated use `scopes.persist` instead */
574
590
  shouldPersistScopes?: boolean;
591
+ scopes?: OAuthAuthenticatorScopeOptions;
575
592
  initialize(ctx: {
576
593
  callbackUrl: string;
577
594
  config: Config;
@@ -596,6 +613,7 @@ interface OAuthRouteHandlersOptions<TProfile> {
596
613
  providerId: string;
597
614
  config: Config;
598
615
  resolverContext: AuthResolverContext;
616
+ additionalScopes?: string[];
599
617
  stateTransform?: OAuthStateTransform;
600
618
  profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;
601
619
  cookieConfigurer?: CookieConfigurer;
@@ -704,6 +722,7 @@ declare function createSignInResolverFactory<TAuthResult, TOptionsOutput, TOptio
704
722
  /** @public */
705
723
  declare function createOAuthProviderFactory<TProfile>(options: {
706
724
  authenticator: OAuthAuthenticator<unknown, TProfile>;
725
+ additionalScopes?: string[];
707
726
  stateTransform?: OAuthStateTransform;
708
727
  profileTransform?: ProfileTransform<OAuthAuthenticatorResult<TProfile>>;
709
728
  signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;
@@ -775,4 +794,4 @@ interface ProxyAuthRouteHandlersOptions<TResult> {
775
794
  /** @public */
776
795
  declare function createProxyAuthRouteHandlers<TResult>(options: ProxyAuthRouteHandlersOptions<TResult>): AuthProviderRouteHandlers;
777
796
 
778
- export { type AuthOwnershipResolutionExtensionPoint, type AuthOwnershipResolver, type AuthProviderConfig, type AuthProviderFactory, type AuthProviderRegistrationOptions, type AuthProviderRouteHandlers, type AuthProvidersExtensionPoint, type AuthResolverCatalogUserQuery, type AuthResolverContext, type BackstageIdentityResponse, type BackstageSignInResult, type BackstageUserIdentity, type ClientAuthResponse, type CookieConfigurer, DefaultIdentityClient, type IdentityApi, type IdentityApiGetIdentityRequest, IdentityClient, type IdentityClientOptions, type OAuthAuthenticator, type OAuthAuthenticatorAuthenticateInput, type OAuthAuthenticatorLogoutInput, type OAuthAuthenticatorRefreshInput, type OAuthAuthenticatorResult, type OAuthAuthenticatorStartInput, OAuthEnvironmentHandler, type OAuthRouteHandlersOptions, type OAuthSession, type OAuthState, type OAuthStateTransform, type PassportDoneCallback, PassportHelpers, PassportOAuthAuthenticatorHelper, type PassportOAuthDoneCallback, type PassportOAuthPrivateInfo, type PassportOAuthResult, type PassportProfile, type ProfileInfo, type ProfileTransform, type ProxyAuthRouteHandlersOptions, type ProxyAuthenticator, type ReadDeclarativeSignInResolverOptions, type SignInInfo, type SignInResolver, type SignInResolverFactory, type SignInResolverFactoryOptions, type TokenParams, type WebMessageResponse, authOwnershipResolutionExtensionPoint, authProvidersExtensionPoint, commonSignInResolvers, createOAuthAuthenticator, createOAuthProviderFactory, createOAuthRouteHandlers, createProxyAuthProviderFactory, createProxyAuthRouteHandlers, createProxyAuthenticator, createSignInResolverFactory, decodeOAuthState, encodeOAuthState, getBearerTokenFromAuthorizationHeader, prepareBackstageIdentityResponse, readDeclarativeSignInResolver, sendWebMessageResponse, tokenTypes };
797
+ export { type AuthOwnershipResolutionExtensionPoint, type AuthOwnershipResolver, type AuthProviderConfig, type AuthProviderFactory, type AuthProviderRegistrationOptions, type AuthProviderRouteHandlers, type AuthProvidersExtensionPoint, type AuthResolverCatalogUserQuery, type AuthResolverContext, type BackstageIdentityResponse, type BackstageSignInResult, type BackstageUserIdentity, type ClientAuthResponse, type CookieConfigurer, DefaultIdentityClient, type IdentityApi, type IdentityApiGetIdentityRequest, IdentityClient, type IdentityClientOptions, type OAuthAuthenticator, type OAuthAuthenticatorAuthenticateInput, type OAuthAuthenticatorLogoutInput, type OAuthAuthenticatorRefreshInput, type OAuthAuthenticatorResult, type OAuthAuthenticatorScopeOptions, type OAuthAuthenticatorStartInput, OAuthEnvironmentHandler, type OAuthRouteHandlersOptions, type OAuthSession, type OAuthState, type OAuthStateTransform, type PassportDoneCallback, PassportHelpers, PassportOAuthAuthenticatorHelper, type PassportOAuthDoneCallback, type PassportOAuthPrivateInfo, type PassportOAuthResult, type PassportProfile, type ProfileInfo, type ProfileTransform, type ProxyAuthRouteHandlersOptions, type ProxyAuthenticator, type ReadDeclarativeSignInResolverOptions, type SignInInfo, type SignInResolver, type SignInResolverFactory, type SignInResolverFactoryOptions, type TokenParams, type WebMessageResponse, authOwnershipResolutionExtensionPoint, authProvidersExtensionPoint, commonSignInResolvers, createOAuthAuthenticator, createOAuthProviderFactory, createOAuthRouteHandlers, createProxyAuthProviderFactory, createProxyAuthRouteHandlers, createProxyAuthenticator, createSignInResolverFactory, decodeOAuthState, encodeOAuthState, getBearerTokenFromAuthorizationHeader, prepareBackstageIdentityResponse, readDeclarativeSignInResolver, sendWebMessageResponse, tokenTypes };
package/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "@backstage/plugin-auth-node",
3
- "version": "0.4.14-next.1",
3
+ "version": "0.4.14-next.3",
4
4
  "backstage": {
5
- "role": "node-library"
5
+ "role": "node-library",
6
+ "pluginId": "auth",
7
+ "pluginPackages": [
8
+ "@backstage/plugin-auth-backend",
9
+ "@backstage/plugin-auth-node",
10
+ "@backstage/plugin-auth-react"
11
+ ]
6
12
  },
7
13
  "publishConfig": {
8
14
  "access": "public",
@@ -31,8 +37,8 @@
31
37
  "test": "backstage-cli package test"
32
38
  },
33
39
  "dependencies": {
34
- "@backstage/backend-common": "^0.23.0-next.1",
35
- "@backstage/backend-plugin-api": "^0.6.19-next.1",
40
+ "@backstage/backend-common": "^0.23.0-next.3",
41
+ "@backstage/backend-plugin-api": "^0.6.19-next.3",
36
42
  "@backstage/catalog-client": "^1.6.5",
37
43
  "@backstage/catalog-model": "^1.5.0",
38
44
  "@backstage/config": "^1.2.0",
@@ -50,8 +56,8 @@
50
56
  "zod-to-json-schema": "^3.21.4"
51
57
  },
52
58
  "devDependencies": {
53
- "@backstage/backend-test-utils": "^0.4.0-next.1",
54
- "@backstage/cli": "^0.26.7-next.1",
59
+ "@backstage/backend-test-utils": "^0.4.0-next.3",
60
+ "@backstage/cli": "^0.26.7-next.3",
55
61
  "cookie-parser": "^1.4.6",
56
62
  "express-promise-router": "^4.1.1",
57
63
  "lodash": "^4.17.21",