{"record":{"id":"ee4ae7a1b19d190b","repo":"alibaba/nacos","slug":"invalid-token-username-is-empty","errorCode":null,"errorMessage":"invalid token, username is empty","messagePattern":"invalid token, username is empty","errorType":"exception","errorClass":"AccessException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/token/impl/CachedJwtTokenManager.java","lineNumber":168,"sourceCode":"            TimeUnit.SECONDS.toMillis(jwtTokenManager.getExpiredTimeInSeconds(token));\n        if (expiredTime <= System.currentTimeMillis()) {\n            return;\n        }\n        NacosUser user = jwtTokenManager.parseToken(token);\n        tokenMap.putIfAbsent(token,\n            new TokenEntity(token, username, expiredTime, authentication, user));\n    }\n    \n    @Override\n    public NacosUser parseToken(String token) throws AccessException {\n        TokenEntity cached = tokenMap.get(token);\n        if (cached != null) {\n            return cached.getNacosUser();\n        }\n        Authentication authentication = jwtTokenManager.getAuthentication(token);\n        String username = authentication.getName();\n        if (username == null || username.isEmpty()) {\n            throw new AccessException(\"invalid token, username is empty\");\n        }\n        long expiredTime =\n            TimeUnit.SECONDS.toMillis(jwtTokenManager.getExpiredTimeInSeconds(token));\n        if (expiredTime <= System.currentTimeMillis()) {\n            throw new AccessException(\"expired token\");\n        }\n        NacosUser user = jwtTokenManager.parseToken(token);\n        tokenMap.putIfAbsent(token,\n            new TokenEntity(token, username, expiredTime, authentication, user));\n        return user;\n    }\n    \n    public long getTokenTtlInSeconds(String token) throws AccessException {\n        TokenEntity cached = tokenMap.get(token);\n        if (cached != null) {\n            return TimeUnit.MILLISECONDS.toSeconds(\n                cached.getExpiredTimeMills() - System.currentTimeMillis());\n        }","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/token/impl/CachedJwtTokenManager.java#L150-L186","documentation":"When parsing a token that is absent from the cache, CachedJwtTokenManager decodes the JWT and reads the subject via authentication.getName(). A well-formed Nacos token always carries a non-empty username; if the subject is null or empty the token is treated as invalid/malformed and AccessException is thrown. This is an auth-denial, distinct from a signature failure (which surfaces earlier inside jwtTokenManager.getAuthentication).","triggerScenarios":"Presenting a hand-built JWT whose 'sub' claim is missing or empty; a token minted by an older/buggy issuer that omits the username; a token whose payload was truncated or corrupted.","commonSituations":"Forging/testing tokens locally without the username claim; interoperating with a non-Nacos token issuer; token corruption in transit or storage.","solutions":["Discard the offending token and obtain a fresh one via the login API (POST /v3/auth/login).","If minting tokens yourself, always set a non-empty username/sub claim using the Nacos JwtParser builder.","Confirm the token was issued by a compatible Nacos version with the same secret key.","Inspect the JWT payload (base64-decode the middle segment) to confirm the sub claim."],"exampleFix":"// before: token missing sub claim\nString payload = Jwts.builder().setClaims(Map.of()).compact(); // parseToken -> AccessException\n\n// after: always include username\nString token = jwtTokenManager.createToken(\"alice\"); // sets sub=alice","handlingStrategy":"validation","validationCode":"// Validate the JWT carries a non-empty subject before calling parseToken.\ntry {\n    String[] parts = token.split(\"\\\\.\");\n    if (parts.length < 2) throw new IllegalArgumentException(\"not a JWT\");\n    String payload = new String(java.util.Base64.getUrlDecoder().decode(parts[1]));\n    com.fasterxml.jackson.databind.JsonNode node =\n        com.alibaba.nacos.common.utils.JacksonUtils.toObj(payload,\n            com.fasterxml.jackson.databind.JsonNode.class);\n    String sub = node.path(\"sub\").asText(\"\");\n    if (sub.isEmpty()) throw new IllegalArgumentException(\"token has no username/sub claim\");\n} catch (Exception pre) {\n    // token is malformed; do not call parseToken\n}","typeGuard":null,"tryCatchPattern":"try {\n    nacosUser = tokenManager.parseToken(token);\n} catch (AccessException e) {\n    if (e.getMessage().contains(\"username is empty\")) {\n        // malformed token -> treat as invalid credentials\n        throw new AccessException(\"invalid token\");\n    }\n    throw e;\n}","preventionTips":["Always obtain tokens via the Nacos login API rather than hand-building them.","When minting tokens yourself, always set a non-empty sub claim.","Catch AccessException at the auth filter and map it to a 401.","Inspect the JWT payload when debugging."],"tags":["auth","token","jwt","validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}