diff --git a/.changeset/short-turtles-dream.md b/.changeset/short-turtles-dream.md new file mode 100644 index 0000000000..022ef35f58 --- /dev/null +++ b/.changeset/short-turtles-dream.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow-backend': patch +--- + +Added option to supply API Access Token. This is required in addition to an API key when trying to access the data for a private Stack Overflow Team. diff --git a/plugins/stack-overflow-backend/README.md b/plugins/stack-overflow-backend/README.md index a35a6678cb..4bcc755404 100644 --- a/plugins/stack-overflow-backend/README.md +++ b/plugins/stack-overflow-backend/README.md @@ -15,14 +15,17 @@ stackoverflow: baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance ``` -### Stack Overflow for Teams (private stack overflow instance) +### Stack Overflow for Teams -If you have a private stack overflow instance you will need to supply an API key as well. You can read more about how to set this up by going to [Stack Overflows Help Page](https://stackoverflow.help/en/articles/4385859-stack-overflow-for-teams-api) +If you have a private Stack Overflow instance and/or a private Stack Overflow Team you will need to supply an API key. You can read more about how to set this up by going to [Stack Overflow's Help Page](https://stackoverflow.help/en/articles/4385859-stack-overflow-for-teams-api). + +A private Stack Overflow Team requires both an API key and an API Access Token. Step 3 ("Generate an Access Token via OAuth") from the previously mentioned Help Page explains the process for generating an API Access Token with no expiration. ```yaml stackoverflow: baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance apiKey: $STACK_OVERFLOW_API_KEY + apiAccessToken: $STACK_OVERFLOW_API_ACCESS_TOKEN ``` ## Areas of Responsibility diff --git a/plugins/stack-overflow-backend/api-report.md b/plugins/stack-overflow-backend/api-report.md index 11bfbaadc9..f6c7530de9 100644 --- a/plugins/stack-overflow-backend/api-report.md +++ b/plugins/stack-overflow-backend/api-report.md @@ -43,6 +43,7 @@ export type StackOverflowQuestionsCollatorFactoryOptions = { baseUrl?: string; maxPage?: number; apiKey?: string; + apiAccessToken?: string; requestParams: StackOverflowQuestionsRequestParams; logger: Logger; }; diff --git a/plugins/stack-overflow-backend/config.d.ts b/plugins/stack-overflow-backend/config.d.ts index 617524f0a3..54e517c5d8 100644 --- a/plugins/stack-overflow-backend/config.d.ts +++ b/plugins/stack-overflow-backend/config.d.ts @@ -25,9 +25,15 @@ export interface Config { baseUrl?: string; /** - * The api key to authenticate to Stack Overflow API + * The API key to authenticate to Stack Overflow API * @visibility secret */ apiKey?: string; + + /** + * The API Access Token to authenticate to Stack Overflow API + * @visibility secret + */ + apiAccessToken?: string; }; } diff --git a/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts b/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts index 1aa0e5d300..ebbad99d0a 100644 --- a/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts +++ b/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts @@ -52,6 +52,7 @@ export type StackOverflowQuestionsCollatorFactoryOptions = { baseUrl?: string; maxPage?: number; apiKey?: string; + apiAccessToken?: string; requestParams: StackOverflowQuestionsRequestParams; logger: Logger; }; @@ -67,6 +68,7 @@ export class StackOverflowQuestionsCollatorFactory protected requestParams: StackOverflowQuestionsRequestParams; private readonly baseUrl: string | undefined; private readonly apiKey: string | undefined; + private readonly apiAccessToken: string | undefined; private readonly maxPage: number | undefined; private readonly logger: Logger; public readonly type: string = 'stack-overflow'; @@ -74,6 +76,7 @@ export class StackOverflowQuestionsCollatorFactory private constructor(options: StackOverflowQuestionsCollatorFactoryOptions) { this.baseUrl = options.baseUrl; this.apiKey = options.apiKey; + this.apiAccessToken = options.apiAccessToken; this.maxPage = options.maxPage; this.requestParams = options.requestParams; this.logger = options.logger.child({ documentType: this.type }); @@ -84,6 +87,9 @@ export class StackOverflowQuestionsCollatorFactory options: StackOverflowQuestionsCollatorFactoryOptions, ) { const apiKey = config.getOptionalString('stackoverflow.apiKey'); + const apiAccessToken = config.getOptionalString( + 'stackoverflow.apiAccessToken', + ); const baseUrl = config.getOptionalString('stackoverflow.baseUrl') || 'https://api.stackexchange.com/2.2'; @@ -93,6 +99,7 @@ export class StackOverflowQuestionsCollatorFactory baseUrl, maxPage, apiKey, + apiAccessToken, }); } @@ -138,6 +145,13 @@ export class StackOverflowQuestionsCollatorFactory } const res = await fetch( `${this.baseUrl}/questions${params}${apiKeyParam}&page=${page}`, + this.apiAccessToken + ? { + headers: { + 'X-API-Access-Token': this.apiAccessToken, + }, + } + : undefined, ); const data = await res.json();