alibaba/nacos · error · HttpSessionRequiredException

session expired!

Error message

session expired!

What it means

Thrown by UserControllerV3.hasPermission() as an org.springframework.web.HttpSessionRequiredException when the request's auth context carries no IdentityContext at all — meaning the caller reached a protected user-management endpoint (e.g., password update) without an established authenticated identity. The controller catches it and responds HTTP 401 'session expired!'.

Source

Thrown at plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/v3/UserControllerV3.java:228

        
        userDetailsService.updateUserPassword(username, newPassword);
        return Result.success("update user ok!");
        
    }
    
    private boolean hasPermission(String username, HttpServletRequest request)
        throws HttpSessionRequiredException, AccessException {
        if (!NacosAuthConfigHolder.getInstance().isAnyAuthEnabled()) {
            return true;
        }
        // Fixes #13959. If the user is server identity, should not check permission.
        if (isFromServerIdentity(request)) {
            return true;
        }
        IdentityContext identityContext =
            RequestContextHolder.getContext().getAuthContext().getIdentityContext();
        if (identityContext == null) {
            throw new HttpSessionRequiredException("session expired!");
        }
        NacosUser user = (NacosUser) identityContext.getParameter(AuthConstants.NACOS_USER_KEY);
        if (user == null) {
            user = iAuthenticationManager.authenticate(request);
            if (user == null) {
                throw new HttpSessionRequiredException("session expired!");
            }
        }
        //get user form jwt need check permission
        iAuthenticationManager.hasGlobalAdminRole(user);
        // admin
        if (user.isGlobalAdmin()) {
            return true;
        }
        // same user
        return user.getUserName().equals(username);
    }
    

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Authenticate first (POST /v3/auth/login) to obtain a valid token/session and pass it on subsequent calls.
  2. Ensure the Authorization header (or session cookie) is sent on the request.
  3. If integrating server-to-server, send the server-identity header which short-circuits the check via isFromServerIdentity().

Example fix

// before
curl -X PUT 'http://host/v3/auth/user/update?username=alice&newPassword=...'
// -> 401 session expired!

// after
token=$(curl -s -X POST 'http://host/v3/auth/login' -d 'username=admin&password=...' | jq -r .data.accessToken)
curl -X PUT 'http://host/v3/auth/user/update?username=alice&newPassword=...' -H "Authorization: Bearer $token"
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: ensure a token is present before calling a protected endpoint.
String token = currentAccessToken();
if (StringUtils.isBlank(token)) {
    throw new IllegalStateException("No auth token; login first");
}
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create(url))
    .header("Authorization", "Bearer " + token)
    .PUT(BodyPublishers.ofString(body)).build();

Try / catch

try {
    controller.updateUser(username, newPassword, response, request);
} catch (HttpSessionRequiredException e) {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "session expired!");
}

Prevention

When it happens

Trigger: Calling /v3/auth/user/update (or another hasPermission-guarded endpoint) when RequestContextHolder.getContext().getAuthContext().getIdentityContext() is null — e.g., no Authorization header / session cookie, or the auth filter did not populate the context (filter ordering / disabled interceptor).

Common situations: Browser session timed out and the UI did not refresh the token; a direct API call without credentials; an auth filter misconfiguration after an upgrade that stops populating IdentityContext; server-identity header also absent.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/427b024a1b815223. Report an issue: GitHub.