link-stack/packages/hapi-nextauth/src/index.ts

103 lines
2.6 KiB
TypeScript
Raw Normal View History

import * as Hapi from "@hapi/hapi";
import * as Hoek from "@hapi/hoek";
import * as Joi from "joi";
import { NextAuthPluginOptions } from "./types";
import * as Routes from "./routes";
const minimumProfileSchema = Joi.object()
.keys({
email: Joi.string().email().required(),
})
.unknown(true);
const minimumUserSchema = Joi.object()
.keys({
id: 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 <TUser, TProfile, TSession>(
server: Hapi.Server,
pluginOpts?: NextAuthPluginOptions<TUser, TProfile, TSession>
): Promise<void> => {
const options: NextAuthPluginOptions<TUser, TProfile, TSession> =
Hoek.applyToDefaults(
// a little type gymnastics here to workaround poor typing
defaultOptions as unknown,
pluginOpts
) as NextAuthPluginOptions<TUser, TProfile, TSession>;
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";
export default nextAuthPlugin;