Merge pull request #8425 from nodify-at/master

export typescript types for OIDC provider
This commit is contained in:
Ben Lambert
2021-12-13 13:30:57 +01:00
committed by GitHub
6 changed files with 105 additions and 30 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
export minimal typescript types for OIDC provider
+40 -3
View File
@@ -47,6 +47,16 @@ export type AtlassianProviderOptions = {
};
};
// @public
export type AuthHandler<AuthResult> = (
input: AuthResult,
) => Promise<AuthHandlerResult>;
// @public
export type AuthHandlerResult = {
profile: ProfileInfo;
};
// Warning: (ae-missing-release-tag) "AuthProviderFactory" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -258,7 +268,6 @@ export const createOAuth2Provider: (
options?: OAuth2ProviderOptions | undefined,
) => AuthProviderFactory;
// Warning: (ae-forgotten-export) The symbol "OidcProviderOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "createOidcProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -534,6 +543,20 @@ export type OAuthState = {
origin?: string;
};
// @public
export type OidcAuthResult = {
tokenset: TokenSet;
userinfo: UserinfoResponse;
};
// @public
export type OidcProviderOptions = {
authHandler?: AuthHandler<OidcAuthResult>;
signIn?: {
resolver?: SignInResolver<OidcAuthResult>;
};
};
// Warning: (ae-missing-release-tag) "oktaEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -606,6 +629,22 @@ export type SamlProviderOptions = {
};
};
// @public
export type SignInInfo<AuthResult> = {
profile: ProfileInfo;
result: AuthResult;
};
// @public
export type SignInResolver<AuthResult> = (
info: SignInInfo<AuthResult>,
context: {
tokenIssuer: TokenIssuer;
catalogIdentityClient: CatalogIdentityClient;
logger: Logger_2;
},
) => Promise<BackstageSignInResult>;
// Warning: (ae-missing-release-tag) "TokenIssuer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
@@ -637,8 +676,6 @@ export type WebMessageResponse =
// Warnings were encountered during analysis:
//
// src/identity/types.d.ts:31:9 - (ae-forgotten-export) The symbol "AnyJWK" needs to be exported by the entry point index.d.ts
// 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: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
@@ -34,6 +34,10 @@ export type {
AuthProviderRouteHandlers,
AuthProviderFactoryOptions,
AuthProviderFactory,
AuthHandler,
AuthHandlerResult,
SignInResolver,
SignInInfo,
} from './types';
// These types are needed for a postMessage from the login pop-up
@@ -13,5 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export type { OidcAuthResult, OidcProviderOptions } from './provider';
export { createOidcProvider } from './provider';
@@ -56,7 +56,11 @@ type OidcImpl = {
client: Client;
};
type AuthResult = {
/**
* authentication result for the OIDC which includes the token set and user information (a profile response sent by OIDC server)
* @public
*/
export type OidcAuthResult = {
tokenset: TokenSet;
userinfo: UserinfoResponse;
};
@@ -66,8 +70,8 @@ export type Options = OAuthProviderOptions & {
scope?: string;
prompt?: string;
tokenSignedResponseAlg?: string;
signInResolver?: SignInResolver<AuthResult>;
authHandler: AuthHandler<AuthResult>;
signInResolver?: SignInResolver<OidcAuthResult>;
authHandler: AuthHandler<OidcAuthResult>;
tokenIssuer: TokenIssuer;
catalogIdentityClient: CatalogIdentityClient;
logger: Logger;
@@ -78,8 +82,8 @@ export class OidcAuthProvider implements OAuthHandlers {
private readonly scope?: string;
private readonly prompt?: string;
private readonly signInResolver?: SignInResolver<AuthResult>;
private readonly authHandler: AuthHandler<AuthResult>;
private readonly signInResolver?: SignInResolver<OidcAuthResult>;
private readonly authHandler: AuthHandler<OidcAuthResult>;
private readonly tokenIssuer: TokenIssuer;
private readonly catalogIdentityClient: CatalogIdentityClient;
private readonly logger: Logger;
@@ -113,7 +117,7 @@ export class OidcAuthProvider implements OAuthHandlers {
): Promise<{ response: OAuthResponse; refreshToken?: string }> {
const { strategy } = await this.implementation;
const strategyResponse = await executeFrameHandlerStrategy<
AuthResult,
OidcAuthResult,
PrivateInfo
>(req, strategy);
const {
@@ -158,7 +162,7 @@ export class OidcAuthProvider implements OAuthHandlers {
(
tokenset: TokenSet,
userinfo: UserinfoResponse,
done: PassportDoneCallback<AuthResult, PrivateInfo>,
done: PassportDoneCallback<OidcAuthResult, PrivateInfo>,
) => {
if (typeof done !== 'function') {
throw new Error(
@@ -180,7 +184,7 @@ export class OidcAuthProvider implements OAuthHandlers {
// Use this function to grab the user profile info from the token
// Then populate the profile with it
private async handleResult(result: AuthResult): Promise<OAuthResponse> {
private async handleResult(result: OidcAuthResult): Promise<OAuthResponse> {
const { profile } = await this.authHandler(result);
const response: OAuthResponse = {
providerInfo: {
@@ -210,27 +214,37 @@ export class OidcAuthProvider implements OAuthHandlers {
}
}
export const oAuth2DefaultSignInResolver: SignInResolver<AuthResult> = async (
info,
ctx,
) => {
const { profile } = info;
export const oAuth2DefaultSignInResolver: SignInResolver<OidcAuthResult> =
async (info, ctx) => {
const { profile } = info;
if (!profile.email) {
throw new Error('Profile contained no email');
}
const userId = profile.email.split('@')[0];
const token = await ctx.tokenIssuer.issueToken({
claims: { sub: userId, ent: [`user:default/${userId}`] },
});
return { id: userId, token };
};
if (!profile.email) {
throw new Error('Profile contained no email');
}
const userId = profile.email.split('@')[0];
const token = await ctx.tokenIssuer.issueToken({
claims: { sub: userId, ent: [`user:default/${userId}`] },
});
return { id: userId, token };
};
/**
* OIDC provider callback options. An auth handler and a sign in resolver
* can be passed while creating a OIDC provider.
*
* authHandler : called after sign in was successful, a new object must be returned which includes a profile
* signInResolver: called after sign in was successful, expects to return a new {@link BackstageSignInResult}
*
* Both options are optional. There is fallback for authHandler where the default handler expect an e-mail explicitly
* otherwise it throws an error
*
* @public
*/
export type OidcProviderOptions = {
authHandler?: AuthHandler<AuthResult>;
authHandler?: AuthHandler<OidcAuthResult>;
signIn?: {
resolver?: SignInResolver<AuthResult>;
resolver?: SignInResolver<OidcAuthResult>;
};
};
@@ -260,7 +274,7 @@ export const createOidcProvider = (
tokenIssuer,
});
const authHandler: AuthHandler<AuthResult> = options?.authHandler
const authHandler: AuthHandler<OidcAuthResult> = options?.authHandler
? options.authHandler
: async ({ userinfo }) => ({
profile: {
@@ -271,7 +285,7 @@ export const createOidcProvider = (
});
const signInResolverFn =
options?.signIn?.resolver ?? oAuth2DefaultSignInResolver;
const signInResolver: SignInResolver<AuthResult> = info =>
const signInResolver: SignInResolver<OidcAuthResult> = info =>
signInResolverFn(info, {
catalogIdentityClient,
tokenIssuer,
@@ -240,6 +240,10 @@ export type ProfileInfo = {
picture?: string;
};
/**
* type of sign in information context, includes the profile information and authentication result which contains auth. related information
* @public
*/
export type SignInInfo<AuthResult> = {
/**
* The simple profile passed down for use in the frontend.
@@ -252,6 +256,11 @@ export type SignInInfo<AuthResult> = {
result: AuthResult;
};
/**
* Sign in resolver type describes the function which handles the result of a successful authentication
* and it must return a valid {@link BackstageSignInResult}
* @public
*/
export type SignInResolver<AuthResult> = (
info: SignInInfo<AuthResult>,
context: {
@@ -261,6 +270,10 @@ export type SignInResolver<AuthResult> = (
},
) => Promise<BackstageSignInResult>;
/**
* The return type of authentication handler which must contain a valid profile information
* @public
*/
export type AuthHandlerResult = { profile: ProfileInfo };
/**
@@ -270,6 +283,8 @@ export type AuthHandlerResult = { profile: ProfileInfo };
*
* Throwing an error in the function will cause the authentication to fail, making it
* possible to use this function as a way to limit access to a certain group of users.
*
* @public
*/
export type AuthHandler<AuthResult> = (
input: AuthResult,