@@ -242,14 +242,25 @@ const nextAuthResult = NextAuth({
242242 async signIn ( { account } ) {
243243 const matchingProvider = account
244244 ? getProviders ( ) . find ( ( p ) => {
245- const providerId = typeof p . provider === 'function'
246- ? p . provider ( ) . id
247- : p . provider . id ;
245+ // NextAuth/Auth.js provider factories (e.g. Bitbucket,
246+ // GitHub, GitLab) hardcode a default `id` at the top of
247+ // the returned object and nest the caller's options
248+ // (including any `id` override) under `.options`. At
249+ // runtime the framework merges options over the
250+ // top-level defaults, so the effective provider id can
251+ // live under either field depending on whether the
252+ // caller passed an override. Read `.options.id` first
253+ // and fall back to the top-level `id`.
254+ const config = (
255+ typeof p . provider === 'function'
256+ ? ( p . provider as unknown as ( ) => unknown ) ( )
257+ : p . provider
258+ ) as { id ?: string ; options ?: { id ?: string } } ;
259+ const providerId = config . options ?. id ?? config . id ;
248260 return providerId === account . provider ;
249261 } )
250262 : undefined ;
251263
252-
253264 // Refuse OAuth signin for providers configured purely for account
254265 // linking when no authenticated user is present on the request.
255266 //
@@ -271,6 +282,7 @@ const nextAuthResult = NextAuth({
271282 // new orphan identity with no UserToOrg row.
272283 const isAccountLinkingAttempt = matchingProvider ?. purpose === 'account_linking' ;
273284 const session = await auth ( ) ;
285+
274286 if ( isAccountLinkingAttempt && session === null ) {
275287 return false ;
276288 }
0 commit comments