diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 7422fa03ec..3b2a8f05d1 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -4,7 +4,7 @@ The Backstage backend APIs are by default available without authentication. To a API requests from frontend plugins include an authorization header with a Backstage identity token acquired when the user logs in. By adding a middleware that verifies said token to be valid and signed by Backstage, non-authenticated requests can be blocked with a 401 Unauthorized response. -Note that this means Backstage will stop working for guests, as no token is issued for them. +**NOTE**: enabling this means the Backstage will stop working for guests, as no token is issued for them. As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire). @@ -181,3 +181,83 @@ const app = createApp({ // ... ``` + +**NOTE**: most Backstage frontend plugins come with the support of the identityApi. +In case you already have a dozen of internal ones, you may need to update those too. +Assuming you follow the common plugin structure, the changes to your front-end may look like: + +```typescript +// plugins/internal-plugin/src/api.ts +-- import {createApiRef} from '@backstage/core'; +++ import {createApiRef, IdentityApi} from '@backstage/core'; +import {Config} from '@backstage/config'; +// ... + +type MyApiOptions = { + configApi: Config; +++ identityApi: IdentityApi; + // ... +} + +interface MyInterface { + getData(): Promise; +} + +export class MyApi implements MyInterface { + private configApi: Config; +++ private identityApi: IdentityApi; + // ... + + constructor(options: MyApiOptions) { + this.configApi = options.configApi; +++ this.identityApi = options.identityApi; + } + + async getMyData() { + const backendUrl = this.configApi.getString('backend.baseUrl'); + +++ const token = await this.identityApi.getIdToken(); + const requestUrl = `${backendUrl}/api/data/`; +-- const response = await fetch(requestUrl); +++ const response = await fetch( + requestUrl, + { headers: { Authorization: `Bearer ${token}` } }, + ); + // ... + } +``` + +and + +```typescript +// plugins/internal-plugin/src/plugin.ts + +import { + configApiRef, + createApiFactory, + createPlugin, +++ identityApiRef, +} from '@backstage/core'; +import {mypluginPageRouteRef} from './routeRefs'; +import {MyApi, myApiRef} from './api'; + +export const plugin = createPlugin({ + id: 'my-plugin', + routes: { + mainPage: mypluginPageRouteRef, + }, + apis: [ + createApiFactory({ + api: myApiRef, + deps: { + configApi: configApiRef, +++ identityApi: identityApiRef, + }, +-- factory: ({configApi}) => +-- new MyApi({ configApi }), +++ factory: ({configApi, identityApi}) => +++ new MyApi({ configApi, identityApi }), + }), + ], +}); +```