Add email verification check during sign-in flow (#12605)

* Add email verification check during sign-in flow

* Add support for Entra External ID with OIDC standard verification claim
This commit is contained in:
Tom Moor
2026-06-06 08:01:26 -04:00
committed by GitHub
parent f329b56d0e
commit b23a39bd39
10 changed files with 191 additions and 1 deletions
+13
View File
@@ -102,6 +102,18 @@ if (env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET) {
const user =
context.state?.auth?.user ?? (await getUserFromOAuthState(context));
// Microsoft's email claim is mutable, only trust it when a verification
// claim confirms it — xms_edov for workforce tenants, or the standard
// email_verified claim in External ID / OIDC scenarios.
// https://learn.microsoft.com/en-us/entra/identity-platform/reference-claims-customization
const verificationClaims = [profile.xms_edov, profile.email_verified];
const presentClaims = verificationClaims.filter(
(claim) => claim !== undefined
);
const emailVerified = presentClaims.length
? presentClaims.some((claim) => claim === true || claim === "true")
: undefined;
const domain = parseEmail(email).domain;
const subdomain = slugifyDomain(domain);
@@ -121,6 +133,7 @@ if (env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET) {
user: {
name: profile.name,
email,
emailVerified,
avatarUrl: profile.picture,
},
authenticationProvider: {
+1
View File
@@ -201,6 +201,7 @@ if (env.DISCORD_CLIENT_ID && env.DISCORD_CLIENT_SECRET) {
},
user: {
email,
emailVerified: profile.verified,
name: userName,
language,
avatarUrl: userAvatarUrl,
+2
View File
@@ -127,6 +127,8 @@ if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) {
},
user: {
email: profile.email,
// Google only returns confirmed workspace email addresses.
emailVerified: true,
name: profile.displayName,
language,
avatarUrl,
+11
View File
@@ -105,6 +105,7 @@ export function createOIDCRouter(
return decoded as {
email?: string;
email_verified?: boolean | string;
preferred_username?: string;
sub?: string;
};
@@ -122,6 +123,15 @@ export function createOIDCRouter(
);
}
// The email_verified claim is part of the OIDC standard claims.
// https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
const emailVerifiedClaim =
profile.email_verified ?? token.email_verified;
const emailVerified =
emailVerifiedClaim === undefined
? undefined
: emailVerifiedClaim === true || emailVerifiedClaim === "true";
const team = await getTeamFromContext(context);
const client = getClientFromOAuthState(context);
const user =
@@ -206,6 +216,7 @@ export function createOIDCRouter(
user: {
name,
email,
emailVerified,
avatarUrl,
},
authenticationProvider: {
+2
View File
@@ -110,6 +110,8 @@ if (env.SLACK_CLIENT_ID && env.SLACK_CLIENT_SECRET) {
user: {
name: profile.user.name,
email: profile.user.email,
// Slack only returns confirmed workspace email addresses.
emailVerified: true,
avatarUrl: profile.user.image_192,
},
authenticationProvider: {