add type-safe getSession()
(#486)
* fix types for auth * implement safer to use `getSession`
This commit is contained in:
parent
a162949cf1
commit
a0a0ec86f0
13 changed files with 130 additions and 92 deletions
34
lib/auth.ts
34
lib/auth.ts
|
@ -1,11 +1,29 @@
|
|||
import { hash, compare } from 'bcryptjs';
|
||||
import { compare, hash } from "bcryptjs";
|
||||
import { DefaultSession } from "next-auth";
|
||||
import { getSession as getSessionInner, GetSessionOptions } from "next-auth/client";
|
||||
|
||||
export async function hashPassword(password) {
|
||||
const hashedPassword = await hash(password, 12);
|
||||
return hashedPassword;
|
||||
export async function hashPassword(password: string) {
|
||||
const hashedPassword = await hash(password, 12);
|
||||
return hashedPassword;
|
||||
}
|
||||
|
||||
export async function verifyPassword(password, hashedPassword) {
|
||||
const isValid = await compare(password, hashedPassword);
|
||||
return isValid;
|
||||
}
|
||||
export async function verifyPassword(password: string, hashedPassword: string) {
|
||||
const isValid = await compare(password, hashedPassword);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
type DefaultSessionUser = NonNullable<DefaultSession["user"]>;
|
||||
type CalendsoSessionUser = DefaultSessionUser & {
|
||||
id: number;
|
||||
username: string;
|
||||
};
|
||||
interface Session extends DefaultSession {
|
||||
user?: CalendsoSessionUser;
|
||||
}
|
||||
|
||||
export async function getSession(options: GetSessionOptions): Promise<CalendsoSession | null> {
|
||||
const session = await getSessionInner(options);
|
||||
|
||||
// that these are equal are ensured in `[...nextauth]`'s callback
|
||||
return session as CalendsoSession;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
|
|
|
@ -1,59 +1,73 @@
|
|||
import NextAuth from 'next-auth';
|
||||
import Providers from 'next-auth/providers';
|
||||
import prisma from '../../../lib/prisma';
|
||||
import {verifyPassword} from "../../../lib/auth";
|
||||
import NextAuth from "next-auth";
|
||||
import Providers from "next-auth/providers";
|
||||
import prisma from "../../../lib/prisma";
|
||||
import { CalendsoSession, verifyPassword } from "../../../lib/auth";
|
||||
|
||||
export default NextAuth({
|
||||
session: {
|
||||
jwt: true
|
||||
session: {
|
||||
jwt: true,
|
||||
},
|
||||
pages: {
|
||||
signIn: "/auth/login",
|
||||
signOut: "/auth/logout",
|
||||
error: "/auth/error", // Error code passed in query string as ?error=
|
||||
},
|
||||
providers: [
|
||||
Providers.Credentials({
|
||||
name: "Calendso",
|
||||
credentials: {
|
||||
email: { label: "Email Address", type: "email", placeholder: "john.doe@example.com" },
|
||||
password: { label: "Password", type: "password", placeholder: "Your super secure password" },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: credentials.email,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error("No user found");
|
||||
}
|
||||
if (!user.password) {
|
||||
throw new Error("Incorrect password");
|
||||
}
|
||||
|
||||
const isValid = await verifyPassword(credentials.password, user.password);
|
||||
|
||||
if (!isValid) {
|
||||
throw new Error("Incorrect password");
|
||||
}
|
||||
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
image: user.avatar,
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
async jwt(token, user) {
|
||||
// Add username to the token right after signin
|
||||
if (user?.username) {
|
||||
token.id = user.id;
|
||||
token.username = user.username;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
pages: {
|
||||
signIn: '/auth/login',
|
||||
signOut: '/auth/logout',
|
||||
error: '/auth/error', // Error code passed in query string as ?error=
|
||||
},
|
||||
providers: [
|
||||
Providers.Credentials({
|
||||
name: 'Calendso',
|
||||
credentials: {
|
||||
email: { label: "Email Address", type: "email", placeholder: "john.doe@example.com" },
|
||||
password: { label: "Password", type: "password", placeholder: "Your super secure password" }
|
||||
},
|
||||
async authorize(credentials) {
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: credentials.email
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error('No user found');
|
||||
}
|
||||
|
||||
const isValid = await verifyPassword(credentials.password, user.password);
|
||||
|
||||
if (!isValid) {
|
||||
throw new Error('Incorrect password');
|
||||
}
|
||||
|
||||
return {id: user.id, username: user.username, email: user.email, name: user.name, image: user.avatar};
|
||||
}
|
||||
})
|
||||
],
|
||||
callbacks: {
|
||||
async jwt(token, user, account, profile, isNewUser) {
|
||||
// Add username to the token right after signin
|
||||
if (user?.username) {
|
||||
token.id = user.id;
|
||||
token.username = user.username;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
async session(session, token) {
|
||||
session.user = session.user || {}
|
||||
session.user.id = token.id;
|
||||
session.user.username = token.username;
|
||||
return session;
|
||||
async session(session, token) {
|
||||
const calendsoSession: CalendsoSession = {
|
||||
...session,
|
||||
user: {
|
||||
...session.user,
|
||||
id: token.id as number,
|
||||
username: token.username as string,
|
||||
},
|
||||
};
|
||||
return calendsoSession;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { hashPassword, verifyPassword } from '../../../lib/auth';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../lib/prisma';
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { hashPassword, verifyPassword } from "../../../lib/auth";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../lib/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getSession({req: req});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type {NextApiRequest, NextApiResponse} from 'next';
|
||||
import {getSession} from 'next-auth/client';
|
||||
import prisma from '../../../lib/prisma';
|
||||
import {IntegrationCalendar, listCalendars} from "../../../lib/calendarClient";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../lib/prisma";
|
||||
import { IntegrationCalendar, listCalendars } from "../../../lib/calendarClient";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getSession({req: req});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type {NextApiRequest, NextApiResponse} from 'next';
|
||||
import {getSession} from 'next-auth/client';
|
||||
import prisma from '../../../lib/prisma';
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../lib/prisma";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const session = await getSession({req: req});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import prisma from '../../lib/prisma';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from "../../lib/prisma";
|
||||
import { getSession } from "@lib/auth";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'GET') {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
const {google} = require('googleapis');
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../../lib/prisma";
|
||||
const { google } = require("googleapis");
|
||||
|
||||
const credentials = process.env.GOOGLE_API_CREDENTIALS;
|
||||
const scopes = ['https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/calendar.events'];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
const {google} = require('googleapis');
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../../lib/prisma";
|
||||
const { google } = require("googleapis");
|
||||
|
||||
const credentials = process.env.GOOGLE_API_CREDENTIALS;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../../lib/prisma";
|
||||
|
||||
const scopes = ['User.Read', 'Calendars.Read', 'Calendars.ReadWrite', 'offline_access'];
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { getSession } from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
const scopes = ['offline_access', 'Calendars.Read', 'Calendars.ReadWrite'];
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../../lib/prisma";
|
||||
const scopes = ["offline_access", "Calendars.Read", "Calendars.ReadWrite"];
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { code } = req.query;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type {NextApiRequest, NextApiResponse} from 'next';
|
||||
import {getSession} from 'next-auth/client';
|
||||
import prisma from '../../../../lib/prisma';
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { getSession } from "@lib/auth";
|
||||
import prisma from "../../../../lib/prisma";
|
||||
|
||||
const client_id = process.env.ZOOM_CLIENT_ID;
|
||||
|
||||
|
|
|
@ -1151,6 +1151,11 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.3.0"
|
||||
|
||||
"@types/bcryptjs@^2.4.2":
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae"
|
||||
integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==
|
||||
|
||||
"@types/graceful-fs@^4.1.2":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
|
||||
|
|
Loading…
Reference in a new issue