From 062eaf3f75085511a641028f05329eadd40a2d45 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Fri, 22 Nov 2024 10:02:54 +0100 Subject: [PATCH] chore: Add documentation Signed-off-by: Johan Haals --- docs/auth/service-to-service-auth.md | 45 +++++++++++++++++++ .../auth/authServiceFactory.test.ts | 1 - .../auth/plugin/PluginTokenHandler.ts | 7 +-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/docs/auth/service-to-service-auth.md b/docs/auth/service-to-service-auth.md index 13516a1117..fddfe89c9a 100644 --- a/docs/auth/service-to-service-auth.md +++ b/docs/auth/service-to-service-auth.md @@ -412,3 +412,48 @@ Each entry has one or more of the following fields: # Also supports the shorthand form: # action: create, read ``` + +## Adding custom or logic for validation and issuing of tokens + +The `pluginTokenHandlerDecoratorServiceRef` can be used to decorate the existing token handler without having to re-implement the entire `PluginTokenHandler`. +This is particularly useful when you want to add additional logic to the handler, such as logging or metrics or custom token validation. + +The `PluginTokenHandler` interface has two methods: + +- `issueToken`: This method is used to issue a token for a plugin. It takes in the `pluginId` and `targetPluginId` as arguments, and an optional `limitedUserToken` object which can be used to issue a token on behalf of another user. The method returns a promise that resolves to an object containing the issued token. + +- `verifyToken`: This method is used to verify a token. It takes in the token as an argument and returns a promise that resolves to an object containing the subject of the token and an optional limited user token. + +```ts +import { + PluginTokenHandler, + pluginTokenHandlerDecoratorServiceRef, +} from '@backstage/backend-defaults/auth'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; + +const decoratedPluginTokenHandler = createServiceFactory({ + service: pluginTokenHandlerDecoratorServiceRef, + deps: {}, + async factory() { + return (defaultImplementation: PluginTokenHandler) => + new (class CustomHandler implements PluginTokenHandler { + verifyToken( + token: string, + ): Promise<{ subject: string; limitedUserToken?: string } | undefined> { + // custom logic here + if (isMyCustomToken(token)) { + return { subject: 'custom-subject' }; + } + return defaultImplementation.verifyToken(token); + } + issueToken(options: { + pluginId: string; + targetPluginId: string; + limitedUserToken?: { token: string; expiresAt: Date }; + }): Promise<{ token: string }> { + return defaultImplementation.issueToken(options); + } + })(); + }, +}); +``` diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index 6f0578e99e..38b8862a4c 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -428,7 +428,6 @@ describe('authServiceFactory', () => { { subject: string; limitedUserToken?: string } | undefined > { customLogic(token); - // check if token is iam/auth or basicAuth, verify. return defaultImplementation.verifyToken(token); } issueToken(options: { diff --git a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts index 22331930aa..281dca6d9e 100644 --- a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts +++ b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts @@ -16,7 +16,7 @@ import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api'; import { decodeJwt, importJWK, SignJWT, decodeProtectedHeader } from 'jose'; -import { AuthenticationError } from '@backstage/errors'; +import { assertError, AuthenticationError } from '@backstage/errors'; import { jwtVerify } from 'jose'; import { tokenTypes } from '@backstage/plugin-auth-node'; import { JwksClient } from '../JwksClient'; @@ -46,7 +46,7 @@ type Options = { /** * @public - * Issues and verifies {@link https://backstage.io/docs/auth/service-to-service-auth | service-to-service tokens}. + * Issues and verifies {@link https://backstage.iceio/docs/auth/service-to-service-auth | service-to-service tokens}. */ export interface PluginTokenHandler { verifyToken( @@ -194,7 +194,8 @@ export class DefaultPluginTokenHandler implements PluginTokenHandler { this.supportedTargetPlugins.add(targetPluginId); return true; - } catch (error: any) { + } catch (error) { + assertError(error); this.logger.error('Unexpected failure for target JWKS check', error); return false; } finally {