UNPKG

@youngshand/payload-auth-plugin

Version:

A temporary fork for testing of Authentication plugin for Payload CMS, use @payload-auth-plugin

233 lines (209 loc) 5.67 kB
/** * The App plugin is used for authenticating users in the frontent app of the Payload CMS application. * It support magic link, password, OAuth, and Passkey based authentications. * * On top of it, to add additional security it also support 2FA using OTP, and TOTP. * * The set up is very lean and flexible to tailor the auth process in a specific way. * * ```ts * import {appAuthPlugin} from "payload-auth-plugin"; * * // TODO: Need complete implementation * * ``` * @packageDocumentation */ import { Config, Endpoint, PayloadRequest, Plugin } from "payload" import { AccountInfo, AuthenticationStrategy, PasswordProviderConfig, OAuthProviderConfig, PasskeyProviderConfig, } from "../types.js" import { InvalidServerURL, MissingEmailAdapter, } from "../core/errors/consoleErrors.js" import { getPasswordProvider, getOAuthProviders, getPasskeyProvider, } from "../providers/utils.js" import { PasswordAuthEndpointStrategy, EndpointsFactory, OAuthEndpointStrategy, PasskeyEndpointStrategy, SessionEndpointStrategy, } from "../core/endpoints.js" import { AppSession } from "../core/session/app.js" import { formatSlug } from "../core/utils/slug.js" import { preflightCollectionCheck } from "../core/preflights/collections.js" /** * The App plugin to set up authentication to the intengrated frontend of Payload CMS. * * Add the plugin to your Payload project plugins. * */ interface PluginOptions { /** * Enable or disable plugin * * @default true * */ enabled?: boolean | undefined /** * Unique name for your frontend app. * * This name will be used to created endpoints, tokens, and etc. */ name: string /** * Auth providers supported by the plugin * */ providers: ( | OAuthProviderConfig | PasskeyProviderConfig | PasswordProviderConfig )[] /** * @description * App users collection slug. * * This collection will be used to store all the app user records. * */ usersCollectionSlug: string /** * App user accounts collection slug. * * This collection will be used to store all the app user account records. * Multiple accounts can belong to one user * */ accountsCollectionSlug: string /** * Allow auto signup if user doesn't have an account. * * @default false * */ allowAutoSignUp?: boolean | undefined /** * Authentication strategies can be either JWT or Cookie based * * @default Cookie * */ authenticationStrategy?: AuthenticationStrategy /** * Secret to use for JWT signing and decryption */ secret: string } /** * App plugin funtion. * * @param {PluginOptions} pluginOptions * @returns {Plugin} */ export const appAuthPlugin = (pluginOptions: PluginOptions): Plugin => (incomingConfig: Config): Config => { const config = { ...incomingConfig } if (pluginOptions.enabled === false) { return config } if (!config.serverURL) { throw new InvalidServerURL() } const { usersCollectionSlug, accountsCollectionSlug, providers, allowAutoSignUp, authenticationStrategy, secret, } = pluginOptions preflightCollectionCheck( [usersCollectionSlug, accountsCollectionSlug], config.collections, ) const name = formatSlug(pluginOptions.name) const oauthProviders = getOAuthProviders(providers) const passkeyProvider = getPasskeyProvider(providers) const passwordProvider = getPasswordProvider(providers) const session = new AppSession( name, { usersCollection: usersCollectionSlug, accountsCollection: accountsCollectionSlug, }, allowAutoSignUp ?? false, authenticationStrategy ?? "Cookie", secret, ) const endpointsFactory = new EndpointsFactory(name) let oauthEndpoints: Endpoint[] = [] let passkeyEndpoints: Endpoint[] = [] let passwordEndpoints: Endpoint[] = [] if (Object.keys(oauthProviders).length > 0) { endpointsFactory.registerStrategy( "oauth", new OAuthEndpointStrategy(oauthProviders), ) oauthEndpoints = endpointsFactory.createEndpoints("oauth", { sessionCallback: ( oauthAccountInfo: AccountInfo, scope: string, issuerName: string, request: PayloadRequest, clientOrigin: string, ) => session.oauthSessionCallback( oauthAccountInfo, scope, issuerName, request, clientOrigin, ), }) } if (passkeyProvider) { endpointsFactory.registerStrategy( "passkey", new PasskeyEndpointStrategy(), ) passkeyEndpoints = endpointsFactory.createEndpoints("passkey") } if (passwordProvider) { if (!!!config.email) { throw new MissingEmailAdapter() } endpointsFactory.registerStrategy( "password", new PasswordAuthEndpointStrategy({ usersCollectionSlug }, secret), ) passwordEndpoints = endpointsFactory.createEndpoints("password", { sessionCallback: (user: { id: string; email: string }) => session.passwordSessionCallback(user), }) } endpointsFactory.registerStrategy( "session", new SessionEndpointStrategy(secret, { usersCollectionSlug }), ) const sessionEndpoints = endpointsFactory.createEndpoints("session") config.endpoints = [ ...(config.endpoints ?? []), ...oauthEndpoints, ...passkeyEndpoints, ...passwordEndpoints, ...sessionEndpoints, ] return config }