From 48b55758e34d9780e2697e654d2e5bc942b0ae5e Mon Sep 17 00:00:00 2001 From: Samuel Raub Date: Mon, 13 Jan 2025 01:05:37 +0100 Subject: [PATCH] feat: ignore unrecognized fields from authorization response (#1479) When authenticating using OIDC some IDPs send additional fields in their authorization response. This leads to an error because these fields can't be persisted to the DB through the auth.js prisma adapter. This PR solves this by deleting all unrecognized fields from the authorization response before persisting. This behaviour is also compliant to [RFC6749 Section 4.1.2](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2) --- packages/lib/next-auth/auth-options.ts | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/lib/next-auth/auth-options.ts b/packages/lib/next-auth/auth-options.ts index 3559467ef..b1fdd891f 100644 --- a/packages/lib/next-auth/auth-options.ts +++ b/packages/lib/next-auth/auth-options.ts @@ -1,6 +1,7 @@ /// import { PrismaAdapter } from '@next-auth/prisma-adapter'; import { compare } from '@node-rs/bcrypt'; +import { Prisma } from '@prisma/client'; import { verifyAuthenticationResponse } from '@simplewebauthn/server'; import { DateTime } from 'luxon'; import type { AuthOptions, Session, User } from 'next-auth'; @@ -27,8 +28,38 @@ import { extractNextAuthRequestMetadata } from '../universal/extract-request-met import { getAuthenticatorOptions } from '../utils/authenticator'; import { ErrorCode } from './error-codes'; +// Delete unrecognized fields from authorization response to comply with +// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2 +const prismaAdapter = PrismaAdapter(prisma); + +const unsafe_linkAccount = prismaAdapter.linkAccount!; +const unsafe_accountModel = Prisma.dmmf.datamodel.models.find(({ name }) => name === 'Account'); + +if (!unsafe_accountModel) { + throw new Error('Account model not found'); +} + +// eslint-disable-next-line @typescript-eslint/promise-function-async +prismaAdapter.linkAccount = (data) => { + const availableFields = unsafe_accountModel.fields.map((field) => field.name); + + const newData = Object.keys(data).reduce( + (acc, key) => { + if (availableFields.includes(key)) { + acc[key] = data[key]; + } + + return acc; + }, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + {} as typeof data, + ); + + return unsafe_linkAccount(newData); +}; + export const NEXT_AUTH_OPTIONS: AuthOptions = { - adapter: PrismaAdapter(prisma), + adapter: prismaAdapter, secret: process.env.NEXTAUTH_SECRET ?? 'secret', session: { strategy: 'jwt',