948e76a68b4a62e4f6f90244eeb266342406ce53 max Wed Sep 16 03:03:36 2026 -0700 hgLogin: make trusting a provider's unverified email a per-provider setting Accepting an address a provider had not marked verified was applied to every provider, to keep CILogon usable: it sends the address it got from the user's institution but leaves email_verified at 0, even for a real institutional sign-in. Extending that to everyone was too much. GitHub hands over a primary address whose owner never confirmed it, and any provider a mirror adds to hg.conf was treated the same way, so an address nobody had checked was enough to be signed in to an existing account that used it. New login.oauth..trustEmail, off unless an admin sets it, says that a named provider's address may be taken without email_verified. It belongs on a provider that reads the address from somewhere the user cannot type into, which is what CILogon does and what GitHub does not. Where it is off and the provider did not verify the address, the address is dropped rather than refused, and the sign-in proceeds as one that arrived with no address at all, which is already the ORCID case: the user is asked for an address and the account does not work until they open the link mailed to it. Dropping it also keeps it out of the account matching in resolveIdentity, so it cannot reach an existing account. Documented in product/mirrorManual.txt next to the other provider settings, with the CILogon line mirrors will need, and in oauthLogin.h with the rest of the keys. diff --git src/product/mirrorManual.txt src/product/mirrorManual.txt index 231b19e4297..a8c24a3f66c 100644 --- src/product/mirrorManual.txt +++ src/product/mirrorManual.txt @@ -1475,38 +1475,59 @@ Two OpenID Connect federations are useful for reaching many universities at once, without registering separately with each institution. Register with them and configure them like any other OIDC provider above (a label, client id/secret and issuer): CILogon, for US universities: https://cilogon.org/oauth2/register LifeScience RI, for EU universities: https://services.aai.lifescience-ri.eu/spreg/auth Their issuer values are below. Endpoint discovery does not follow redirects, so the issuer must be the exact URL whose /.well-known/openid-configuration is served directly (for example, LifeScience RI needs the /oidc path, and neither issuer should have a trailing space or slash): login.oauth.cilogon.issuer=https://cilogon.org login.oauth.lsaii.issuer=https://login.aai.lifescience-ri.eu/oidc +CILogon needs one more setting. It sends the address it got from the user's institution but +does not mark it as verified, even for a real institutional sign-in, so by default hgLogin +discards it and asks the user to type an address and confirm it by mail. That is a pointless +round trip for an address the institution already vouched for, so tell hgLogin to take +CILogon's word for it: + + login.oauth.cilogon.trustEmail=on + +Turn trustEmail on only for a provider that reads the address from somewhere the user cannot +type into, such as a federation that gets it from the user's own institution. It is off for +every provider unless you set it. Leave it off for GitHub in particular: GitHub will hand over +a primary address whose owner never confirmed it, and with trustEmail on, an address like that +is enough to be signed in to an existing account that uses it. + +Without trustEmail, a provider that does not verify an address is not refused; hgLogin simply +behaves as if no address had been sent, which is also what happens with ORCID (ORCID's OpenID +Connect offers only the "openid" scope and never releases an address at all). The user is asked +for an address, and the account does not work until they open the link mailed to it. + (For social login, login.cookieSalt must be set, to a secret random string: it is the key that signs the identity handed back from the provider, so hgLogin refuses to run a social login without it.) A provider's button appears on the login and sign-up pages only when both its client id and secret are set, so unconfigured mirrors are unaffected. When a provider reports an email -address that it has verified, and that address matches an existing account, that account is -automatically linked to the new identity and the user is signed in; if the address matches -several accounts, the user is asked which one to use. GitHub is a plain OAuth 2.0 provider +address that it has verified (or one you have trusted with trustEmail), and that address +matches an existing account, that account is automatically linked to the new identity and the +user is signed in; if the address matches several accounts, the user is asked which one to +use. An address hgLogin will not trust never takes part in that matching at all, so it cannot +be used to reach somebody else's account. GitHub is a plain OAuth 2.0 provider rather than OpenID Connect and is handled as a special case; it is the only non-OIDC provider supported without extra code. (The older, un-prefixed keys login.google.clientId and login.orcid.clientId are still recognized for backward compatibility.) ## Passwordless email sign-in link, and changing the account email login.emailLink=on When this is on, the login page offers an "Email me a sign-in link" option: the user types their email address and receives a one-time link that signs them in without a password, which is convenient on a computer where the password is not saved. The same switch also enables the "Change email" option in the account menu. It is off by default and needs working outbound email (see login.mailReturnAddr), so turn it on only where email delivery is configured. # Proxy support