From 0d0ed5fe54485fca32ea1f281d5fe6a0af259c0f Mon Sep 17 00:00:00 2001 From: Eugene Sh Date: Sat, 12 Jun 2021 01:55:19 +0300 Subject: [PATCH 1/3] slightly extend the documentation for enabling identityAPi Signed-off-by: Eugene S --- .../tutorials/authenticate-api-requests.md | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 7422fa03eced0..3b2a8f05d1f41 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 }), + }), + ], +}); +``` From 234a6453a93700b403fd8452f3ff77cf4166c628 Mon Sep 17 00:00:00 2001 From: Eugene Sh Date: Tue, 15 Jun 2021 17:49:06 +0300 Subject: [PATCH 2/3] switch from typescript to diff syntax now it's proper syntax, based on @OrkoHunter's suggestion. Signed-off-by: Eugene S --- contrib/docs/tutorials/authenticate-api-requests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 3b2a8f05d1f41..16b753bc84f21 100644 --- a/contrib/docs/tutorials/authenticate-api-requests.md +++ b/contrib/docs/tutorials/authenticate-api-requests.md @@ -186,7 +186,7 @@ const app = createApp({ 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 +```diff // plugins/internal-plugin/src/api.ts -- import {createApiRef} from '@backstage/core'; ++ import {createApiRef, IdentityApi} from '@backstage/core'; @@ -229,7 +229,7 @@ export class MyApi implements MyInterface { and -```typescript +```diff // plugins/internal-plugin/src/plugin.ts import { From 4a0cb1d8bc6ba6d8c2efeb833462665cad996b5d Mon Sep 17 00:00:00 2001 From: Eugene S Date: Sun, 20 Jun 2021 00:37:20 +0300 Subject: [PATCH 3/3] iron little things out :) Signed-off-by: Eugene S --- .../tutorials/authenticate-api-requests.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md index 16b753bc84f21..bc26a8c89ada2 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**: enabling this means the Backstage will stop working for guests, as no token is issued for them. +**NOTE**: Enabling this means that 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). @@ -182,20 +182,20 @@ const app = createApp({ // ... ``` -**NOTE**: most Backstage frontend plugins come with the support of the identityApi. +**NOTE**: Most Backstage frontend plugins come with the support for 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: ```diff // plugins/internal-plugin/src/api.ts --- import {createApiRef} from '@backstage/core'; -++ import {createApiRef, IdentityApi} from '@backstage/core'; +- import {createApiRef} from '@backstage/core'; ++ import {createApiRef, IdentityApi} from '@backstage/core'; import {Config} from '@backstage/config'; // ... type MyApiOptions = { configApi: Config; -++ identityApi: IdentityApi; ++ identityApi: IdentityApi; // ... } @@ -205,21 +205,21 @@ interface MyInterface { export class MyApi implements MyInterface { private configApi: Config; -++ private identityApi: IdentityApi; ++ private identityApi: IdentityApi; // ... constructor(options: MyApiOptions) { this.configApi = options.configApi; -++ this.identityApi = options.identityApi; ++ this.identityApi = options.identityApi; } async getMyData() { const backendUrl = this.configApi.getString('backend.baseUrl'); -++ const token = await this.identityApi.getIdToken(); ++ const token = await this.identityApi.getIdToken(); const requestUrl = `${backendUrl}/api/data/`; --- const response = await fetch(requestUrl); -++ const response = await fetch( +- const response = await fetch(requestUrl); ++ const response = await fetch( requestUrl, { headers: { Authorization: `Bearer ${token}` } }, ); @@ -236,7 +236,7 @@ import { configApiRef, createApiFactory, createPlugin, -++ identityApiRef, ++ identityApiRef, } from '@backstage/core'; import {mypluginPageRouteRef} from './routeRefs'; import {MyApi, myApiRef} from './api'; @@ -251,12 +251,12 @@ export const plugin = createPlugin({ api: myApiRef, deps: { configApi: configApiRef, -++ identityApi: identityApiRef, ++ identityApi: identityApiRef, }, --- factory: ({configApi}) => --- new MyApi({ configApi }), -++ factory: ({configApi, identityApi}) => -++ new MyApi({ configApi, identityApi }), +- factory: ({configApi}) => +- new MyApi({ configApi }), ++ factory: ({configApi, identityApi}) => ++ new MyApi({ configApi, identityApi }), }), ], });