apache/shenyu · error · AuthenticationException

clientId is invalid or does not match

Error message

clientId is invalid or does not match

What it means

ShenYu supports binding a dashboard user to a specific clientId. If the JWT carries a clientId claim that differs from the clientId stored on the DashboardUser (both non-empty), authentication fails to prevent token reuse across clients.

Solutions

  1. Re-login from the intended client so a token with the matching clientId is issued
  2. Clear the user's stored clientId (or set it to the expected value) in dashboard_user if multi-client login is desired
  3. Ensure only one active session/client per user, or remove the clientId binding for that user
  4. Verify all admin instances share the same database so clientId updates are consistent

Example fix

// before
UPDATE dashboard_user SET client_id = 'old-client' WHERE user_name = 'admin';
// after
UPDATE dashboard_user SET client_id = NULL WHERE user_name = 'admin'; -- allow any client
Defensive patterns

Strategy: validation

Validate before calling

String tokenClientId = parseClaim(token, "clientId");
String storedClientId = dashboardUser.getClientId();
boolean mismatch = tokenClientId != null && storedClientId != null && !storedClientId.equals(tokenClientId);

Try / catch

try { call(); } catch (AuthenticationException e) { if (e.getMessage().contains("clientId is invalid")) { reloginFromClient(); } }

Prevention

When it happens

Trigger: A token issued for client A is replayed while the dashboard_user row has clientId B — e.g. user logged in from a second browser/client after the server recorded the first clientId, or load-balanced admin instances with divergent DB state mid-update.

Common situations: User logged in on two machines concurrently where login updates the stored clientId; copying tokens between environments/tools; admin DB partially migrated when the clientId column feature was introduced; JWT library omitting clientId claim handling in custom clients.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/d563d566b2ccbc1e. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java:116

        }

        String userName = JwtUtils.getIssuer(token);
        if (StringUtils.isEmpty(userName)) {
            throw new AuthenticationException("userName is null");
        }

        DashboardUserVO dashboardUserVO = dashboardUserService.findByUserName(userName);
        if (Objects.isNull(dashboardUserVO)) {
            throw new AuthenticationException(String.format("userName(%s) can not be found.", userName));
        }
        if (!Boolean.TRUE.equals(dashboardUserVO.getEnabled())) {
            throw new AuthenticationException(String.format("user(%s) is disabled.", userName));
        }
        String clientIdFromToken = JwtUtils.getClientId(token);
        if (StringUtils.isNotEmpty(clientIdFromToken)
                && StringUtils.isNotEmpty(dashboardUserVO.getClientId())
                && !StringUtils.equals(dashboardUserVO.getClientId(), clientIdFromToken)) {
            throw new AuthenticationException("clientId is invalid or does not match");
        }

        if (!JwtUtils.verifyToken(token, jwtProperties.getSecretKey())) {
            throw new AuthenticationException("token is error.");
        }

        return new SimpleAuthenticationInfo(UserInfo.builder()
                .userName(userName)
                .userId(dashboardUserVO.getId())
                .build(), token, this.getName());
    }
}

View on GitHub (pinned to 567142e072)