UNPKG

@zeushq/nextjs-zidentity

Version:

Next.js SDK for signin in with Zeus Identity

134 lines (126 loc) 3.76 kB
import { strict as assert } from 'assert'; import { NextApiResponse, NextApiRequest } from 'next'; import { HandleCallback as BaseHandleCallback } from '../zsession'; import { Session } from '../session'; import { assertReqRes } from '../utils/assert'; import { NextConfig } from '../config'; import { HandlerError } from '../utils/errors'; /** * Use this function for validating additional claims on the user's ID Token or adding removing items from * the session after login, eg * * ### Validate additional claims * * ```js * // pages/api/auth/[...zidentity].js * import { handleAuth, handleCallback } from '@zeushq/nextjs-zidentity'; * * const afterCallback = (req, res, session, state) => { * if (!session.user.isAdmin) { * throw new UnauthorizedError('User is not admin'); * } * return session; * }; * * export default handleAuth({ * async callback(req, res) { * try { * await handleCallback(req, res, { afterCallback }); * } catch (error) { * res.status(error.status || 500).end(error.message); * } * } * }); * ``` * * ### Modify the session after login * * ```js * // pages/api/auth/[...zidentity].js * import { handleAuth, handleCallback } from '@zeushq/nextjs-zidentity'; * * const afterCallback = (req, res, session, state) => { * session.user.customProperty = 'foo'; * delete session.refreshToken; * return session; * }; * * export default handleAuth({ * async callback(req, res) { * try { * await handleCallback(req, res, { afterCallback }); * } catch (error) { * res.status(error.status || 500).end(error.message); * } * } * }); * ``` * * @category Server */ export type AfterCallback = ( req: NextApiRequest, res: NextApiResponse, session: Session, state: { [key: string]: any } ) => Promise<Session> | Session; /** * Options to customize the callback handler. * * @category Server */ export interface CallbackOptions { afterCallback?: AfterCallback; /** * This is useful to specify in addition to {@Link BaseConfig.baseURL} when your app runs on multiple domains, * it should match {@Link LoginOptions.authorizationParams.redirect_uri}. */ redirectUri?: string; /** * This is useful to specify instead of {@Link NextConfig.organization} when your app has multiple * organizations, it should match {@Link LoginOptions.authorizationParams}. */ organization?: string; } /** * The handler for the `api/auth/callback` route. * * @category Server */ export type HandleCallback = (req: NextApiRequest, res: NextApiResponse, options?: CallbackOptions) => Promise<void>; /** * @ignore */ const idTokenValidator = (afterCallback?: AfterCallback, organization?: string): AfterCallback => (req, res, session, state) => { if (organization) { assert(session.user.org_id, 'Organization Id (org_id) claim must be a string present in the ID token'); assert.equal( session.user.org_id, organization, `Organization Id (org_id) claim value mismatch in the ID token; ` + `expected "${organization}", found "${session.user.org_id}"` ); } if (afterCallback) { return afterCallback(req, res, session, state); } return session; }; /** * @ignore */ export default function handleCallbackFactory(handler: BaseHandleCallback, config: NextConfig): HandleCallback { return async (req, res, options = {}): Promise<void> => { try { assertReqRes(req, res); return await handler(req, res, { ...options, afterCallback: idTokenValidator(options.afterCallback, options.organization || config.organization) }); } catch (e: any) { throw new HandlerError(e); } }; }