amir20/dozzle · error

Unauthorized

Error message

Unauthorized

What it means

RequireAuthentication middleware checks the request context for a User; if none is present the request is rejected with 401 Unauthorized. It means no authenticated session/JWT was established before reaching a protected route.

Solutions

  1. Log in to obtain a JWT cookie before calling protected endpoints
  2. Clear cookies and re-authenticate if the token expired
  3. Include the JWT cookie when calling the API from scripts/curl
  4. Check DOZZLE_LEVEL=debug logs to see why user was not populated (bad signature, missing cookie)

Example fix

// before
curl http://dozzle/api/containers
// after
curl -c cookies.txt -d 'user=admin&password=...' http://dozzle/api/token
curl -b cookies.txt http://dozzle/api/containers
Defensive patterns

Strategy: retry

Validate before calling

const hasJwt = document.cookie.split(';').some(c => c.trim().startsWith('jwt='));
if (!hasJwt) location.href = '/login';

Try / catch

const res = await fetch(url, {credentials: 'include'});
if (res.status === 401) {
  await login(); // re-authenticate, then retry once
  return fetch(url, {credentials: 'include'});
}

Prevention

When it happens

Trigger: Hitting any route wrapped in RequireAuthentication without a valid JWT cookie, an expired token, or when auth is configured (simple mode) but the client never logged in.

Common situations: JWT expired after TTL; browser deleted cookies; API/script calls missing the login step; clock skew invalidating tokens; calling protected endpoints before POST /api/auth/... token creation.

Understand the failure class

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/093c53c7adc42981. Report an issue: GitHub.

Appendix: source

Thrown at internal/auth/users.go:198

// request. Both providers resolve the user themselves: proxy auth from the request
// headers, simple auth from users.yml keyed by the verified token's username. Roles
// deliberately are not read back out of the JWT, because a bitmask frozen at login
// goes stale the moment the role set grows or users.yml changes.
func UserFromContext(ctx context.Context) *User {
	if user, ok := ctx.Value(remoteUser).(User); ok {
		return &user
	}

	return nil
}

func RequireAuthentication(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		user := UserFromContext(r.Context())
		if user != nil {
			next.ServeHTTP(w, r)
		} else {
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	})
}

View on GitHub (pinned to d9463cbe21)