import * as Hapi from "@hapi/hapi"; import * as Hoek from "@hapi/hoek"; import Joi from "joi"; import { NextAuthPluginOptions } from "./types.js"; import * as Routes from "./routes.js"; const minimumProfileSchema = Joi.object() .keys({ email: Joi.string().email().required(), }) .unknown(true); const minimumUserSchema = Joi.object() .keys({ userId: Joi.string().required(), email: Joi.string().email().required(), }) .unknown(true); const minimumSessionSchema = Joi.object() .keys({ id: Joi.string().required(), userId: Joi.string().required(), expires: Joi.number().required(), sessionToken: Joi.string().required(), accessToken: Joi.string().required(), }) .unknown(true); const defaultOptions = { basePath: "/api/nextauth", validators: { userId: Joi.string().required(), profile: minimumProfileSchema, user: minimumUserSchema, session: minimumSessionSchema, }, tags: [], }; const validateAuth = (sharedSecret) => (request, username, password) => { // we follow stripe's lead here for authenticating with basic auth // the shared secret should be bassed as the basic auth username, the password should be empty if (password !== "") { console.error( "hapi-nextauth: attempted authentication with basic auth password. only the username should be defined." ); return { isValid: false, credentials: {} }; } const isValid = username === sharedSecret; const credentials = { id: "nextauth-frontend", }; return { isValid, credentials }; }; const register = async ( server: Hapi.Server, pluginOpts?: any ): Promise => { const options: any = Hoek.applyToDefaults( // a little type gymnastics here to workaround poor typing defaultOptions as any, pluginOpts ) as any; if (!options.nextAuthAdapterFactory) { throw new Error( "You must pass a NextAuthAdapterFactory instance to hapi-nextauth." ); } server.validator(Joi); let auth = "hapi-nextauth"; if (options.sharedSecret) { server.dependency(["@hapi/basic"]); server.auth.strategy(auth, "basic", { validate: validateAuth(options.sharedSecret), }); } else { console.warn( "hapi-nextauth: AUTHENTICATION OF FRONTEND TO NEXTAUTH ENDPOINTS DISABLED!" ); auth = undefined; } await Routes.register(server, options, auth); }; const nextAuthPlugin = { register, name: "@digiresilience/hapi-nextauth", version: "0.0.3", }; export * from "./types.js"; export default nextAuthPlugin;