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 <sacha@probo.com>
This commit is contained in:
Sacha Al Himdani
2026-07-13 13:06:19 +02:00
parent 54c055ebcc
commit af475bb02e
2 changed files with 10 additions and 6 deletions

View File

@@ -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/") &&

View File

@@ -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]