diff --git a/lib/tests/users.test.ts b/lib/tests/users.test.ts index 18cd66428a..0dee3d725e 100644 --- a/lib/tests/users.test.ts +++ b/lib/tests/users.test.ts @@ -13,7 +13,6 @@ import { Session } from "next-auth"; import { logEvent } from "@lib/auditLogs"; jest.mock("@lib/auditLogs"); const mockedLogEvent = jest.mocked(logEvent, { shallow: true }); -import { JWT } from "next-auth/jwt"; describe("User query tests should fail gracefully", () => { it("getOrCreateUser should fail gracefully - create", async () => { @@ -26,7 +25,7 @@ describe("User query tests should fail gracefully", () => { }) ); - const result = await getOrCreateUser({ email: "test-user@test.ca" } as JWT); + const result = await getOrCreateUser("", "test-user@test.ca", undefined); expect(result).toEqual(null); expect(mockedLogEvent).not.toBeCalled(); }); @@ -45,7 +44,7 @@ describe("User query tests should fail gracefully", () => { clientVersion: "4.3.2", }) ); - const result = await getOrCreateUser({ email: "test-user@test.ca" } as JWT); + const result = await getOrCreateUser("", "test-user@test.ca", undefined); expect(result).toEqual(null); expect(mockedLogEvent).not.toBeCalled(); }); @@ -80,7 +79,7 @@ describe("getOrCreateUser", () => { (prismaMock.user.findUnique as jest.MockedFunction).mockResolvedValue(user); - const result = await getOrCreateUser({ email: "fads@asdf.ca" } as JWT); + const result = await getOrCreateUser("", "fads@asdf.ca", undefined); expect(result).toMatchObject(user); expect(mockedLogEvent).not.toBeCalled(); }); @@ -99,10 +98,7 @@ describe("getOrCreateUser", () => { }); (prismaMock.user.create as jest.MockedFunction).mockResolvedValue(user); - const result = await getOrCreateUser({ - name: "test", - email: "fads@asdf.ca", - } as JWT); + const result = await getOrCreateUser("test", "fads@asdf.ca", undefined); expect(result).toMatchObject(user); expect(prismaMock.user.create).toBeCalledWith({ diff --git a/lib/users.ts b/lib/users.ts index b912299c96..528aac6e38 100644 --- a/lib/users.ts +++ b/lib/users.ts @@ -1,5 +1,4 @@ import { prisma, prismaErrors } from "@lib/integration/prismaConnector"; -import { JWT } from "next-auth/jwt"; import { AccessControlError, checkPrivileges } from "@lib/privileges"; import { NagwareResult, UserAbility } from "./types"; import { logEvent } from "./auditLogs"; @@ -16,11 +15,11 @@ import { activeStatusUpdate } from "@lib/cache/userActiveStatus"; * Get or Create a user if a record does not exist * @returns A User Object */ -export const getOrCreateUser = async ({ - name, - email, - picture, -}: JWT): Promise<{ +export const getOrCreateUser = async ( + name: string, + email: string, + picture: string | null | undefined +): Promise<{ newlyRegistered?: boolean; name: string | null; email: string; diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 0f8ad6e2ea..ffd13c2649 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -115,7 +115,22 @@ export const authOptions: NextAuthOptions = { adapter: PrismaAdapter(prisma), events: { async signIn({ user }) { - logEvent(user.id, { type: "User", id: user.id }, "UserSignIn"); + if (!user.name || !user.email) + throw new Error( + "Could not produce the UserSignIn audit log because of missing name and/or email" + ); + + const internalUser = await getOrCreateUser(user.name, user.email, user.image); + + if (internalUser === null) + throw new Error(`Could not retrieve existing user with email: ${user.email}`); + + logEvent( + internalUser.id, + { type: "User", id: internalUser.id }, + "UserSignIn", + `Cognito user unique identifier (sub): ${user.id}` + ); }, async signOut({ token }) { logEvent(token.userId, { type: "User", id: token.userId }, "UserSignOut"); @@ -126,16 +141,18 @@ export const authOptions: NextAuthOptions = { async jwt({ token, account }) { // account is only available on the first call to the JWT function if (account?.provider) { - if (!token.email) { + if (!token.email) throw new Error(`JWT token does not have an email for user with name ${token.name}`); - } - const user = await getOrCreateUser(token); + + const user = await getOrCreateUser(token.name, token.email, token.picture); + if (user === null) throw new Error(`Could not get or create user with email: ${token.email}`); token.userId = user.id; token.lastLoginTime = new Date(); token.newlyRegistered = user.newlyRegistered; + // If name isn't passed in by the provider, use the name from the database if (!token.name) { token.name = user.name ?? "";