f85553903a3f87b3029f94e49f0a7d1bb805445b
max
  Mon Aug 3 12:52:33 2026 -0700
hgLogin: configurable OIDC providers, GitHub login, top-level email-link button, sign-in wording. refs #37984

diff --git src/hg/hgLogin/oauthLogin.h src/hg/hgLogin/oauthLogin.h
index 2f928ea1aa3..623fe34a2bf 100644
--- src/hg/hgLogin/oauthLogin.h
+++ src/hg/hgLogin/oauthLogin.h
@@ -1,52 +1,61 @@
-/* oauthLogin - social login (Google, ORCID) for hgLogin via OAuth 2.0 / OpenID Connect.
+/* oauthLogin - social login for hgLogin via OAuth 2.0 / OpenID Connect.
  *
- * All provider configuration comes from hg.conf:
- *   login.google.clientId, login.google.clientSecret
- *   login.orcid.clientId,  login.orcid.clientSecret
- *   login.orcid.sandbox    (optional, "on" to use sandbox.orcid.org)
- * A provider is "enabled" only when both its clientId and clientSecret are set,
- * so mirrors without credentials simply don't see the buttons. */
+ * Providers are configured entirely in hg.conf.  List the ones to offer with:
+ *   login.oauth.providers = google,orcid,github,myuni
+ * and give each a block of settings:
+ *   login.oauth.<name>.label        Button text (defaults to <name>)
+ *   login.oauth.<name>.clientId      OAuth client id      (required)
+ *   login.oauth.<name>.clientSecret  OAuth client secret  (required)
+ *   login.oauth.<name>.type          "oidc" (default) or "github"
+ *   login.oauth.<name>.issuer        OIDC issuer; endpoints are auto-discovered from
+ *                                    <issuer>/.well-known/openid-configuration
+ *   login.oauth.<name>.authUrl       Explicit endpoints (used when there is no issuer,
+ *   login.oauth.<name>.tokenUrl        or to override discovery)
+ *   login.oauth.<name>.userinfoUrl
+ *   login.oauth.<name>.scopes        Space-separated (default "openid email profile")
+ *
+ * "google", "orcid" and "github" are known names with built-in endpoints, so those only
+ * need clientId/clientSecret.  The older login.<name>.clientId/clientSecret keys are still
+ * honored.  A provider is offered only when both its clientId and clientSecret are set. */
 
 /* Copyright (C) 2026 The Regents of the University of California
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #ifndef OAUTHLOGIN_H
 #define OAUTHLOGIN_H
 
-/* hg.conf option prefixes. Full names are built as login.<provider>.<field>. */
-#define CFG_LOGIN_OAUTH_PREFIX "login."
-#define OAUTH_PROVIDER_GOOGLE "google"
-#define OAUTH_PROVIDER_ORCID  "orcid"
-
 struct oauthIdentity
 /* An authenticated identity returned by an external OAuth/OpenID provider. */
     {
     struct oauthIdentity *next;
-    char *provider;         /* "google" or "orcid" */
-    char *subject;          /* stable, unique id from the provider (Google 'sub', ORCID iD) */
+    char *provider;         /* provider short name, e.g. "google" */
+    char *subject;          /* stable, unique id from the provider */
     char *email;            /* email reported by provider, or NULL */
     boolean emailVerified;  /* TRUE if the provider asserts the email is verified */
     char *displayName;      /* full name from provider, or NULL */
     };
 
-boolean oauthProviderEnabled(char *provider);
-/* Return TRUE if both clientId and clientSecret for provider are set in hg.conf. */
-
 boolean oauthAnyProviderEnabled();
 /* Return TRUE if at least one social login provider is configured. */
 
-char *oauthLoginUrl(char *provider, char *redirectUri, char *state);
-/* Return the provider's authorization-endpoint URL to redirect the browser to.
- * redirectUri must exactly match the URI registered with the provider (the hgLogin URL).
- * state is an opaque anti-CSRF nonce that the provider echoes back.
- * Returns NULL if provider is unknown or not enabled.  Result is allocd here. */
+boolean oauthProviderEnabled(char *name);
+/* Return TRUE if the named provider is configured (clientId and clientSecret set). */
+
+struct slName *oauthProviderNames();
+/* Return the short names of all configured providers, in the order listed in hg.conf.
+ * Do not free (owned by an internal cache). */
+
+char *oauthProviderLabel(char *name);
+/* Return the display label for a provider (falls back to the name).  Do not free. */
+
+char *oauthLoginUrl(char *name, char *redirectUri, char *state);
+/* Return the provider's authorization URL to redirect the browser to, or NULL.  Allocd. */
 
-struct oauthIdentity *oauthFetchIdentity(char *provider, char *code, char *redirectUri);
-/* Exchange the authorization code for tokens at the provider's token endpoint, then
- * fetch the user's identity.  Return the identity, or NULL on any failure.
- * Dispose of the result with oauthIdentityFree(). */
+struct oauthIdentity *oauthFetchIdentity(char *name, char *code, char *redirectUri);
+/* Exchange the authorization code for tokens and fetch the authenticated identity, or NULL
+ * on any failure.  Dispose of the result with oauthIdentityFree(). */
 
 void oauthIdentityFree(struct oauthIdentity **pId);
 /* Free an oauthIdentity. */
 
 #endif /* OAUTHLOGIN_H */