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
- Log in to obtain a JWT cookie before calling protected endpoints
- Clear cookies and re-authenticate if the token expired
- Include the JWT cookie when calling the API from scripts/curl
- 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
- Re-authenticate before long-running scripts hit protected APIs
- Include credentials: 'include' on cross-origin calls
- Monitor JWT TTL and refresh proactively in long sessions
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
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)