theonedev/onedev · error · UnauthorizedException

Not authorized

Error message

Not authorized

What it means

getToken throws UnauthorizedException when a non-admin caller requests an access token they do not own. GET /{accessTokenId} loads the token and compares accessToken.getOwner() with the authenticated user; any mismatch without admin rights is rejected, preventing users from reading other users' token metadata.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/AccessTokenResource.java:55

public class AccessTokenResource {
	
	private final AccessTokenService accessTokenService;

	private final AuditService auditService;
	
	@Inject
	public AccessTokenResource(AccessTokenService accessTokenService, AuditService auditService) {
		this.accessTokenService = accessTokenService;
		this.auditService = auditService;
	}

	@Api(order=100)
	@Path("/{accessTokenId}")
	@GET
	public AccessToken getToken(@PathParam("accessTokenId") Long accessTokenId) {
		var accessToken = accessTokenService.load(accessTokenId);
    	if (!isAdministrator() && !accessToken.getOwner().equals(getAuthUser())) 
			throw new UnauthorizedException();
    	return accessToken;
	}

	@Api(order=150)
	@Path("/{accessTokenId}/authorizations")
	@GET
	public Collection<AccessTokenAuthorization> getAuthorizations(@PathParam("accessTokenId") Long accessTokenId) {
		var accessToken = accessTokenService.load(accessTokenId);
		if (!isAdministrator() && !accessToken.getOwner().equals(getAuthUser()))
			throw new UnauthorizedException();
		return accessToken.getAuthorizations();
	}
	
	@Api(order=200, description="Create access token")
	@POST
	public Long createToken(@NotNull @Valid AccessToken accessToken) {
		var owner = accessToken.getOwner();
		if (!isAdministrator() && !owner.equals(getAuthUser()))

View on GitHub (pinned to d44925c47c)

Solutions

  1. Call the API as the token's owner or as an administrator.
  2. List your own tokens first (GET /~access-tokens) and use an id you own.
  3. Confirm which user the Authorization credential belongs to.
  4. If admin access is intended, authenticate with an admin account.

Example fix

// before
GET /~access-tokens/12  // token #12 belongs to 'alice', caller is 'bob'
// after
GET /~access-tokens/15  // token #15 belongs to 'bob' (the authenticated user)
Defensive patterns

Strategy: validation

Validate before calling

const myTokens = await listMyAccessTokens();
if (!myTokens.some(t => t.id === tokenId)) {
  throw new Error(`Token ${tokenId} is not owned by the authenticated user`);
}

Type guard

function ownsToken(myTokenIds: number[], tokenId: number): boolean {
  return myTokenIds.includes(tokenId);
}

Try / catch

try {
  const token = await getToken(tokenId);
} catch (e) {
  if (e.response?.status === 401) {
    // wrong owner: list own tokens and use a valid id
  } else throw e;
}

Prevention

When it happens

Trigger: GET /~access-tokens/{accessTokenId} (AccessTokenResource.getToken) where accessToken.getOwner() != getAuthUser() and the caller is not an administrator.

Common situations: Using a hardcoded token id from documentation or a colleague's example while authenticated as yourself; a CI bot enumerating other users' token ids; stale ids copied from a different OneDev instance.

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/c658662b2ca964b7. Report an issue: GitHub.