apache/shenyu · error · AuthenticationException
userName is null
Error message
userName is null
What it means
Shiro authentication realm for the ShenYu dashboard rejects a JWT whose issuer (userName) claim cannot be extracted. JwtUtils.getIssuer(token) returned an empty string, meaning the token is malformed or missing the issuer claim, so authentication cannot proceed.
Solutions
- Re-login to the dashboard via the login endpoint to obtain a fresh, correctly-signed JWT and update the client's stored token
- Decode the JWT (base64 of payload) and verify it contains a non-empty issuer/userName claim
- Check that the client sends the token correctly: 'Authorization: Bearer <token>' with no duplicated prefix or whitespace
- Ensure the admin's jwt key configuration matches between token issuance and verification environments
Example fix
// before (client script)
curl -H "Authorization: ${TOKEN}" http://admin:9095/dashboard/user/list
// after
curl -H "Authorization: Bearer ${TOKEN}" http://admin:9095/dashboard/api/login first to refresh TOKEN Defensive patterns
Strategy: try-catch
Validate before calling
boolean hasIssuer = token != null && !token.isBlank() && new String(Base64.getDecoder().decode(token.split("\\.")[1])).contains("\"iss\""); Type guard
boolean isValidJwtShape(String t) { return t != null && t.split("\\.").length == 3 && !t.isBlank(); } Try / catch
try { dashboardApi.call(token); } catch (AuthenticationException e) { if (e.getMessage().contains("userName is null")) { relogin(); } else { throw e; } } Prevention
- Always re-login rather than hand-crafting JWTs for admin API calls
- Send the raw token without extra 'Bearer ' duplication when the client adds it
- Validate token shape (3 dot-separated segments) before storing/sending
- Clear stale tokens after admin upgrades or DB resets
When it happens
Trigger: A request hits the admin API with an Authorization bearer token that is empty after the earlier isEmpty(token) guard passes but has no parseable issuer claim — e.g. a truncated token, a token signed by a different JWT library without the issuer claim, or a token consisting of padding/whitespace.
Common situations: Clients caching a corrupt token in localStorage; sending a placeholder token like 'null' or 'Bearer Bearer'; a dashboard version upgrade changing JWT claim names; manually crafted tokens in scripts/curl calls against the admin REST API (port 9095).
Related errors
- userName( ) can not be found.
- user( ) is disabled.
- clientId is invalid or does not match
- token is error.
- 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/b917eed0dfd1b1b2.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/shiro/config/ShiroRealm.java:102
@Override
protected boolean isPermitted(final Permission permission, final AuthorizationInfo info) {
UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
if (Objects.nonNull(userInfo) && ADMIN_NAME.equals(userInfo.getUserName())) {
return true;
}
return super.isPermitted(permission, info);
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authenticationToken) {
String token = (String) authenticationToken.getCredentials();
if (StringUtils.isEmpty(token)) {
return null;
}
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.");View on GitHub (pinned to 567142e072)