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
- Re-login from the intended client so a token with the matching clientId is issued
- Clear the user's stored clientId (or set it to the expected value) in dashboard_user if multi-client login is desired
- Ensure only one active session/client per user, or remove the clientId binding for that user
- 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
- Avoid concurrent logins of the same dashboard user from multiple clients
- Null out client_id binding if multi-client use is required
- Ensure all admin replicas share one database
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
- userName is null
- userName( ) can not be found.
- token is error.
- user( ) is disabled.
- shenyu.jwt.secretKey is not configured. In a multi-instance…
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)