diff --git a/registry/registry.c b/registry/registry.c
index 0393389ea3..a2a8dd7ecb 100644
--- a/registry/registry.c
+++ b/registry/registry.c
@@ -192,6 +192,7 @@ int registry_request_hello_json(RRDHOST *host, struct web_client *w) {
 
     buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce);
     buffer_json_member_add_boolean(w->response.data, "anonymous_statistics", netdata_anonymous_statistics_enabled);
+    buffer_json_member_add_boolean(w->response.data, "X-Netdata-Auth", true);
 
     buffer_json_member_add_array(w->response.data, "nodes");
     RRDHOST *h;
diff --git a/web/api/web_api.c b/web/api/web_api.c
index 7a4704bd58..96ab003900 100644
--- a/web/api/web_api.c
+++ b/web/api/web_api.c
@@ -5,27 +5,27 @@
 bool netdata_is_protected_by_bearer = false; // this is controlled by cloud, at the point the agent logs in - this should also be saved to /var/lib/netdata
 DICTIONARY *netdata_authorized_bearers = NULL;
 
-static bool web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL endpoint_acl) {
+static short int web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL endpoint_acl) {
     if(endpoint_acl == WEB_CLIENT_ACL_NONE || (endpoint_acl & WEB_CLIENT_ACL_NOCHECK))
         // the endpoint is totally public
-        return true;
+        return HTTP_RESP_OK;
 
     bool acl_allows = w->acl & endpoint_acl;
     if(!acl_allows)
         // the channel we received the request from (w->acl) is not compatible with the endpoint
-        return false;
+        return HTTP_RESP_FORBIDDEN;
 
     if(!netdata_is_protected_by_bearer && !(endpoint_acl & WEB_CLIENT_ACL_BEARER_REQUIRED))
         // bearer protection is not enabled and is not required by the endpoint
-        return true;
+        return HTTP_RESP_OK;
 
     if(!(endpoint_acl & (WEB_CLIENT_ACL_BEARER_REQUIRED|WEB_CLIENT_ACL_BEARER_OPTIONAL)))
         // endpoint does not require a bearer
-        return true;
+        return HTTP_RESP_OK;
 
     if((w->acl & (WEB_CLIENT_ACL_ACLK|WEB_CLIENT_ACL_WEBRTC)))
         // the request is coming from ACLK or WEBRTC (authorized already),
-        return true;
+        return HTTP_RESP_OK;
 
     // at this point we need a bearer to serve the request
     // either because:
@@ -37,11 +37,11 @@ static bool web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL
     BEARER_STATUS t = api_check_bearer_token(w);
     if(t == BEARER_STATUS_AVAILABLE_AND_VALIDATED)
         // we have a valid bearer on the request
-        return true;
+        return HTTP_RESP_OK;
 
     netdata_log_info("BEARER: bearer is required for request: code %d", t);
 
-    return false;
+    return HTTP_RESP_PRECOND_FAIL;
 }
 
 int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_path_endpoint, struct web_api_command *api_commands) {
@@ -73,8 +73,19 @@ int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_pat
                 return HTTP_RESP_BAD_REQUEST;
             }
 
-            if(unlikely(!web_client_check_acl_and_bearer(w, api_commands[i].acl)))
-                return web_client_permission_denied(w);
+            short int code = web_client_check_acl_and_bearer(w, api_commands[i].acl);
+            if(code != HTTP_RESP_OK) {
+                if(code == HTTP_RESP_FORBIDDEN)
+                    return web_client_permission_denied(w);
+
+                if(code == HTTP_RESP_PRECOND_FAIL)
+                    return web_client_bearer_required(w);
+
+                buffer_flush(w->response.data);
+                buffer_sprintf(w->response.data, "Failed with code %d", code);
+                w->response.code = code;
+                return code;
+            }
 
             char *query_string = (char *)buffer_tostring(w->url_query_string_decoded);
 
diff --git a/web/api/web_api_v2.c b/web/api/web_api_v2.c
index 5921db1682..af4b60ceb5 100644
--- a/web/api/web_api_v2.c
+++ b/web/api/web_api_v2.c
@@ -53,16 +53,27 @@ static time_t bearer_get_token(uuid_t *uuid) {
 }
 
 #define HTTP_REQUEST_AUTHORIZATION_BEARER "\r\nAuthorization: Bearer "
+#define HTTP_REQUEST_X_NETDATA_AUTH_BEARER "\r\nX-Netdata-Auth: Bearer "
 
 BEARER_STATUS extract_bearer_token_from_request(struct web_client *w, char *dst, size_t dst_len) {
     const char *req = buffer_tostring(w->response.data);
     size_t req_len = buffer_strlen(w->response.data);
-    const char *bearer = strcasestr(req, HTTP_REQUEST_AUTHORIZATION_BEARER);
+    const char *bearer = NULL;
+    const char *bearer_end = NULL;
 
-    if(!bearer)
+    bearer = strcasestr(req, HTTP_REQUEST_X_NETDATA_AUTH_BEARER);
+    if(bearer)
+        bearer_end = bearer + sizeof(HTTP_REQUEST_X_NETDATA_AUTH_BEARER) - 1;
+    else {
+        bearer = strcasestr(req, HTTP_REQUEST_AUTHORIZATION_BEARER);
+        if(bearer)
+            bearer_end = bearer + sizeof(HTTP_REQUEST_AUTHORIZATION_BEARER) - 1;
+    }
+
+    if(!bearer || !bearer_end)
         return BEARER_STATUS_NO_BEARER_IN_HEADERS;
 
-    const char *token_start = bearer + sizeof(HTTP_REQUEST_AUTHORIZATION_BEARER) - 1;
+    const char *token_start = bearer_end;
 
     while(isspace(*token_start))
         token_start++;
diff --git a/web/server/web_client.c b/web/server/web_client.c
index 92d97e8a80..456de68928 100644
--- a/web/server/web_client.c
+++ b/web/server/web_client.c
@@ -22,8 +22,8 @@ inline int web_client_bearer_required(struct web_client *w) {
     w->response.data->content_type = CT_TEXT_PLAIN;
     buffer_flush(w->response.data);
     buffer_strcat(w->response.data, "An authorization bearer is required to access the resource.");
-    w->response.code = HTTP_RESP_UNAUTHORIZED;
-    return HTTP_RESP_UNAUTHORIZED;
+    w->response.code = HTTP_RESP_PRECOND_FAIL;
+    return HTTP_RESP_PRECOND_FAIL;
 }
 
 static inline int bad_request_multiple_dashboard_versions(struct web_client *w) {