goharbor/harbor · error
Unauthorized
Error message
Unauthorized
What it means
BaseController.RequireAuthenticated (src/core/api/base.go:70) returns false and sends HTTP 401 Unauthorized when the request's security context reports an unauthenticated caller. It is the standard gate for core API endpoints; the companion Prepare must already have succeeded (a security context exists, but the caller is anonymous).
Source
Thrown at src/core/api/base.go:70
// Prepare inits security context and project manager from request
// context
func (b *BaseController) Prepare() {
ctx, ok := security.FromContext(b.Context())
if !ok {
log.Errorf("failed to get security context")
b.SendInternalServerError(errors.New(""))
return
}
b.SecurityCtx = ctx
b.ProjectCtl = projectcontroller.Ctl
}
// RequireAuthenticated returns true when the request is authenticated
// otherwise send Unauthorized response and returns false
func (b *BaseController) RequireAuthenticated() bool {
if !b.SecurityCtx.IsAuthenticated() {
b.SendError(errors.UnauthorizedError(errors.New("Unauthorized")))
return false
}
return true
}
// HasProjectPermission returns true when the request has action permission on project subresource
func (b *BaseController) HasProjectPermission(projectIDOrName any, action rbac.Action, subresource ...rbac.Resource) (bool, error) {
_, _, err := utils.ParseProjectIDOrName(projectIDOrName)
if err != nil {
return false, err
}
project, err := b.ProjectCtl.Get(b.Context(), projectIDOrName)
if err != nil {
return false, err
}
resource := rbac_project.NewNamespace(project.ProjectID).Resource(subresource...)View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Send valid credentials: basic auth for robots/users, or Authorization: Bearer <token> obtained from the token service
- Refresh or recreate the robot account token (check its expires_at) and update the secret in CI
- Verify the user/robot is active and not locked, and that the auth mode (db_auth/oidc/ldap) matches how the credential was issued
Example fix
# before curl https://harbor.example.com/api/v2.0/projects # 401 Unauthorized # after curl -u 'robot$ci+drone:<secret>' https://harbor.example.com/api/v2.0/projects # or curl -H 'Authorization: Bearer <jwt>' https://harbor.example.com/api/v2.0/projects
Defensive patterns
Strategy: validation
Validate before calling
req.SetBasicAuth(robotName, robotSecret) // or
req.Header.Set("Authorization", "Bearer "+getToken())
// validate robot token expiry before use:
if robotToken.ExpiresAt != nil && robotToken.ExpiresAt.Before(time.Now()) {
return errors.New("robot token expired; rotate it")
} Type guard
func isUnauthorized(err error) bool {
return errors.IsErr(err, errors.UnauthorizedCode)
} Try / catch
resp, err := client.Do(req)
if err == nil && resp.StatusCode == http.StatusUnauthorized {
// refresh token / rotate robot secret, then retry once with new credentials
} Prevention
- Send credentials on every authenticated endpoint call (basic auth or bearer token)
- Track robot token expires_at and rotate before expiry; alert ahead of time
- Verify the account is active and the auth mode matches how credentials were issued
- On 401, refresh credentials once and retry - repeated identical retries will keep failing
When it happens
Trigger: Calling any authenticated Harbor API without credentials; using an expired/revoked OIDC or robot token; a robot account whose disabling makes IsAuthenticated() false; bearer token from a different issuer.
Common situations: Expired robot account tokens in CI after the configured TTL; OIDC token refresh missed by a client; curl without -u/-H Authorization against an authenticated endpoint; scripts run after a user was deactivated.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/b7fa7caa8c449366.
Report an issue: GitHub.