theonedev/onedev · error · UnauthorizedException

Not authorized

Error message

Not authorized

What it means

getUser (GET /~api/users/{userId} in UserResource) returns profile data only to administrators or the user themself. OneDev throws UnauthorizedException ('Not authorized', HTTP 403) for any other authenticated or anonymous caller. This protects personal user data from being enumerated via the REST API.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java:129

		data.setId(user.getId());
		data.setDisabled(user.isDisabled());
		data.setType(user.getType());
		data.setName(user.getName());
		data.setFullName(user.getFullName());
		if (user.getType() != SERVICE) 
			data.setNotifyOwnEvents(user.isNotifyOwnEvents());
		if (user.getType() == AI)
			data.setAiSetting(user.getAiSetting());
		return data;
	}

	@Api(order=100)
	@Path("/{userId}")
    @GET
    public UserData getUser(@PathParam("userId") Long userId) {
    	User user = userService.load(userId);
    	if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser())) 
			throw new UnauthorizedException();
		return getData(user);
    }

	@Api(order=200)
	@Path("/me")
    @GET
    public UserData getMe() {
		User user = getAuthUser();
		if (user == null)
			throw new UnauthorizedException();
		return getData(user);
    }
	
	@Api(order=250)
	@Path("/{userId}/access-tokens")
    @GET
    public Collection<AccessToken> getAccessTokens(@PathParam("userId") Long userId) {
    	User user = userService.load(userId);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Query your own user id (find it via GET /~api/users/me) with your token.
  2. Use an administrator's access token when you need other users' data.
  3. Confirm the token is being sent (an anonymous request fails this check even for self).
  4. If you need only basic info about another user, use the project-scoped member endpoints where visible.

Example fix

// before
curl -H "Authorization: Bearer <user-token>" https://onedev/~api/users/7 // userId 7 != token owner
// after
curl -H "Authorization: Bearer <user-token>" https://onedev/~api/users/me
Defensive patterns

Strategy: validation

Validate before calling

const me = await fetch(`${baseUrl}/~api/users/me`, { headers }).then(r => r.json());
if (me.id !== targetUserId) {
  console.warn('403 expected: only admins may read other users');
}

Try / catch

try {
  const user = await get(`/users/${userId}`);
} catch (e) {
  if (e.response?.status === 403) return get('/users/me'); // self fallback
  throw e;
}

Prevention

When it happens

Trigger: GET /~api/users/{userId} where the authenticated user is not an administrator and userId does not equal the id of the authenticated user (getAuthUser()).

Common situations: A non-admin token querying another user's profile; scripts hardcoding a userId that differs from the token owner's id; calling without authentication so getAuthUser() is not admin and matches nobody; assuming any project manager can read all users (only admins can).

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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