theonedev/onedev · error · IncorrectCredentialsException

Invalid or expired access token

Error message

Invalid or expired access token

What it means

BearerAuthenticationFilter authenticates requests carrying a Bearer token. If the token matches no access token, agent token, or active job context, it throws IncorrectCredentialsException('Invalid or expired access token'), which Shiro treats as failed authentication.

Source

Thrown at server-core/src/main/java/io/onedev/server/security/BearerAuthenticationFilter.java:66

    	Subject subject = SecurityUtils.getSubject();
		if (!subject.isAuthenticated()) {
			String bearerToken = SecurityUtils.getBearerToken((HttpServletRequest)request);
			if (bearerToken != null) {
				if (clusterService.getCredential().equals(bearerToken)) {
					ThreadContext.bind(userService.getSystem().asSubject());
				} else {
					var accessToken = accessTokenService.findByValue(bearerToken);
					if (accessToken != null) {
						ThreadContext.bind(accessToken.asSubject());
					} else {
						var workspaceContext = workspaceService.getWorkspaceContext(bearerToken, false);
						if (workspaceContext != null) {
							var workspace = workspaceService.load(workspaceContext.getWorkspaceId());
							ThreadContext.bind(workspace.getUser().asSubject());
							ProjectEvent.setContextualParticipatingUserIds(workspace.getParticipatingUserIds());
						} else if (agentTokenService.find(bearerToken) == null 
								&& jobService.getJobContext(bearerToken, false) == null) {
							throw new IncorrectCredentialsException("Invalid or expired access token");
						}
					}
				}
	        } 
		}
		return true;
	}

	@Override
	protected void cleanup(ServletRequest request, ServletResponse response, Exception existing)
			throws ServletException, IOException {
		try {
			super.cleanup(request, response, existing);
		} finally {
			ProjectEvent.clearContextualParticipatingUserIds();
		}
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Generate a fresh access token from user profile > Access Tokens and update the client.
  2. Verify the token belongs to the correct OneDev instance.
  3. For agents, re-sync the agent token after re-registration.
  4. Check the Authorization header format is exactly 'Bearer <token>' with no extra whitespace.

Example fix

// before
curl -H "Authorization: Bearer old-expired-token" https://onedev/api/projects
// after
curl -H "Authorization: Bearer <newly-generated-token>" https://onedev/api/projects
Defensive patterns

Strategy: try-catch

Validate before calling

if (bearerToken == null || bearerToken.isBlank()) throw new IllegalArgumentException("Missing bearer token");
// Optionally probe the token against the API before real use

Try / catch

try {
    // request with Authorization: Bearer <token>
} catch (UnauthenticatedException | IncorrectCredentialsException e) {
    // refresh token and retry once
}

Prevention

When it happens

Trigger: HTTP request with an Authorization: Bearer header whose token is not a valid access token, agent token, or job execution token (e.g. hitting the REST/API endpoint with a stale token).

Common situations: Access token revoked or expired; token rotated in user profile; using an API token from another OneDev instance; agents reinstalled with new tokens; CI job token used after job completion.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/7b453dae4dabfeb8. Report an issue: GitHub.