Summary
The portal's OIDC trust boundary only supports a single email domain
(OIDC_ALLOWED_EMAIL_DOMAIN, checked as email.endsWith("@<domain>")). We need
to allow sign-in from two org domains (two separate org domains).
Today the only way to cover two domains is OIDC_ALLOWED_EMAILS, which requires
enumerating every individual account — fragile as people join.
What we'd like
A comma-separated OIDC_ALLOWED_EMAIL_DOMAINS (plural), keeping the existing
singular OIDC_ALLOWED_EMAIL_DOMAIN for backward compatibility. Both should
feed the same domain check, and the production trust-boundary validation should
count the plural list as satisfying the boundary requirement.
Patch we're carrying locally (for reference)
We've been running this as a local patch; happy to hand it over or let you
implement it however you prefer.
--- a/plugins/portal/src/oidc.ts
+++ b/plugins/portal/src/oidc.ts
@@ export interface PrincipalRule {
claim: "sub" | "email";
allowedEmailDomain?: string;
+ allowedEmailDomains?: readonly string[];
allowedEmails?: readonly string[];
}
@@ resolvePrincipal:
- if (rule.allowedEmailDomain) {
- const domain = rule.allowedEmailDomain.toLowerCase();
- if (!email.endsWith(`@${domain}`)) throw new Error("account is outside the permitted domain");
- const hd = args.userinfo.hd ?? args.claims.hd;
- if (typeof hd === "string" && hd.toLowerCase() !== domain)
- throw new Error("account is outside the permitted domain");
- }
+ const allowedDomains = [
+ ...(rule.allowedEmailDomain ? [rule.allowedEmailDomain] : []),
+ ...(rule.allowedEmailDomains ?? []),
+ ].map((domain) => domain.toLowerCase());
+ if (allowedDomains.length) {
+ if (!allowedDomains.some((domain) => email.endsWith(`@${domain}`)))
+ throw new Error("account is outside the permitted domain");
+ const hd = args.userinfo.hd ?? args.claims.hd;
+ if (typeof hd === "string" && !allowedDomains.includes(hd.toLowerCase()))
+ throw new Error("account is outside the permitted domain");
+ }
--- a/plugins/portal/src/index.ts
+++ b/plugins/portal/src/index.ts
@@ const PRINCIPAL_RULE: PrincipalRule = {
claim: (process.env.OIDC_PRINCIPAL_CLAIM ?? "email") as PrincipalRule["claim"],
allowedEmailDomain: process.env.OIDC_ALLOWED_EMAIL_DOMAIN || undefined,
+ allowedEmailDomains: process.env.OIDC_ALLOWED_EMAIL_DOMAINS?.split(",")
+ .map((domain) => domain.trim())
+ .filter(Boolean),
allowedEmails: process.env.OIDC_ALLOWED_EMAILS?.split(",")
.map((email) => email.trim())
.filter(Boolean),
};
Plus three validation tweaks: the "requires OIDC_PRINCIPAL_CLAIM=email" check,
a new "OIDC_ALLOWED_EMAIL_DOMAINS must be a comma-separated list of valid
domains" check, and the production trust-boundary check all include
allowedEmailDomains.
Summary
The portal's OIDC trust boundary only supports a single email domain
(
OIDC_ALLOWED_EMAIL_DOMAIN, checked asemail.endsWith("@<domain>")). We needto allow sign-in from two org domains (two separate org domains).
Today the only way to cover two domains is
OIDC_ALLOWED_EMAILS, which requiresenumerating every individual account — fragile as people join.
What we'd like
A comma-separated
OIDC_ALLOWED_EMAIL_DOMAINS(plural), keeping the existingsingular
OIDC_ALLOWED_EMAIL_DOMAINfor backward compatibility. Both shouldfeed the same domain check, and the production trust-boundary validation should
count the plural list as satisfying the boundary requirement.
Patch we're carrying locally (for reference)
We've been running this as a local patch; happy to hand it over or let you
implement it however you prefer.
Plus three validation tweaks: the "requires OIDC_PRINCIPAL_CLAIM=email" check,
a new "OIDC_ALLOWED_EMAIL_DOMAINS must be a comma-separated list of valid
domains" check, and the production trust-boundary check all include
allowedEmailDomains.