[GH-ISSUE #2154] Better Auth is not respecting the result of mapProfileToUser #17701

Closed
opened 2026-04-15 15:56:25 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @ian on GitHub (Apr 6, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2154

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

It does not seem like better-auth is respecting the result of mapProfileToUser.

Consider the following configuration:

google: {
  clientId: process.env.GOOGLE_CLIENT_ID as string,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
  prompt: 'select_account',
  mapProfileToUser: (profile) => {
    return {
      name: [profile.given_name, profile.family_name]
        .filter(Boolean)
        .join(' '),
      email: profile.email,
      emailVerified: profile.email_verified,
    };
  },
}

This should create a user with only the fields returned by mapProfileToUser.

However, it's still injecting the image field into the user:

2025-04-06T16:46:21.215Z ERROR [Better Auth]: PrismaClientValidationError:
Invalid `db[getModelName(model)].create()` invocation in
/Users/ian/Projects/brg/brg/apps/api/.next/server/chunks/node_modules_better-auth_dist_e7fe42cb._.js:2876:62

  2873 if (!db[getModelName(model)]) {
  2874     throw new __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$better$2d$auth$2f$dist$2f$shared$2f$better$2d$auth$2e$DdzSJf$2d$n$2e$mjs__$5b$app$2d$route$5d$__$28$ecmascript$29$__["B"](`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`);
  2875 }
→ 2876 const result = await db[getModelName(model)].create({
         data: {
           id: "VIfODcTT9aXwSitddnZuzmklT0c0I6dT",
           name: "Test",
           email: "test@test.com",
           emailVerified: true,
           image: "https://lh3.googleusercontent.com/a/ACg8ocLNKrhvWEOI9CoFAdc7DMvSTEX2jB5dmBlZGJsw9ztRDtlguBzAhQ=s96-c",
           ~~~~~
           createdAt: new Date("2025-04-06T16:46:21.208Z"),
           updatedAt: new Date("2025-04-06T16:46:21.208Z"),
           role: "user",
       ?   imageKey?: String | Null,
       ?   username?: String | Null,
       ?   bio?: String | Null,
       ?   instagram?: String | Null,
       ?   twitter?: String | Null,
       ?   lastSeenAt?: DateTime | Null,
       ?   password_hash?: String | Null,
       ?   isAdmin?: Boolean,
       ?   isVerified?: Boolean,
       ?   following?: UserFollowCreateNestedManyWithoutFollowerInput,
       ?   followers?: UserFollowCreateNestedManyWithoutFollowingInput,
       ?   savedRestaurants?: SavedRestaurantCreateNestedManyWithoutUserInput,
       ?   sessions?: SessionCreateNestedManyWithoutUserInput,
       ?   accounts?: AccountCreateNestedManyWithoutUserInput
         },
         select: undefined
       })

Unknown argument `image`. Did you mean `name`? Available options are marked with ?.

Why is this happening? There is no image field in the returned profile.

Current vs. Expected behavior

It should not be including the image field since that is NOT in the returned profile.

What version of Better Auth are you using?

1.2.4

Provide environment information

- OS: Mac

Which area(s) are affected? (Select all that apply)

Client, Backend

Auth config (if applicable)

import { expo } from '@better-auth/expo';
import { prisma } from '@db';
import { betterAuth, type BetterAuthOptions } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { nextCookies } from 'better-auth/next-js';
import { bearer, emailOTP } from 'better-auth/plugins';

export type { BetterAuthOptions };

const config = {
  advanced: {
    cookiePrefix: 'brg',
  },
  basePath: '/auth',
  database: prismaAdapter(prisma, {
    provider: 'postgresql',
  }),
  plugins: [
    bearer(),
    nextCookies(),
    expo(),
  ],
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      prompt: 'select_account',
      mapProfileToUser: (profile) => {
        return {
          name: [profile.given_name, profile.family_name]
            .filter(Boolean)
            .join(' '),
          email: profile.email,
          emailVerified: profile.email_verified,
        };
      },
    },
  },
  user: {
    additionalFields: {
      bio: {
        type: 'string',
        required: false,
      },
      instagram: {
        type: 'string',
        required: false,
      },
      isAdmin: {
        type: 'boolean',
        required: false,
        defaultValue: false,
        input: false,
      },
      isVerified: {
        type: 'boolean',
        required: false,
        defaultValue: false,
        input: false,
      },
      role: {
        type: 'string',
        required: false,
        defaultValue: 'user',
        input: false,
      },
      twitter: {
        type: 'string',
        required: false,
      },
      username: {
        type: 'string',
        required: false,
      },
    },
  },
} satisfies BetterAuthOptions;

export const auth = betterAuth(config);

Additional context

No response

Originally created by @ian on GitHub (Apr 6, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2154 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce It does not seem like better-auth is respecting the result of `mapProfileToUser`. Consider the following configuration: ``` google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, prompt: 'select_account', mapProfileToUser: (profile) => { return { name: [profile.given_name, profile.family_name] .filter(Boolean) .join(' '), email: profile.email, emailVerified: profile.email_verified, }; }, } ``` This should create a user with only the fields returned by `mapProfileToUser`. However, it's still injecting the `image` field into the user: ``` 2025-04-06T16:46:21.215Z ERROR [Better Auth]: PrismaClientValidationError: Invalid `db[getModelName(model)].create()` invocation in /Users/ian/Projects/brg/brg/apps/api/.next/server/chunks/node_modules_better-auth_dist_e7fe42cb._.js:2876:62 2873 if (!db[getModelName(model)]) { 2874 throw new __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$better$2d$auth$2f$dist$2f$shared$2f$better$2d$auth$2e$DdzSJf$2d$n$2e$mjs__$5b$app$2d$route$5d$__$28$ecmascript$29$__["B"](`Model ${model} does not exist in the database. If you haven't generated the Prisma client, you need to run 'npx prisma generate'`); 2875 } → 2876 const result = await db[getModelName(model)].create({ data: { id: "VIfODcTT9aXwSitddnZuzmklT0c0I6dT", name: "Test", email: "test@test.com", emailVerified: true, image: "https://lh3.googleusercontent.com/a/ACg8ocLNKrhvWEOI9CoFAdc7DMvSTEX2jB5dmBlZGJsw9ztRDtlguBzAhQ=s96-c", ~~~~~ createdAt: new Date("2025-04-06T16:46:21.208Z"), updatedAt: new Date("2025-04-06T16:46:21.208Z"), role: "user", ? imageKey?: String | Null, ? username?: String | Null, ? bio?: String | Null, ? instagram?: String | Null, ? twitter?: String | Null, ? lastSeenAt?: DateTime | Null, ? password_hash?: String | Null, ? isAdmin?: Boolean, ? isVerified?: Boolean, ? following?: UserFollowCreateNestedManyWithoutFollowerInput, ? followers?: UserFollowCreateNestedManyWithoutFollowingInput, ? savedRestaurants?: SavedRestaurantCreateNestedManyWithoutUserInput, ? sessions?: SessionCreateNestedManyWithoutUserInput, ? accounts?: AccountCreateNestedManyWithoutUserInput }, select: undefined }) Unknown argument `image`. Did you mean `name`? Available options are marked with ?. ``` Why is this happening? There is no image field in the returned profile. ### Current vs. Expected behavior It should not be including the `image` field since that is NOT in the returned profile. ### What version of Better Auth are you using? 1.2.4 ### Provide environment information ```bash - OS: Mac ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript import { expo } from '@better-auth/expo'; import { prisma } from '@db'; import { betterAuth, type BetterAuthOptions } from 'better-auth'; import { prismaAdapter } from 'better-auth/adapters/prisma'; import { nextCookies } from 'better-auth/next-js'; import { bearer, emailOTP } from 'better-auth/plugins'; export type { BetterAuthOptions }; const config = { advanced: { cookiePrefix: 'brg', }, basePath: '/auth', database: prismaAdapter(prisma, { provider: 'postgresql', }), plugins: [ bearer(), nextCookies(), expo(), ], socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, prompt: 'select_account', mapProfileToUser: (profile) => { return { name: [profile.given_name, profile.family_name] .filter(Boolean) .join(' '), email: profile.email, emailVerified: profile.email_verified, }; }, }, }, user: { additionalFields: { bio: { type: 'string', required: false, }, instagram: { type: 'string', required: false, }, isAdmin: { type: 'boolean', required: false, defaultValue: false, input: false, }, isVerified: { type: 'boolean', required: false, defaultValue: false, input: false, }, role: { type: 'string', required: false, defaultValue: 'user', input: false, }, twitter: { type: 'string', required: false, }, username: { type: 'string', required: false, }, }, }, } satisfies BetterAuthOptions; export const auth = betterAuth(config); ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-15 15:56:25 -05:00
Author
Owner

@Kinfe123 commented on GitHub (Apr 7, 2025):

can you try overriding the getUserInfo options without image here on provider config -

 getUserInfo: async (token) => {
        if (!token.idToken) {
          return null;
        }
        const profile = decodeJwt(token.idToken) as GoogleProfile;
       
        return {
          user: {
            id: profile.sub,
            name: [profile.given_name, profile.family_name]
              .filter(Boolean)
              .join(' '),
            email: profile.email,
            emailVerified: profile.email_verified,
          },
          data: profile,
        };
      },

since this one got processed before mapProfileToUser and passed to it

<!-- gh-comment-id:2782150819 --> @Kinfe123 commented on GitHub (Apr 7, 2025): can you try overriding the getUserInfo options without image here on provider config - ```ts getUserInfo: async (token) => { if (!token.idToken) { return null; } const profile = decodeJwt(token.idToken) as GoogleProfile; return { user: { id: profile.sub, name: [profile.given_name, profile.family_name] .filter(Boolean) .join(' '), email: profile.email, emailVerified: profile.email_verified, }, data: profile, }; }, ``` since this one got processed before mapProfileToUser and passed to it
Author
Owner

@Kinfe123 commented on GitHub (Apr 7, 2025):

ref - #2148

<!-- gh-comment-id:2782729929 --> @Kinfe123 commented on GitHub (Apr 7, 2025): ref - #2148
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#17701