added extra hardening options to the Microsoft OAuth2 provider allowing devs to specify the preferred safe email extraction method

This commit is contained in:
Gani Georgiev
2026-07-06 15:44:37 +03:00
parent 667a765070
commit 7b3f4d62b1
13 changed files with 213 additions and 18 deletions
+1
View File
@@ -42,6 +42,7 @@ window.app.oauth2.lark = function(providerInfo, namePrefix, data) {
{ className: "field" },
t.label({ htmlFor: uniqueId + ".site" }, "Site"),
app.components.select({
id: uniqueId + ".site",
options: domainOptions,
required: true,
value: () => local.domain || "",
+101 -1
View File
@@ -5,9 +5,93 @@ window.app.oauth2 = window.app.oauth2 || {};
window.app.oauth2.microsoft = function(providerInfo, namePrefix, data) {
const uniqueId = "microsoft_" + app.utils.randomString();
const idTokenEmailClaimOptions = [
{
value: "",
selected: `Graph API "mail" field (default)`,
label: () => {
return t.div(
{ className: "option-content" },
t.strong(null, "Graph API ", t.code(null, "mail"), " field (default)"),
t.br(),
t.small(
{ className: "txt-hint" },
`Extracts the "mail" field from the Graph API /me endpoint (this is a historical default and it is generally accepted to be safe for controlled single-tenant apps).`,
),
);
},
},
{
value: "email",
selected: `"email" id_token claim`,
label: () => {
return t.div(
{ className: "option-content" },
t.strong(null, t.code(null, "email"), " id_token claim"),
t.br(),
t.small(
{ className: "txt-hint" },
`Extracts the "email" token field (since June 2023 by default Microsoft will populate the field only if the email is considered verified, unless the "removeUnverifiedEmailClaim" property was disabled).`,
),
);
},
},
{
value: "email_and_xms_edov",
selected: `"email" + "xms_edov" id_token claims`,
label: () => {
return t.div(
{ className: "option-content" },
t.strong(null, t.code(null, "email"), " + ", t.code(null, "xms_edov"), " id_token claims"),
t.br(),
t.small(
{ className: "txt-hint" },
`Extracts the "email" token field ONLY if the domain owner has been verified.`,
),
);
},
},
{
value: "verified_primary_email",
selected: `"verified_primary_email" id_token claim`,
label: () => {
return t.div(
{ className: "option-content" },
t.strong(null, t.code(null, "verified_primary_email"), " id_token claim"),
t.br(),
t.small(
{ className: "txt-hint" },
`Extracts the configured user's "PrimaryAuthoritativeEmail" attribute value.`,
),
);
},
},
{
value: "any_verified",
selected: `Either "verified_primary_email" OR "email" + "xms_edov" id_token claims`,
label: () => {
return t.div(
{ className: "option-content" },
t.strong(
null,
"Either ",
t.code(null, "verified_primary_email"),
" OR ",
t.code(null, "email"),
" + ",
t.code(null, "xms_edov"),
" id_token claims",
),
t.br(),
t.small({ className: "txt-hint" }, "Extracts the first nonempty value from the 2."),
);
},
},
];
return t.div(
{ pbEvent: "oauth2MicrosoftOptions", className: "oauth2-microsoft-options" },
t.p({ className: "txt-bold" }, "Azure AD endpoints"),
t.p({ className: "txt-bold" }, "Azure AD / Entra ID"),
t.div(
{ className: "grid" },
t.div(
@@ -48,6 +132,22 @@ window.app.oauth2.microsoft = function(providerInfo, namePrefix, data) {
"Ex. https://login.microsoftonline.com/YOUR_DIRECTORY_TENANT_ID/oauth2/v2.0/token",
),
),
t.div(
{ className: "col-12" },
t.div(
{ className: "field" },
t.label({ htmlFor: uniqueId + ".extra.idTokenEmailClaim" }, "Extract email from"),
app.components.select({
id: uniqueId + ".extra.idTokenEmailClaim",
options: idTokenEmailClaimOptions,
value: () => data.config.extra?.idTokenEmailClaim || "",
onchange: (selectedOpts) => {
data.config.extra = data.config.extra || {};
data.config.extra.idTokenEmailClaim = selectedOpts[0]?.value;
},
}),
),
),
),
);
};
+3
View File
@@ -82,6 +82,9 @@
&.active {
background: var(--surfaceAlt2Color);
transition-duration: var(--activeAnimationSpeed);
code {
background: var(--surfaceAlt1Color);
}
&:hover {
background: var(--surfaceAlt3Color);
transition-duration: var(--animationSpeed);