Skip to content

Commit 6bc883f

Browse files
committed
clean up
1 parent 37833e3 commit 6bc883f

1 file changed

Lines changed: 34 additions & 32 deletions

File tree

packages/web/src/auth.ts

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -239,43 +239,45 @@ const nextAuthResult = NextAuth({
239239
}
240240
},
241241
callbacks: {
242-
// Refuse OAuth signin for providers configured purely for account
243-
// linking when no authenticated user is present on the request.
244-
//
245-
// Background: @auth/core's handleLoginOrRegister (callback/handle-login.js)
246-
// reads the session token from the request and, if it can't decode it
247-
// (e.g., the session cookie expired browser-side mid auth flow, or it
248-
// never made it across the cross-site redirect),
249-
// falls through to `createUser({ ...profile })`, silently spawning a
250-
// new orphan User row from the OAuth profile. That's correct behavior
251-
// for `purpose: "sso"` providers (an unauthenticated user logging in
252-
// via SSO should become a new Sourcebot user). It's wrong for
253-
// `purpose: "account_linking"` providers: by definition, those should
254-
// only ever attach an upstream identity to an *existing* signed-in
255-
// user, never mint a new Sourcebot user.
256-
//
257-
// Returning `false` here short-circuits the callback action with an
258-
// `AccessDenied` before handleLoginOrRegister can run, redirecting
259-
// the user to the error page instead of leaving them stranded as a
260-
// new orphan identity with no UserToOrg row.
261242
async signIn({ account }) {
262-
if (!account || (account.type !== 'oauth' && account.type !== 'oidc')) {
263-
return true;
264-
}
265-
266-
const matchingProvider = getProviders().find((p) => {
243+
const matchingProvider = account
244+
? getProviders().find((p) => {
267245
const providerId = typeof p.provider === 'function'
268-
? p.provider().id
269-
: p.provider.id;
246+
? p.provider().id
247+
: p.provider.id;
270248
return providerId === account.provider;
271-
});
272-
273-
if (matchingProvider?.purpose !== 'account_linking') {
274-
return true;
249+
})
250+
: undefined;
251+
252+
const isAccountLinkingAttempt =
253+
(account?.type === 'oauth' || account?.type === 'oidc') &&
254+
matchingProvider?.purpose === 'account_linking';
255+
256+
// Refuse OAuth signin for providers configured purely for account
257+
// linking when no authenticated user is present on the request.
258+
//
259+
// Background: @auth/core's handleLoginOrRegister (callback/handle-login.js)
260+
// reads the session token from the request and, if it can't decode it
261+
// (e.g., the session cookie expired browser-side mid auth flow, or it
262+
// never made it across the cross-site redirect),
263+
// falls through to `createUser({ ...profile })`, silently spawning a
264+
// new orphan User row from the OAuth profile. That's correct behavior
265+
// for `purpose: "sso"` providers (an unauthenticated user logging in
266+
// via SSO should become a new Sourcebot user). It's wrong for
267+
// `purpose: "account_linking"` providers: by definition, those should
268+
// only ever attach an upstream identity to an *existing* signed-in
269+
// user, never mint a new Sourcebot user.
270+
//
271+
// Returning `false` here short-circuits the callback action with an
272+
// `AccessDenied` before handleLoginOrRegister can run, redirecting
273+
// the user to the error page instead of leaving them stranded as a
274+
// new orphan identity with no UserToOrg row.
275+
const session = await auth();
276+
if (isAccountLinkingAttempt && session === null) {
277+
return false;
275278
}
276279

277-
const session = await auth();
278-
return session !== null;
280+
return true;
279281
},
280282
// Restrict post-auth redirects (sign-in / sign-out, `callbackUrl`,
281283
// `redirectTo`) to the same origin as the application. This mirrors

0 commit comments

Comments
 (0)