theonedev/onedev · error · AuthenticationException

OIDC error: Inconsistent sub in ID token and userinfo

Error message

OIDC error: Inconsistent sub in ID token and userinfo

What it means

Thrown by OpenIdConnector.processTokenResponse after fetching the userinfo endpoint: the 'sub' (subject) returned by userinfo does not match the 'sub' claim of the ID token. OIDC requires these to be identical; a mismatch signals a misconfigured or compromised provider setup, so authentication is aborted.

Source

Thrown at server-plugin/server-plugin-sso-openid/src/main/java/io/onedev/server/plugin/sso/openid/OpenIdConnector.java:267

					groups = null;
			} else {
				groups = null;
			}
			
			var accessToken = tokenResponse.getOIDCTokens().getBearerAccessToken();
			if (email == null || userName == null || fullName == null 
					|| getGroupsClaim() != null && groups == null) {

				UserInfoRequest userInfoRequest = new UserInfoRequest(
						new URI(getCachedProviderMetadata().getUserInfoEndpoint()), accessToken);
				var httpRequest = userInfoRequest.toHTTPRequest();
				httpRequest.setSSLSocketFactory(TrustCertsSSLSocketFactory.getDefault());
				var httpResponse = httpRequest.send();

				if (httpResponse.getStatusCode() == HTTPResponse.SC_OK) {
					JSONObject json = httpResponse.getBodyAsJSONObject();
					if (!subject.equals(json.get("sub")))
						throw new AuthenticationException(_T("OIDC error: Inconsistent sub in ID token and userinfo"));

					if (email == null) {
						email = getStringValue(json.get("email"));
						emailVerified = getBooleanValue(json.get("email_verified"));
						if (emailVerified == null)
							emailVerified = getBooleanValue(json.get("emailVerified"));
						if (emailVerified != null && !emailVerified)
							email = null;
					}
						
					if (userName == null) 
						userName = getStringValue(json.get("preferred_username"));

					if (fullName == null)
						fullName = getStringValue(json.get("name"));

					if (getGroupsClaim() != null && groups == null) {
						var jsonArray = (JSONArray) json.get(getGroupsClaim());

View on GitHub (pinned to d44925c47c)

Solutions

  1. Verify the connector's userinfo/discovery configuration points to the same provider and realm that issued the ID token.
  2. Update or fix the identity provider so userinfo returns the same sub as the ID token (same realm, no rewriting proxy).
  3. Check for intermediary proxies/gateways altering the userinfo response body.
  4. Compare sub value types (string vs numeric) returned by the provider and update provider firmware/version if it emits a typed mismatch.

Example fix

// before: token from realm A, userinfo from realm B
wellKnownConfiguration: "https://sso.example.com/realms/old/.well-known/openid-configuration"
// after
wellKnownConfiguration: "https://sso.example.com/realms/current/.well-known/openid-configuration"
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check userinfo before wiring the connector:
// GET userinfo endpoint with a test token; assert response JSON 'sub' equals the ID token's sub.

Try / catch

try {
    auth = connector.handleAuthResponse(...);
} catch (AuthenticationException e) {
    if (e.getMessage().contains("Inconsistent sub")) {
        // verify token issuer realm and userinfo endpoint alignment, then retry
    }
}

Prevention

When it happens

Trigger: The connector calls the userinfo endpoint (over an SSL connection using TrustCertsSSLSocketFactory) and compares json.get("sub") with the ID token subject; the values differ — typically when a proxy/gateway or mismatched client configuration returns a different user, or token/userinfo come from different realms/issuers.

Common situations: Identity provider behind a gateway that rewrites or substitutes responses; userinfo URL pointing to a different realm/environment than the token issuer; multiple identity providers (e.g. Keycloak realms) mixed in connector settings; provider bug where userinfo sub is stored as number vs string type difference.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/71caae2bb8fdf181. Report an issue: GitHub.