theonedev/onedev · error · UnauthorizedException

Unauthorized

Error message

Unauthorized

What it means

BuildResource.getBuild loads a build by id and throws UnauthorizedException unless SecurityUtils.canAccessProject(build.getProject()) passes. Even a valid build id returns 401/403 if the caller cannot access the containing project. This enforces project-level access control on the REST build API.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/BuildResource.java:65

public class BuildResource {

	private final BuildService buildService;
	
	private final AuditService auditService;
	
	@Inject
	public BuildResource(BuildService buildService, AuditService auditService) {
		this.buildService = buildService;
		this.auditService = auditService;
	}

	@Api(order=100)
	@Path("/{buildId}")
    @GET
    public Build getBuild(@PathParam("buildId") Long buildId) {
		Build build = buildService.load(buildId);
    	if (!SecurityUtils.canAccessProject(build.getProject())) 
			throw new UnauthorizedException();
    	return build;
    }

	@Api(order=150, description = "Get list of <a href='/~help/api/io.onedev.server.rest.BuildLabelResource'>labels</a>")
	@Path("/{buildId}/labels")
	@GET
	public Collection<BuildLabel> getLabels(@PathParam("buildId") Long buildId) {
		Build build = buildService.load(buildId);
		if (!SecurityUtils.canAccessProject(build.getProject()))
			throw new UnauthorizedException();
		return build.getLabels();
	}
	
	@Api(order=200)
	@Path("/{buildId}/params")
    @GET
    public Collection<BuildParam> getParams(@PathParam("buildId") Long buildId) {
		Build build = buildService.load(buildId);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Request access (read) to the project owning the build, or use a token from a member account.
  2. Verify the buildId belongs to a project the token can access — list accessible builds first via project-scoped endpoints.
  3. Check the Authorization header is present and the token is valid/not expired.
  4. As admin, add the user or token's role to the project with at least read permission.

Example fix

// before: fetch build directly by id
Build b = client.path("/rest/builds/" + id).get(Build.class);
// after: scope to a project you can access
List<Build> builds = client.path("/rest/projects/" + projectPath + "/builds").get();
Build b = builds.stream().filter(x -> x.getId().equals(id)).findFirst().orElseThrow();
Defensive patterns

Strategy: validation

Validate before calling

// before calling, ensure project access via a lightweight GET
Response r = client.path("/rest/projects/" + projectPath).get();
if (r.getStatus() == 401 || r.getStatus() == 403) {
    throw new SecurityException("Account cannot access project " + projectPath + " — request membership");
}

Try / catch

try {
    Build b = client.path("/rest/builds/" + id).get(Build.class);
} catch (NotAuthorizedException e) {
    throw new AccessDeniedException("No access to project owning build " + id, e);
}

Prevention

When it happens

Trigger: GET /rest/builds/{buildId} with a build in a project the user cannot see — private project membership missing, anonymous request, API token role without project read access, or simply a wrong guess of buildId pointing into another project.

Common situations: Scripts using a token created under a different account than expected; users removed from the project but caching old build ids; guessing/incrementing build ids; forks where the caller only has access to the upstream project.

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