{"record":{"id":"d563d566b2ccbc1e","repo":"apache/shenyu","slug":"clientid-is-invalid-or-does-not-match","errorCode":null,"errorMessage":"clientId is invalid or does not match","messagePattern":"clientId is invalid or does not match","errorType":"exception","errorClass":"AuthenticationException","httpStatus":401,"severity":"error","filePath":"shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java","lineNumber":116,"sourceCode":"        }\n\n        String userName = JwtUtils.getIssuer(token);\n        if (StringUtils.isEmpty(userName)) {\n            throw new AuthenticationException(\"userName is null\");\n        }\n\n        DashboardUserVO dashboardUserVO = dashboardUserService.findByUserName(userName);\n        if (Objects.isNull(dashboardUserVO)) {\n            throw new AuthenticationException(String.format(\"userName(%s) can not be found.\", userName));\n        }\n        if (!Boolean.TRUE.equals(dashboardUserVO.getEnabled())) {\n            throw new AuthenticationException(String.format(\"user(%s) is disabled.\", userName));\n        }\n        String clientIdFromToken = JwtUtils.getClientId(token);\n        if (StringUtils.isNotEmpty(clientIdFromToken)\n                && StringUtils.isNotEmpty(dashboardUserVO.getClientId())\n                && !StringUtils.equals(dashboardUserVO.getClientId(), clientIdFromToken)) {\n            throw new AuthenticationException(\"clientId is invalid or does not match\");\n        }\n\n        if (!JwtUtils.verifyToken(token, jwtProperties.getSecretKey())) {\n            throw new AuthenticationException(\"token is error.\");\n        }\n\n        return new SimpleAuthenticationInfo(UserInfo.builder()\n                .userName(userName)\n                .userId(dashboardUserVO.getId())\n                .build(), token, this.getName());\n    }\n}\n","sourceCodeStart":98,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java#L98-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nUPDATE dashboard_user SET client_id = 'old-client' WHERE user_name = 'admin';\n// after\nUPDATE dashboard_user SET client_id = NULL WHERE user_name = 'admin'; -- allow any client","handlingStrategy":"validation","validationCode":"String tokenClientId = parseClaim(token, \"clientId\");\nString storedClientId = dashboardUser.getClientId();\nboolean mismatch = tokenClientId != null && storedClientId != null && !storedClientId.equals(tokenClientId);","typeGuard":null,"tryCatchPattern":"try { call(); } catch (AuthenticationException e) { if (e.getMessage().contains(\"clientId is invalid\")) { reloginFromClient(); } }","preventionTips":["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"],"tags":["jwt","authentication","client-binding","admin"],"backgroundTag":"jwt-token-expired","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}