theonedev/onedev · error · UnauthorizedException

Unauthorized

Error message

Unauthorized

What it means

After finding the build for an artifact request (only when the caller is not the internal system identity), ArtifactResource checks SecurityUtils.canAccessProject(build.getProject()) and throws Shiro UnauthorizedException when the current user cannot access that project. Access to artifacts is gated on project access, not just on knowing the URL.

Source

Thrown at server-core/src/main/java/io/onedev/server/web/resource/ArtifactResource.java:74

		if (pathSegments.isEmpty())
			throw new ExplicitException("Artifact path has to be specified");
		
		String artifactPath = Joiner.on("/").join(pathSegments);
		
		FileInfo fileInfo = null;
		if (!SecurityUtils.isSystem()) {
			Project project = OneDev.getInstance(ProjectService.class).load(projectId);
			
			Build build = OneDev.getInstance(BuildService.class).find(project, buildNumber);

			if (build == null) {
				String message = String.format("Unable to find build (project: %s, build number: %d)", 
						project.getPath(), buildNumber);
				throw new EntityNotFoundException(message);
			}
			
			if (!SecurityUtils.canAccessProject(build.getProject()))
				throw new UnauthorizedException();
			
			fileInfo = (FileInfo) getBuildService().getArtifactInfo(build, artifactPath);
		}
		
		ResourceResponse response = new ResourceResponse();
		response.getHeaders().addHeader("X-Content-Type-Options", "nosniff");
		response.disableCaching();

		String fileName = artifactPath;
		if (fileName.contains("/"))
			fileName = StringUtils.substringAfterLast(fileName, "/");
		try {
			response.setFileName(URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
		
		if (fileInfo != null) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Request the project admin to grant you access (can access project) to the project owning the build
  2. Authenticate as a user/agent with membership in the target project
  3. For CI, use the job authorization token of the same project's build
  4. Confirm the URL's project/build pair actually points to the project you have access to
Defensive patterns

Strategy: validation

Validate before calling

const perm = await onedevApi.get(`/projects/${projectId}/permissions`);
if (!perm.canAccess) throw new Error('current user cannot access project ' + projectId + '; request membership or use a project token');

Try / catch

try { await fetch(artifactUrl); } catch (e) { if (e.status === 403) console.error('Unauthorized: obtain project access or authenticate as a member of the build\'s project'); }

Prevention

When it happens

Trigger: A user without project access requests artifacts of a build in a private/non-member project; a job or user token from another project fetches this project's artifacts.

Common situations: Sharing artifact links between teams; permission revoked after the URL was saved; CI job using another project's token; anonymous request against a private 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/31c864597e5b4c70. Report an issue: GitHub.