@@ -284,6 +284,7 @@ type SamlIdpUser = {
284284 name : string ;
285285 email_verified : boolean ;
286286 profile : UserProfile ;
287+ samlTenant ?: string ;
287288} ;
288289
289290if ( IS_GOOGLE_LOGIN_ENABLED ) {
@@ -349,7 +350,7 @@ if (isSAMLLoginEnabled) {
349350 locale : profile . locale ,
350351 // Pass SAML tenant for domain authority checks in signIn callback
351352 samlTenant : profile . requested ?. tenant ,
352- ...( user ? { profile : user . allProfiles [ 0 ] } : { } ) ,
353+ ...( user && { profile : user . allProfiles [ 0 ] } ) ,
353354 } ;
354355 } ,
355356 options : {
@@ -400,7 +401,7 @@ if (isSAMLLoginEnabled) {
400401 return null ;
401402 }
402403
403- const { id, firstName, lastName } = userInfo ;
404+ const { id, firstName, lastName, requested } = userInfo ;
404405 const email = userInfo . email . toLowerCase ( ) ;
405406 const userRepo = new UserRepository ( prisma ) ;
406407 let user = ! email ? undefined : await userRepo . findByEmailAndIncludeProfilesAndPassword ( { email } ) ;
@@ -440,6 +441,8 @@ if (isSAMLLoginEnabled) {
440441 name : `${ firstName } ${ lastName } ` . trim ( ) ,
441442 email_verified : true ,
442443 profile : userProfile ,
444+ // Pass SAML tenant for domain authority checks in signIn callback (IdP-initiated flow)
445+ samlTenant : requested ?. tenant ,
443446 } ;
444447 } ,
445448 } )
@@ -817,6 +820,19 @@ export const getOptions = ({
817820
818821 log . debug ( "callbacks:signin" , safeStringify ( params ) ) ;
819822
823+ // Extract samlTenant from user (credentials/saml-idp) or profile (oauth/saml)
824+ const getSamlTenant = ( ) : string | undefined => {
825+ // Primary: user.samlTenant is set in authorize/profile callbacks (type-safe via NextAuth User extension)
826+ if ( user . samlTenant ) return user . samlTenant ;
827+
828+ // Fallback for OAuth SAML: raw BoxyHQ profile contains requested.tenant
829+ // (NextAuth adapter doesn't pass custom fields through)
830+ if ( account ?. provider === "saml" ) {
831+ return ( profile as { requested ?: { tenant ?: string } } | undefined ) ?. requested ?. tenant ;
832+ }
833+ return undefined ;
834+ } ;
835+
820836 if ( account ?. provider === "email" ) {
821837 return true ;
822838 }
@@ -978,7 +994,7 @@ export const getOptions = ({
978994 ) {
979995 // Verify SAML IdP is authoritative before auto-merge
980996 if ( idP === IdentityProvider . SAML ) {
981- const samlTenant = ( user as { samlTenant ?: string } ) . samlTenant ;
997+ const samlTenant = getSamlTenant ( ) ;
982998 const validation = await validateSamlAccountConversion ( samlTenant , user . email , "SelfHosted→SAML" ) ;
983999 if ( ! validation . allowed ) {
9841000 return validation . errorUrl ;
@@ -1000,7 +1016,7 @@ export const getOptions = ({
10001016 ) {
10011017 // Verify SAML IdP is authoritative before claiming invited user
10021018 if ( idP === IdentityProvider . SAML ) {
1003- const samlTenant = ( user as { samlTenant ?: string } ) . samlTenant ;
1019+ const samlTenant = getSamlTenant ( ) ;
10041020 const validation = await validateSamlAccountConversion ( samlTenant , user . email , "Invite→SAML" ) ;
10051021 if ( ! validation . allowed ) {
10061022 return validation . errorUrl ;
@@ -1038,7 +1054,7 @@ export const getOptions = ({
10381054 ) {
10391055 // Verify SAML IdP is authoritative before converting account
10401056 if ( idP === IdentityProvider . SAML ) {
1041- const samlTenant = ( user as { samlTenant ?: string } ) . samlTenant ;
1057+ const samlTenant = getSamlTenant ( ) ;
10421058 const validation = await validateSamlAccountConversion ( samlTenant , user . email , "CAL→SAML" ) ;
10431059 if ( ! validation . allowed ) {
10441060 return validation . errorUrl ;
@@ -1072,7 +1088,7 @@ export const getOptions = ({
10721088 idP === IdentityProvider . SAML
10731089 ) {
10741090 // Verify SAML IdP is authoritative before converting account
1075- const samlTenant = ( user as { samlTenant ?: string } ) . samlTenant ;
1091+ const samlTenant = getSamlTenant ( ) ;
10761092 const validation = await validateSamlAccountConversion ( samlTenant , user . email , "Google→SAML" ) ;
10771093 if ( ! validation . allowed ) {
10781094 return validation . errorUrl ;
0 commit comments