From af475bb02edd67fd9bdc87f52500da5a348164bd Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Mon, 13 Jul 2026 13:06:19 +0200 Subject: [PATCH] Skip absent email_verified for Microsoft OIDC The nOAuth fix set trustProviderEmail to false, requiring the email_verified claim. Microsoft never emits that claim, so the check rejected every legitimate Microsoft login before the xms_edov check was reached. Restore trustProviderEmail to true and keep the required xms_edov claim, which is the actual nOAuth mitigation: Azure sets it only after verifying the issuing tenant owns the email's domain, so a token lacking it is still rejected before any identity is matched. Signed-off-by: Sacha Al Himdani --- pkg/iam/oidc/service.go | 6 ++++-- pkg/iam/oidc/service_test.go | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/iam/oidc/service.go b/pkg/iam/oidc/service.go index c4554019e..215334f96 100644 --- a/pkg/iam/oidc/service.go +++ b/pkg/iam/oidc/service.go @@ -226,8 +226,10 @@ func NewService( RedirectURL: baseURL + "/api/connect/v1/oidc/microsoft/callback", Scopes: []string{"openid", "email", "profile"}, }, - jwksURL: microsoftJWKSURL, - trustProviderEmail: false, + jwksURL: microsoftJWKSURL, + // Microsoft never emits email_verified; nOAuth is + // mitigated by the required xms_edov claim below. + trustProviderEmail: true, requireEmailDomainOwnerVerified: true, issuerValidator: func(iss string) bool { return strings.HasPrefix(iss, "https://login.microsoftonline.com/") && diff --git a/pkg/iam/oidc/service_test.go b/pkg/iam/oidc/service_test.go index e59bfa526..52d5ae061 100644 --- a/pkg/iam/oidc/service_test.go +++ b/pkg/iam/oidc/service_test.go @@ -35,9 +35,11 @@ func newTestService(t *testing.T) *Service { ) } -// TestMicrosoftRequiresDomainOwnerVerified pins the nOAuth mitigation: the -// Microsoft provider must not trust the email claim on email_verified alone and -// must require the xms_edov domain-ownership claim. +// TestMicrosoftRequiresDomainOwnerVerified pins the nOAuth mitigation. +// Microsoft never emits the standard email_verified claim, so trustProviderEmail +// must be true (the email_verified check is skipped); email verification is +// instead enforced through the xms_edov domain-ownership claim, which +// requireEmailDomainOwnerVerified pins. func TestMicrosoftRequiresDomainOwnerVerified(t *testing.T) { t.Parallel() @@ -45,7 +47,7 @@ func TestMicrosoftRequiresDomainOwnerVerified(t *testing.T) { microsoft := s.providers[coredata.OIDCProviderMicrosoft] require.NotNil(t, microsoft) - assert.False(t, microsoft.trustProviderEmail, "Microsoft email must not be trusted unconditionally") + assert.True(t, microsoft.trustProviderEmail, "Microsoft does not emit email_verified; rely on xms_edov") assert.True(t, microsoft.requireEmailDomainOwnerVerified, "Microsoft must require xms_edov") google := s.providers[coredata.OIDCProviderGoogle]