From 7714547af59367d96f96a5807d38bb65fae6207d Mon Sep 17 00:00:00 2001 From: Nicolas Arnold Date: Thu, 21 Oct 2021 10:27:19 +0100 Subject: [PATCH] Fixing types Signed-off-by: Nicolas Arnold --- .changeset/lucky-books-worry.md | 2 +- plugins/auth-backend/api-report.md | 13 +++++-- .../src/providers/github/provider.test.ts | 8 ++-- .../src/providers/github/provider.ts | 38 +++++++++++++------ plugins/auth-backend/src/providers/types.ts | 5 ++- 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/.changeset/lucky-books-worry.md b/.changeset/lucky-books-worry.md index f91dccb3f9..5645b4b4e9 100644 --- a/.changeset/lucky-books-worry.md +++ b/.changeset/lucky-books-worry.md @@ -2,4 +2,4 @@ '@backstage/plugin-auth-backend': patch --- -Allow extra field in OAuth state parameter +Allow OAuth state to be encoded by a stateEncoder. diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index d8275ef5d0..35c93e9537 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -293,7 +293,7 @@ export type GithubProviderOptions = { signIn?: { resolver?: SignInResolver; }; - stateHandler?: StateHandler; + stateEncoder?: StateEncoder; }; // Warning: (ae-missing-release-tag) "GitlabProviderOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -583,7 +583,12 @@ export type WebMessageResponse = // src/providers/atlassian/provider.d.ts:37:5 - (ae-forgotten-export) The symbol "AuthHandler" needs to be exported by the entry point index.d.ts // src/providers/atlassian/provider.d.ts:42:9 - (ae-forgotten-export) The symbol "SignInResolver" needs to be exported by the entry point index.d.ts // src/providers/aws-alb/provider.d.ts:77:5 - (ae-forgotten-export) The symbol "AwsAlbResult" needs to be exported by the entry point index.d.ts -// src/providers/github/provider.d.ts:65:5 - (ae-forgotten-export) The symbol "StateHandler" needs to be exported by the entry point index.d.ts -// src/providers/types.d.ts:99:5 - (ae-forgotten-export) The symbol "AuthProviderConfig" needs to be exported by the entry point index.d.ts -// src/providers/types.d.ts:121:8 - (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative +// src/providers/github/provider.d.ts:71:58 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// src/providers/github/provider.d.ts:71:90 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// src/providers/github/provider.d.ts:71:89 - (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// src/providers/github/provider.d.ts:71:67 - (tsdoc-malformed-html-name) Invalid HTML element: Expecting an HTML name +// src/providers/github/provider.d.ts:71:68 - (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// src/providers/github/provider.d.ts:78:5 - (ae-forgotten-export) The symbol "StateEncoder" needs to be exported by the entry point index.d.ts +// src/providers/types.d.ts:100:5 - (ae-forgotten-export) The symbol "AuthProviderConfig" needs to be exported by the entry point index.d.ts +// src/providers/types.d.ts:122:8 - (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative ``` diff --git a/plugins/auth-backend/src/providers/github/provider.test.ts b/plugins/auth-backend/src/providers/github/provider.test.ts index dd0910163f..44467ce66c 100644 --- a/plugins/auth-backend/src/providers/github/provider.test.ts +++ b/plugins/auth-backend/src/providers/github/provider.test.ts @@ -25,7 +25,7 @@ import { } from './provider'; import * as helpers from '../../lib/passport/PassportStrategyHelper'; import { makeProfileInfo } from '../../lib/passport/PassportStrategyHelper'; -import { OAuthStartRequest, encodeState } from '../../lib/oauth'; +import { OAuthState, encodeState } from '../../lib/oauth'; const mockFrameHandler = jest.spyOn( helpers, @@ -57,9 +57,9 @@ describe('GithubAuthProvider', () => { authHandler: async ({ fullProfile }) => ({ profile: makeProfileInfo(fullProfile), }), - stateHandler: async (req: OAuthStartRequest) => { - return encodeState(req.state); - }, + stateEncoder: async (state: OAuthState) => ({ + encodedState: encodeState(state), + }), callbackUrl: 'mock', clientId: 'mock', clientSecret: 'mock', diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 63d2cf79c9..ff718dde87 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -31,7 +31,7 @@ import { AuthProviderFactory, AuthHandler, SignInResolver, - StateHandler, + StateEncoder, } from '../types'; import { OAuthAdapter, @@ -42,6 +42,7 @@ import { encodeState, OAuthRefreshRequest, OAuthResponse, + OAuthState, } from '../../lib/oauth'; import { CatalogIdentityClient } from '../../lib/catalog'; import { TokenIssuer } from '../../identity'; @@ -67,7 +68,7 @@ export type GithubAuthProviderOptions = OAuthProviderOptions & { authorizationUrl?: string; signInResolver?: SignInResolver; authHandler: AuthHandler; - stateHandler: StateHandler; + stateEncoder: StateEncoder; tokenIssuer: TokenIssuer; catalogIdentityClient: CatalogIdentityClient; logger: Logger; @@ -80,12 +81,12 @@ export class GithubAuthProvider implements OAuthHandlers { private readonly tokenIssuer: TokenIssuer; private readonly catalogIdentityClient: CatalogIdentityClient; private readonly logger: Logger; - private readonly stateHandler: StateHandler; + private readonly stateEncoder: StateEncoder; constructor(options: GithubAuthProviderOptions) { this.signInResolver = options.signInResolver; this.authHandler = options.authHandler; - this.stateHandler = options.stateHandler; + this.stateEncoder = options.stateEncoder; this.tokenIssuer = options.tokenIssuer; this.catalogIdentityClient = options.catalogIdentityClient; this.logger = options.logger; @@ -113,7 +114,7 @@ export class GithubAuthProvider implements OAuthHandlers { async start(req: OAuthStartRequest): Promise { return await executeRedirectStrategy(req, this._strategy, { scope: req.scope, - state: await this.stateHandler(req.state), + state: await (await this.stateEncoder(req.state)).encodedState, }); } @@ -215,9 +216,22 @@ export type GithubProviderOptions = { }; /** - * The state handler that sets the uri query param 'state' + * The state encoder used to encode the 'state' parameter on the OAuth request. + * + * It should return a string that takes the state params (from the request), url encodes the params + * and finally base64 encodes them. + * + * Providing your own stateEncoder will allow you to add addition parameters to the state field. + * + * It is typed as follows: + * export type StateEncoder = (input: OAuthState) => Promise<{encodedState: string}>; + * + * Note: the stateEncoder must encode a 'nonce' value and an 'env' value. Without this, the OAuth flow will fail + * (These two values will be set by the req.state by default) + * + * For more information, please see the helper module in ../../oauth/helpers #readState */ - stateHandler?: StateHandler; + stateEncoder?: StateEncoder; }; export const createGithubProvider = ( @@ -272,10 +286,10 @@ export const createGithubProvider = ( logger, }); - const stateHandler: StateHandler = options?.stateHandler - ? options.stateHandler - : async (req: OAuthStartRequest) => { - return encodeState(req.state); + const stateEncoder: StateEncoder = options?.stateEncoder + ? options.stateEncoder + : async (state: OAuthState): Promise<{ encodedState: string }> => { + return { encodedState: encodeState(state) }; }; const provider = new GithubAuthProvider({ @@ -289,7 +303,7 @@ export const createGithubProvider = ( authHandler, tokenIssuer, catalogIdentityClient, - stateHandler, + stateEncoder, logger, }); diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 83e6e0bcb6..09e1935f3e 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -21,6 +21,7 @@ import { Config } from '@backstage/config'; import express from 'express'; import { Logger } from 'winston'; import { TokenIssuer } from '../identity/types'; +import { OAuthState } from '../lib/oauth/types'; import { CatalogIdentityClient } from '../lib/catalog'; export type AuthProviderConfig = { @@ -224,4 +225,6 @@ export type AuthHandler = ( input: AuthResult, ) => Promise; -export type StateHandler = (input: any) => Promise; +export type StateEncoder = ( + input: OAuthState, +) => Promise<{ encodedState: string }>;