diff --git a/.changeset/lovely-impalas-sell.md b/.changeset/lovely-impalas-sell.md new file mode 100644 index 0000000000..80447c066f --- /dev/null +++ b/.changeset/lovely-impalas-sell.md @@ -0,0 +1,16 @@ +--- +'@backstage/plugin-search-backend-module-explore': patch +--- + +Allows for an optional `tokenManager` to authenticate requests from the collator to the explore backend. For example: + +```diff + indexBuilder.addCollator({ + schedule: every10MinutesSchedule, + factory: ToolDocumentCollatorFactory.fromConfig(env.config, { + discovery: env.discovery, + logger: env.logger, + + tokenManager: env.tokenManager, + }), + }); +``` diff --git a/plugins/search-backend-module-explore/README.md b/plugins/search-backend-module-explore/README.md index a87f2d78f9..e775cf42b6 100644 --- a/plugins/search-backend-module-explore/README.md +++ b/plugins/search-backend-module-explore/README.md @@ -39,3 +39,18 @@ backend.add(searchPlugin()); backend.add(searchModuleExploreCollator({ schedule })); backend.start(); ``` + +### Using Auth Middleware + +If your Backstage instance uses service-to-service authentication you can pass an optional `tokenManager` to the collator factory. This will ensure that the collator makes authenticated requests to the explore backend. + +```tsx +indexBuilder.addCollator({ + schedule: every10MinutesSchedule, + factory: ToolDocumentCollatorFactory.fromConfig(env.config, { + discovery: env.discovery, + logger: env.logger, + tokenManager: env.tokenManager, + }), +}); +``` diff --git a/plugins/search-backend-module-explore/api-report.md b/plugins/search-backend-module-explore/api-report.md index 80e8c0c06b..50cda184a9 100644 --- a/plugins/search-backend-module-explore/api-report.md +++ b/plugins/search-backend-module-explore/api-report.md @@ -12,6 +12,7 @@ import { IndexableDocument } from '@backstage/plugin-search-common'; import { Logger } from 'winston'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { Readable } from 'stream'; +import { TokenManager } from '@backstage/backend-common'; // @public export interface ToolDocument extends IndexableDocument, ExploreTool {} @@ -35,5 +36,6 @@ export class ToolDocumentCollatorFactory implements DocumentCollatorFactory { export type ToolDocumentCollatorFactoryOptions = { discovery: PluginEndpointDiscovery; logger: Logger; + tokenManager?: TokenManager; }; ``` diff --git a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts index dd9872acec..bf6f07839b 100644 --- a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts +++ b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { + PluginEndpointDiscovery, + TokenManager, +} from '@backstage/backend-common'; import { Config } from '@backstage/config'; import { ExploreTool } from '@backstage/plugin-explore-common'; import { @@ -40,6 +43,7 @@ export interface ToolDocument extends IndexableDocument, ExploreTool {} export type ToolDocumentCollatorFactoryOptions = { discovery: PluginEndpointDiscovery; logger: Logger; + tokenManager?: TokenManager; }; /** @@ -52,10 +56,12 @@ export class ToolDocumentCollatorFactory implements DocumentCollatorFactory { private readonly discovery: PluginEndpointDiscovery; private readonly logger: Logger; + private readonly tokenManager?: TokenManager; private constructor(options: ToolDocumentCollatorFactoryOptions) { this.discovery = options.discovery; this.logger = options.logger; + this.tokenManager = options.tokenManager; } static fromConfig( @@ -87,7 +93,17 @@ export class ToolDocumentCollatorFactory implements DocumentCollatorFactory { private async fetchTools() { const baseUrl = await this.discovery.getBaseUrl('explore'); - const response = await fetch(`${baseUrl}/tools`); + + let headers = {}; + + if (this.tokenManager) { + const { token } = await this.tokenManager.getToken(); + headers = { + Authorization: `Bearer ${token}`, + }; + } + + const response = await fetch(`${baseUrl}/tools`, headers); if (!response.ok) { throw new Error(