@@ -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.
|
||||
|
||||
@@ -293,7 +293,7 @@ export type GithubProviderOptions = {
|
||||
signIn?: {
|
||||
resolver?: SignInResolver<GithubOAuthResult>;
|
||||
};
|
||||
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
|
||||
```
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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<GithubOAuthResult>;
|
||||
authHandler: AuthHandler<GithubOAuthResult>;
|
||||
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<RedirectInfo> {
|
||||
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,
|
||||
});
|
||||
|
||||
|
||||
@@ -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<AuthResult> = (
|
||||
input: AuthResult,
|
||||
) => Promise<AuthHandlerResult>;
|
||||
|
||||
export type StateHandler = (input: any) => Promise<string>;
|
||||
export type StateEncoder = (
|
||||
input: OAuthState,
|
||||
) => Promise<{ encodedState: string }>;
|
||||
|
||||
Reference in New Issue
Block a user