#10

fix(auth): map Vercel OIDC preferred_username to user.name

Openeret9616wants to merge intofrom

Problem

Signing in via the "Continue with Vercel" button on a fresh deployment of this starter always lands on /auth/error?error=name_is_missing after the user grants consent on vercel.com/oauth/authorize.

Root cause

Vercel's OIDC userinfo endpoint advertised in the discovery doc this provider already uses (https://api.vercel.com/login/oauth/userinfo) lists the following claims_supported:

sub, aud, exp, iat, iss, jti, nbf, nonce, preferred_username, email, picture

There is no name claim. better-auth's genericOAuth plugin maps profile.name to user.name by default, and lib/schema.ts declares:

export const user = pgTable(\"user\", {
  // ...
  name: text(\"name\").notNull(),
  // ...
});

So the first sign-in's INSERT INTO user fails with name_is_missing and the user is redirected to the auth error page.

Fix

Add a small mapProfileToUser on the Vercel provider config that walks name → preferred_username → email local-part → sub. Keeps the row insert happy regardless of the claim subset Vercel returns, and stays correct if/when Vercel ever adds a name claim upstream.

                 providerId: \"vercel\",
                 discoveryUrl:
                   \"https://vercel.com/.well-known/openid-configuration\",
                 clientId: vercelClientId!,
                 clientSecret: vercelClientSecret!,
                 scopes: [\"openid\", \"email\", \"profile\", \"offline_access\"],
                 pkce: true,
+                mapProfileToUser: (profile) => {
+                  const email =
+                    typeof profile.email === \"string\" ? profile.email : undefined;
+                  const name =
+                    (typeof profile.name === \"string\" && profile.name) ||
+                    (typeof profile.preferred_username === \"string\" &&
+                      profile.preferred_username) ||
+                    (email ? email.split(\"@\")[0] : undefined) ||
+                    (typeof profile.sub === \"string\" ? profile.sub : \"Vercel user\");
+                  return { name };
+                },

Repro on main

  1. Click the "Deploy with Vercel" button in the README and finish the one-click setup (Neon, env vars).
  2. Run pnpm db:push locally so the better-auth tables exist (otherwise sign-in 500s first with relation \"verification\" does not exist — separate documentation issue, not fixed here).
  3. On the deployed site, click Sign in → Continue with Vercel → Allow.
  4. Observe redirect to /auth/error?error=name_is_missing.

After this patch the same flow completes successfully: /api/auth/get-session returns a valid session and the user lands on the dashboard with their Vercel username shown in the sidebar.

Notes

  • 13-line, single-file change. No new dependencies.
  • Affects only the Vercel provider config; the (optional) GitHub social provider is untouched because GitHub's userinfo does return name.

Activity

2
vercel[bot]5mo ago

@eret9616 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.