From bf93cfb343367455c95c030e4ffc409fa457fb13 Mon Sep 17 00:00:00 2001 From: Raghunandan Date: Thu, 18 Jun 2020 12:07:12 +0200 Subject: [PATCH] docs docs --- .../core-api/src/apis/definitions/auth.ts | 24 +- .../src/lib/PassportStrategyHelper.ts | 11 +- plugins/auth-backend/src/providers/types.ts | 214 +++++++++++++++--- 3 files changed, 212 insertions(+), 37 deletions(-) diff --git a/packages/core-api/src/apis/definitions/auth.ts b/packages/core-api/src/apis/definitions/auth.ts index 7abab45780..a9b82cefc7 100644 --- a/packages/core-api/src/apis/definitions/auth.ts +++ b/packages/core-api/src/apis/definitions/auth.ts @@ -157,25 +157,47 @@ export type ProfileInfoOptions = { optional?: boolean; }; +/** + * This API provides access to profile information of the signed in user. + */ export type ProfileInfoApi = { getProfile(options?: ProfileInfoOptions): Promise; }; +/** + * Profile information of a signed in user. + */ export type ProfileInfo = { - provider: string; + /** + * Email ID. + */ email: string; + /** + * Display name that can be presented to the user. + */ name?: string; + /** + * URL to an avatar image of the user. + */ picture?: string; }; +/** + * Session state values passed to subscribers of the SessionStateApi. + */ export enum SessionState { SignedIn = 'SignedIn', SignedOut = 'SignedOut', } +/** + * This API provides access to an sessionState$ observable which provides an update when the + * user performs a sign in or sign out from an auth provider. + */ export type SessionStateApi = { sessionState$(): Observable; }; + /** * Provides authentication towards Google APIs and identities. * diff --git a/plugins/auth-backend/src/lib/PassportStrategyHelper.ts b/plugins/auth-backend/src/lib/PassportStrategyHelper.ts index f9e32a2b6f..6fa65d01da 100644 --- a/plugins/auth-backend/src/lib/PassportStrategyHelper.ts +++ b/plugins/auth-backend/src/lib/PassportStrategyHelper.ts @@ -27,7 +27,7 @@ export const makeProfileInfo = ( profile: passport.Profile, params: any, ): ProfileInfo => { - const { provider, displayName: name } = profile; + const { displayName: name } = profile; let email = ''; if (profile.emails) { @@ -51,7 +51,6 @@ export const makeProfileInfo = ( } return { - provider, name, email, picture, @@ -100,12 +99,12 @@ export const executeFrameHandlerStrategy = async ( }; export const executeRefreshTokenStrategy = async ( - providerstrategy: passport.Strategy, + providerStrategy: passport.Strategy, refreshToken: string, scope: string, ): Promise => { return new Promise((resolve, reject) => { - const anyStrategy = providerstrategy as any; + const anyStrategy = providerStrategy as any; const OAuth2 = anyStrategy._oauth2.constructor; const oauth2 = new OAuth2( anyStrategy._oauth2._clientId, @@ -149,12 +148,12 @@ export const executeRefreshTokenStrategy = async ( }; export const executeFetchUserProfileStrategy = async ( - providerstrategy: passport.Strategy, + providerStrategy: passport.Strategy, accessToken: string, params: any, ): Promise => { return new Promise((resolve, reject) => { - const anyStrategy = providerstrategy as any; + const anyStrategy = providerStrategy as any; anyStrategy.userProfile( accessToken, (error: Error, passportProfile: passport.Profile) => { diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 419a041637..fa2ef7f49e 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -18,48 +18,160 @@ import express from 'express'; import { Logger } from 'winston'; export type OAuthProviderOptions = { + /** + * Client ID of the auth provider. + */ clientID: string; + /** + * Client Secret of the auth provider. + */ clientSecret: string; + /** + * Callback URL to be passed to the auth provider to redirect to after the user signs in. + */ callbackURL: string; }; -export type SAMLProviderConfig = { - entryPoint: string; - issuer: string; -}; - -export type EnvironmentProviderConfig = { - [key: string]: OAuthProviderConfig | SAMLProviderConfig; -}; - -export type AuthProviderConfig = { - baseUrl: string; -}; - export type OAuthProviderConfig = { + /** + * If the cookies set by the provider have to be marked secure. For development environment + * we don't mark the cookie as secure. + */ secure: boolean; - appOrigin: string; // http://localhost:3000 + /** + * The domain:port where the app (frontend) is hosted. This is used to post messages back + * to the window that initiates an auth request. + */ + appOrigin: string; + /** + * Client ID of the auth provider. + */ clientId: string; + /** + * Client Secret of the auth provider. + */ clientSecret: string; }; +export type EnvironmentProviderConfig = { + /** + * key, values are environment names and OAuthProviderConfigs + * + * For e.g + * { + * development: DevelopmentOAuthProviderConfig + * production: ProductionOAuthProviderConfig + * } + */ + [key: string]: OAuthProviderConfig; +}; + +export type AuthProviderConfig = { + /** + * The domain:port where the app is hosted. This is used to construct the + * callbackURL to redirect to once the user signs in to the auth provider. + */ + baseUrl: string; +}; + +/** + * Any OAuth provider needs to implement this interface which has provider specific + * handlers for different methods to perform authentication, get access tokens, + * refresh tokens and perform sign out. + */ export interface OAuthProviderHandlers { + /** + * This method initiates a sign in request with an auth provider. + * @param {express.Request} req + * @param options + */ start(req: express.Request, options: any): Promise; + + /** + * Handles the redirect from the auth provider when the user has signed in. + * @param {express.Request} req + */ handler(req: express.Request): Promise; + + /** + * (Optional) Given a refresh token and scope fetches a new access token from the auth provider. + * @param {string} refreshToken + * @param {string} scope + */ refresh?(refreshToken: string, scope: string): Promise; + + /** + * (Optional) Sign out of the auth provider. + */ logout?(): Promise; } +/** + * Any Auth provider needs to implement this interface which handles the routes in the + * auth backend. Any auth API requests from the frontend reaches these methods. + * + * The routes in the auth backend API are tied to these methods like below + * + * /auth/[provider]/start -> start + * /auth/[provider]/handler/frame -> frameHandler + * /auth/[provider]/refresh -> refresh + * /auth/[provider]/logout -> logout + */ export interface AuthProviderRouteHandlers { + /** + * Handles the start route of the API. This initiates a sign in request with an auth provider. + * + * Request + * - scopes for the auth request (Optional) + * Response + * - redirect to the auth provider for the user to sign in or consent. + * - sets a nonce cookie and also pass the nonce as 'state' query parameter in the redirect request + * + * @param {express.Request} req + * @param {express.Response} res + */ start(req: express.Request, res: express.Response): Promise; - frameHandler(req: express.Request, res: express.Response): Promise; - refresh?(req: express.Request, res: express.Response): Promise; - logout(req: express.Request, res: express.Response): Promise; -} -export type SAMLEnvironmentProviderConfig = { - [key: string]: SAMLProviderConfig; -}; + /** + * Once the user signs in or consents in the OAuth screen, the auth provider redirects to the + * callbackURL which is handled by this method. + * + * Request + * - to contain a nonce cookie and a 'state' query parameter + * Response + * - postMessage to the window with a payload that contains accessToken, expiryInSeconds?, idToken? and scope. + * - sets a refresh token cookie if the auth provider supports refresh tokens + * + * @param {express.Request} req + * @param {express.Response} res + */ + frameHandler(req: express.Request, res: express.Response): Promise; + + /** + * (Optional) If the auth provider supports refresh tokens then this method handles + * requests to get a new access token. + * + * Request + * - to contain a refresh token cookie and scope (Optional) query parameter. + * Response + * - payload with accessToken, expiryInSeconds?, idToken?, scope and user profile information. + * + * @param {express.Request} req + * @param {express.Response} res + */ + refresh?(req: express.Request, res: express.Response): Promise; + + /** + * (Optional) Handles logout requests + * + * Response + * - removes the refresh token cookie + * + * @param {express.Request} req + * @param {express.Response} res + */ + logout?(req: express.Request, res: express.Response): Promise; +} export type AuthProviderFactory = ( globalConfig: AuthProviderConfig, @@ -68,27 +180,42 @@ export type AuthProviderFactory = ( ) => AuthProviderRouteHandlers; export type AuthInfoBase = { + /** + * An access token issued for the signed in user. + */ accessToken: string; + /** + * (Optional) Id token issued for the signed in user. + */ idToken?: string; + /** + * Expiry of the access token in seconds. + */ expiresInSeconds?: number; + /** + * Scopes granted for the access token. + */ scope: string; }; export type AuthInfoWithProfile = AuthInfoBase & { - profile: - | { - provider: string; - email: string; - name?: string; - picture?: string; - } - | undefined; + /** + * Profile information of the signed in user. + */ + profile: ProfileInfo | undefined; }; export type AuthInfoPrivate = { + /** + * A refresh token issued for the signed in user. + */ refreshToken: string; }; +/** + * Payload sent as a post message after the auth request is complete. + * If successful then has a valid payload with Auth information else contains an error. + */ export type AuthResponse = | { type: 'auth-result'; @@ -100,18 +227,45 @@ export type AuthResponse = }; export type RedirectInfo = { + /** + * URL to redirect to + */ url: string; + /** + * Status code to use for the redirect + */ status?: number; }; export type ProfileInfo = { - provider: string; + /** + * Email ID of the signed in user. + */ email: string; + /** + * Display name that can be presented to the signed in user. + */ name: string; + /** + * URL to an image that can be used as the display image or avatar of the + * signed in user. + */ picture: string; }; export type RefreshTokenResponse = { + /** + * An access token issued for the signed in user. + */ accessToken: string; params: any; }; + +export type SAMLProviderConfig = { + entryPoint: string; + issuer: string; +}; + +export type SAMLEnvironmentProviderConfig = { + [key: string]: SAMLProviderConfig; +};