diff --git a/warden3/warden_client/warden_client.cfg b/warden3/warden_client/warden_client.cfg
index 9a771b4710d6d59ef4a8ec031a62cff9f822ac23..5b9bce5d3d89979be5459a6ff59125b37f18e467 100644
--- a/warden3/warden_client/warden_client.cfg
+++ b/warden3/warden_client/warden_client.cfg
@@ -14,5 +14,7 @@
 
     "idstore": "warden_client.id",
 
-    "name": "warden_client_kostik"
+    "name": "warden_client_kostik",
+
+    "secret": "Phaipe5ush7p"
 }
diff --git a/warden3/warden_client/warden_client.py b/warden3/warden_client/warden_client.py
index 25e9e73a13680f3bad100d7778edae6cb6f37f45..80f5b4ac3c9052a2787fbd3cf9a52dcce75e42d8 100644
--- a/warden3/warden_client/warden_client.py
+++ b/warden3/warden_client/warden_client.py
@@ -134,9 +134,11 @@ class Client(object):
             syslog=None,
             filelog=None,
             idstore=None,
-            name="warden_client"):
+            name="warden_client",
+            secret=None):
 
         self.name = name
+        self.secret = secret
         # Init logging as soon as possible and make sure we don't
         # spit out exceptions but just log or return Error objects
         self.init_log(errlog, syslog, filelog)
@@ -253,6 +255,8 @@ class Client(object):
     def sendRequest(self, func="", payload=None, **kwargs):
 
         kwargs["client"] = self.name
+        if self.secret is not None:
+            kwargs["secret"] = self.secret
 
         if kwargs:
             for k in kwargs.keys():
diff --git a/warden3/warden_client/warden_curl_test.sh b/warden3/warden_client/warden_curl_test.sh
index bab94acacd3b05bc47f8a584b25b56ba51034594..e513ce3146d4b18c851d87728711b4b17911c78e 100755
--- a/warden3/warden_client/warden_curl_test.sh
+++ b/warden3/warden_client/warden_curl_test.sh
@@ -8,6 +8,7 @@ certfile='cert.pem'
 cafile='tcs-ca-bundle.pem'
 url="$1"
 client="$2"
+secret="$3"
 
 #    --fail \
 #    --show-error \
@@ -20,7 +21,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/blefub?client=$2"
+    "$url/blefub?client=$client&secret=$secret"
 echo
 
 echo "Test  404"
@@ -30,7 +31,17 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/?client=$2"
+    "$url/?client=$client&secret=$secret"
+echo
+
+echo "Test  403 - no secret"
+curl \
+    --key $keyfile \
+    --cert $certfile \
+    --cacert $cafile \
+    --connect-timeout 3 \
+    --request POST \
+    "$url/getEvents?client=$client"
 echo
 
 echo "Test  403 - no client"
@@ -61,7 +72,7 @@ curl \
     --connect-timeout 3 \
     --request POST \
     --data '{#$%^' \
-    "$url/getEvents?client=$2"
+    "$url/getEvents?client=$client&secret=$secret"
 echo
 
 echo "Test  Called with unknown category"
@@ -71,7 +82,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2&cat=bflm"
+    "$url/getEvents?client=$client&secret=$secret&cat=bflm"
 echo
 
 echo "Test  Called with both cat and nocat"
@@ -81,7 +92,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2&cat=Other&nocat=Test"
+    "$url/getEvents?client=$client&secret=$secret&cat=Other&nocat=Test"
 echo
 
 echo "Test  Invalid data for getEvents - silently discarded"
@@ -92,7 +103,7 @@ curl \
     --connect-timeout 3 \
     --request POST \
     --data '[1]' \
-    "$url/getEvents?client=$2"
+    "$url/getEvents?client=$client&secret=$secret"
 echo
 
 echo "Test  Called with internal args - just in log"
@@ -102,7 +113,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2&self=test"
+    "$url/getEvents?client=$client&secret=$secret&self=test"
 echo
 
 echo "Test  Called with superfluous args - just in log"
@@ -112,7 +123,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2&bad=guy"
+    "$url/getEvents?client=$client&secret=$secret&bad=guy"
 echo
 
 echo "Test  getEvents with no args - should be OK"
@@ -122,7 +133,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2"
+    "$url/getEvents?client=$client&secret=$secret"
 echo
 
 echo "Test  getEvents - should be OK"
@@ -132,7 +143,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getEvents?client=$2&count=3&id=10"
+    "$url/getEvents?client=$client&secret=$secret&count=3&id=10"
 echo
 
 echo "Test  getDebug"
@@ -142,7 +153,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getDebug?client=$2"
+    "$url/getDebug?client=$client&secret=$secret"
 echo
 
 echo "Test  getInfo"
@@ -152,7 +163,7 @@ curl \
     --cacert $cafile \
     --connect-timeout 3 \
     --request POST \
-    "$url/getInfo?client=$2"
+    "$url/getInfo?client=$client&secret=$secret"
 echo
 
 #curl \
diff --git a/warden3/warden_server/warden3.0-alpha.sql b/warden3/warden_server/warden3.0-alpha.sql
index 0f66f01553aef3c97c64c076341ff37d9a84455c..16d78b539dda27566524a20caa6ecbce8905ce9c 100644
--- a/warden3/warden_server/warden3.0-alpha.sql
+++ b/warden3/warden_server/warden3.0-alpha.sql
@@ -97,6 +97,7 @@ CREATE TABLE IF NOT EXISTS `clients` (
   `note` text NOT NULL,
   `valid` tinyint(1) NOT NULL DEFAULT '1',
   `identity` varchar(64) NOT NULL,
+  `secret` varchar(16) NULL,
   `read` tinyint(1) NOT NULL DEFAULT '1',
   `debug` tinyint(1) NOT NULL DEFAULT '0',
   `write` tinyint(1) NOT NULL DEFAULT '0',
@@ -108,38 +109,38 @@ CREATE TABLE IF NOT EXISTS `clients` (
 -- Dumping data for table `clients`
 --
 
-INSERT INTO `clients` (`id`, `registered`, `requestor`, `hostname`, `service`, `note`, `valid`, `identity`, `read`, `debug`, `write`, `test`) VALUES
-(1, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', 1, 0, 1, 0),
-(2, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', 1, 0, 1, 0),
-(3, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', 1, 0, 1, 0),
-(4, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', 1, 0, 1, 0),
-(5, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', 1, 0, 1, 0),
-(6, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', 1, 0, 1, 0),
-(7, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', 1, 0, 1, 0),
-(8, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', 1, 0, 1, 0),
-(9, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', 1, 0, 1, 0),
-(10, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', 1, 0, 1, 0),
-(11, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'report_n6v-virut', '', 1, 'cz.cesnet.au1.report_n6v-virut', 1, 0, 1, 0),
-(12, '0000-00-00 00:00:00', '', 'au2.cesnet.cz', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', 1, 0, 1, 0),
-(13, '0000-00-00 00:00:00', '', 'bee.net.vutbr.cz', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', 1, 0, 1, 0),
-(14, '0000-00-00 00:00:00', '', 'buldog.vsb.cz', 'kippo', '', 1, 'cz.vsb.buldog.kippo', 1, 0, 1, 0),
-(15, '0000-00-00 00:00:00', '', 'collector-nemea.liberouter.org', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', 1, 0, 1, 0),
-(16, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'hoststats', '', 1, 'org.liberouter.collector.hoststats', 1, 0, 1, 0),
-(17, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'synscandetector_1_0', '', 1, 'org.liberouter.collector.synscandetector_1_0', 1, 0, 1, 0),
-(18, '0000-00-00 00:00:00', '', 'holly.cesnet.cz', 'kippohoneypot', '', 1, 'cz.cesnet.holly.kippohoneypot', 1, 0, 1, 0),
-(19, '0000-00-00 00:00:00', '', 'kryten.cesnet.cz', 'dionaeahoneypot', '', 1, 'cz.cesnet.kryten.dionaeahoneypot', 1, 0, 1, 0),
-(20, '0000-00-00 00:00:00', '', 'mentat.cesnet.cz', 'mentat', '', 1, 'cz.cesnet.mentat.mentat', 1, 0, 1, 0),
-(21, '0000-00-00 00:00:00', '', 'miel.opf.slu.cz', 'kippo', '', 1, 'cz.slu.opf.miel.kippo', 1, 0, 1, 0),
-(22, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'honeyscan', '', 1, 'cz.muni.ics.nfsen.honeyscan', 1, 0, 1, 0),
-(23, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'scandetector_1_0', '', 1, 'cz.muni.ics.nfsen.scandetector_1_0', 1, 0, 1, 0),
-(24, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'sshbruteforce-1_n', '', 1, 'cz.muni.ics.nfsen.sshbruteforce-1_n', 1, 0, 1, 0),
-(25, '0000-00-00 00:00:00', '', 'vinovago.cesnet.cz', 'fail2ban', '', 1, 'cz.cesnet.vinovago.fail2ban', 1, 0, 1, 0),
-(26, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'dionaeatul', '', 1, 'cz.tul.ward.dionaeatul', 1, 0, 1, 0),
-(27, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'kippo', '', 1, 'cz.tul.ward.kippo', 1, 0, 1, 0),
-(28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node', '', 1, 'com.example.test-node', 1, 0, 0, 0),
-(29, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node2', '', 1, 'com.example.test-node2', 1, 0, 0, 0),
-(30, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'Test', '', 1, 'com.example.test-node3', 1, 0, 0, 0),
-(31, '2014-12-11 13:51:18', 'ph@cesnet.cz', 'grey.cesnet.cz', 'Test', '', 1, 'cz.cesnet.grey.test', 1, 1, 1, 0);
+INSERT INTO `clients` (`id`, `registered`, `requestor`, `hostname`, `service`, `note`, `valid`, `identity`, `secret`, `read`, `debug`, `write`, `test`) VALUES
+(1, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', NULL, 1, 0, 1, 0),
+(2, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', NULL, 1, 0, 1, 0),
+(3, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', NULL, 1, 0, 1, 0),
+(4, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', NULL, 1, 0, 1, 0),
+(5, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', NULL, 1, 0, 1, 0),
+(6, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', NULL, 1, 0, 1, 0),
+(7, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', NULL, 1, 0, 1, 0),
+(8, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', NULL, 1, 0, 1, 0),
+(9, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', NULL, 1, 0, 1, 0),
+(10, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', NULL, 1, 0, 1, 0),
+(11, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'report_n6v-virut', '', 1, 'cz.cesnet.au1.report_n6v-virut', NULL, 1, 0, 1, 0),
+(12, '0000-00-00 00:00:00', '', 'au2.cesnet.cz', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', NULL, 1, 0, 1, 0),
+(13, '0000-00-00 00:00:00', '', 'bee.net.vutbr.cz', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', NULL, 1, 0, 1, 0),
+(14, '0000-00-00 00:00:00', '', 'buldog.vsb.cz', 'kippo', '', 1, 'cz.vsb.buldog.kippo', NULL, 1, 0, 1, 0),
+(15, '0000-00-00 00:00:00', '', 'collector-nemea.liberouter.org', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', NULL, 1, 0, 1, 0),
+(16, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'hoststats', '', 1, 'org.liberouter.collector.hoststats', NULL, 1, 0, 1, 0),
+(17, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'synscandetector_1_0', '', 1, 'org.liberouter.collector.synscandetector_1_0', NULL, 1, 0, 1, 0),
+(18, '0000-00-00 00:00:00', '', 'holly.cesnet.cz', 'kippohoneypot', '', 1, 'cz.cesnet.holly.kippohoneypot', NULL, 1, 0, 1, 0),
+(19, '0000-00-00 00:00:00', '', 'kryten.cesnet.cz', 'dionaeahoneypot', '', 1, 'cz.cesnet.kryten.dionaeahoneypot', NULL, 1, 0, 1, 0),
+(20, '0000-00-00 00:00:00', '', 'mentat.cesnet.cz', 'mentat', '', 1, 'cz.cesnet.mentat.mentat', NULL, 1, 0, 1, 0),
+(21, '0000-00-00 00:00:00', '', 'miel.opf.slu.cz', 'kippo', '', 1, 'cz.slu.opf.miel.kippo', NULL, 1, 0, 1, 0),
+(22, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'honeyscan', '', 1, 'cz.muni.ics.nfsen.honeyscan', NULL, 1, 0, 1, 0),
+(23, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'scandetector_1_0', '', 1, 'cz.muni.ics.nfsen.scandetector_1_0', NULL, 1, 0, 1, 0),
+(24, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'sshbruteforce-1_n', '', 1, 'cz.muni.ics.nfsen.sshbruteforce-1_n', NULL, 1, 0, 1, 0),
+(25, '0000-00-00 00:00:00', '', 'vinovago.cesnet.cz', 'fail2ban', '', 1, 'cz.cesnet.vinovago.fail2ban', NULL, 1, 0, 1, 0),
+(26, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'dionaeatul', '', 1, 'cz.tul.ward.dionaeatul', NULL, 1, 0, 1, 0),
+(27, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'kippo', '', 1, 'cz.tul.ward.kippo', NULL, 1, 0, 1, 0),
+(28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node', '', 1, 'com.example.test-node', "Phaipe5ush7p", 1, 0, 0, 0),
+(29, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node2', '', 1, 'com.example.test-node2', NULL, 1, 0, 0, 0),
+(30, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'Test', '', 1, 'com.example.test-node3', NULL, 1, 0, 0, 0),
+(31, '2014-12-11 13:51:18', 'ph@cesnet.cz', 'grey.cesnet.cz', 'Test', '', 1, 'cz.cesnet.grey.test', "co3kaero5Ruv", 1, 1, 1, 0);
 
 -- --------------------------------------------------------
 
diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py
index b7e214dbe6d96e4cb7cb66abd2987bcad6ac80f6..404d3675f268fa0c780ca139c1de340be6782eef 100755
--- a/warden3/warden_server/warden_server.py
+++ b/warden3/warden_server/warden_server.py
@@ -167,17 +167,26 @@ def SysLogger(req, socket="/dev/log", facility=logging.handlers.SysLogHandler.LO
 
 
 
-class Object(object):
+class Client(namedtuple("ClientTuple",
+    ["id", "registered", "requestor", "hostname", "service", "note",
+    "identity", "secret", "read", "debug", "write", "test"])):
 
     def __str__(self):
-        return "%s()" % type(self).__name__
+        return (
+            "%s(id=%i, registered=%s, requestor=\"%s\", hostname=\"%s\", "
+            "service=\"%s\", note=\"%s\", identity=\"%s\", secret=%s, "
+            "read=%i, debug=%i, write=%i, test=%i)") % (
+            type(self).__name__, self.id, self.registered.isoformat(),
+            self.requestor, self.hostname, self.service, self.note,
+            self.identity, "..." if self.secret is not None else "None",
+            self.read, self.debug, self.write, self.test)
 
 
 
-# Simple container class definition shortcut
-Client = namedtuple("Client",
-    ["id", "registered", "requestor", "hostname", "service", "note",
-    "identity", "read", "debug", "write", "test"])
+class Object(object):
+
+    def __str__(self):
+        return "%s()" % type(self).__name__
 
 
 
@@ -293,8 +302,24 @@ class X509Authenticator(NoAuthenticator):
 
         if not client:
             logging.info("authenticate: client not found")
+            return None
         
-        logging.info("authenticate: ok, client=%s" % str(client))
+        # Clients with 'secret' set muset get authorized by it.
+        # No secret turns auth off for this particular client.
+        if client.secret is not None:
+            try:
+                secret = args["secret"][0]
+            except KeyError:
+                logging.info("authenticate: missing secret argument")
+                return None
+            if secret != client.secret:
+                logging.info("authenticate: wrong credentials")
+                return None
+            # Already checked, prevent to spill it over logs
+            args["secret"] = ["..."]
+
+        logging.info("authenticate: %s" % str(client))
+
         return client
 
 
@@ -398,7 +423,7 @@ class MySQL(ObjectReq):
 
     def get_client_by_name(self, identity, cert_names):
         format_strings = ','.join(['%s'] * len(cert_names))
-        query = "SELECT id, registered, requestor, hostname, service, note, identity, `read`, debug, `write`, test FROM clients WHERE valid = 1 AND identity = %%s AND hostname IN (%s)" % format_strings
+        query = "SELECT id, registered, requestor, hostname, service, note, identity, secret, `read`, debug, `write`, test FROM clients WHERE valid = 1 AND identity = %%s AND hostname IN (%s)" % format_strings
         self.crs.execute(query, [identity] + cert_names)
         rows = self.crs.fetchall()
 
@@ -631,7 +656,6 @@ class Server(ObjectReq):
                 raise self.req.error("You've fallen of the cliff.", 404)
 
             self.req.args = args = parse_qs(environ.get('QUERY_STRING', ""))
-            logging.debug("arguments: %s" % str(args))
 
             self.req.client = client = self.auth.authenticate(environ, args)
             if not client:
@@ -649,7 +673,12 @@ class Server(ObjectReq):
             if not auth:
                 raise self.req.error("I'm watching. Not authorized.", 403, detail={"client": client.identity})
 
+            logging.debug("arguments: %s" % str(args))
+
+            # These args are not for handler
             args.pop("client", None)
+            args.pop("secret", None)
+
             args = self.sanitize_args(path, method, args)
             result = method(**args)   # call requested method