diff --git a/modules/cookies/README.rst b/modules/cookies/README.rst
index 13eed5286f4ff4f11ac22a2d52ba949b528eeb16..286629c2264c6fbcddcdbd01e04258b71755f543 100644
--- a/modules/cookies/README.rst
+++ b/modules/cookies/README.rst
@@ -17,12 +17,12 @@ Example Configuration
 
 	-- Configure the client part of the resolver. Set 8 bytes of the client
 	-- secret and choose the hashing algorithm to be used.
-	cookies.config( { ['client_secret'] = { 0, 1, 2, 3, 4, 5, 6, 7 },
+	-- Use a string composed of hexadecimal digits to set the secret.
+	cookies.config( { ['client_secret'] = '0123456789ABCDEF',
 	                  ['client_cookie_alg'] = 'FNV-64' } )
 
-	-- Configure the server part of the resolver. Sets a string to be used
-	-- as server secret. Also chooses the hashing algorithm to be used.
-	cookies.config( { ['server_secret'] = 'secret key',
+	-- Configure the server part of the resolver.
+	cookies.config( { ['server_secret'] = 'FEDCBA9876543210',
 	                  ['server_cookie_alg'] = 'FNV-64' } )
 
 	-- Enable client cookie functionality. (Add cookies into outbound
@@ -43,7 +43,7 @@ Properties
 .. function:: cookies.config(configuration)
 
   :param table configuration: part of cookie configuration to be changed, may be called without parameter
-  :return: JSON dictionary containing corrent configuration
+  :return: JSON dictionary containing current configuration
 
   The function may be called without any parameter. In such case it only returns current configuration. The returned JSON alsao contains available algorithm choices.
 
diff --git a/modules/cookies/cookiectl.c b/modules/cookies/cookiectl.c
index fbb87e9bace989097d04f92b6dcfa39bcc049c85..8ffaf2d2eb3cdaae1d511933762d2bcacf06451f 100644
--- a/modules/cookies/cookiectl.c
+++ b/modules/cookies/cookiectl.c
@@ -16,6 +16,7 @@
 
 #include <assert.h>
 #include <ccan/json/json.h>
+#include <ctype.h>
 #include <libknot/rrtype/opt-cookie.h>
 #include <libknot/db/db_lmdb.h>
 #include <stdlib.h>
@@ -86,48 +87,126 @@ static struct kr_cookie_secret *new_cookie_secret(size_t size, bool zero)
 	return sq;
 }
 
-static struct kr_cookie_secret *new_sq_str(const JsonNode *node)
+static int hexchar2val(int d)
 {
-	assert(node && node->tag == JSON_STRING);
+	if (('0' <= d) && (d <= '9')) {
+		return d - '0';
+	} else if (('a' <= d) && (d <= 'f')) {
+		return d - 'a' + 0x0a;
+	} else {
+		return -1;
+	}
+}
 
-	size_t len = strlen(node->string_);
+static int hexval2char(int i)
+{
+	if ((0 <= i) && (i <= 9)) {
+		return i + '0';
+	} if ((0x0a <= i) && (i <= 0x0f)) {
+		return i - 0x0a + 'A';
+	} else {
+		return -1;
+	}
+}
 
-	struct kr_cookie_secret *sq = new_cookie_secret(len, false);
-	if (!sq) {
-		return NULL;
+/**
+ * @brief Converts string containing two-digit hexadecimal number into int.
+ * @param hexstr hexadecimal string
+ * @return -1 on error, value from 0 to 255 else.
+ */
+static int hexbyte2int(const char *hexstr)
+{
+	if (!hexstr) {
+		return -1;
 	}
-	memcpy(sq->data, node->string_, len);
 
-	return sq;
+	int dhi = tolower(hexstr[0]);
+	if (!isxdigit(dhi)) {
+		/* Exit also on empty string. */
+		return -1;
+	}
+	int dlo = tolower(hexstr[1]);
+	if (!isxdigit(dlo)) {
+		return -1;
+	}
+
+	dhi = hexchar2val(dhi);
+	assert(dhi != -1);
+	dlo = hexchar2val(dlo);
+	assert(dlo != -1);
+
+	return (dhi << 4) | dlo;
 }
 
-#define holds_char(x) ((x) >= 0 && (x) <= 255)
+/**
+ * @brief Writes two hexadecimal digits (two byes) into given memory location.
+ * @param tgt target location
+ * @param i number from 0 to 255
+ * @return 0 on success, -1 on failure
+ */
+static int int2hexbyte(char *tgt, int i)
+{
+	if (!tgt || i < 0x00 || i > 0xff) {
+		return -1;
+	}
+
+	int ilo = hexval2char(i & 0x0f);
+	assert(ilo != -1);
+	int ihi = hexval2char((i >> 4) & 0x0f);
+	assert(ihi != -1);
 
-static struct kr_cookie_secret *new_sq_array(const JsonNode *node)
+	tgt[0] = ihi;
+	tgt[1] = ilo;
+
+	return 0;
+}
+
+/**
+ * @brief Reads a string containing hexadecimal values.
+ * @note String must consist of hexadecimal digits only and must have even
+ *       non-zero length.
+ */
+static struct kr_cookie_secret *new_sq_from_hexstr(const JsonNode *node)
 {
-	assert(node && node->tag == JSON_ARRAY);
+	assert(node && node->tag == JSON_STRING);
 
-	const JsonNode *element = NULL;
-	size_t cnt = 0;
-	json_foreach(element, node) {
-		if (element->tag != JSON_NUMBER || !holds_char(element->number_)) {
-			return NULL;
-		}
-		++cnt;
-	}
-	if (cnt == 0) {
+	size_t len = strlen(node->string_);
+	if ((len % 2) != 0) {
 		return NULL;
 	}
 
-	struct kr_cookie_secret *sq = new_cookie_secret(cnt, false);
+	struct kr_cookie_secret *sq = new_cookie_secret(len / 2, false);
 	if (!sq) {
 		return NULL;
 	}
 
-	cnt = 0;
-	json_foreach(element, node) {
-		sq->data[cnt++] = (uint8_t) element->number_;
+	const char *hexstr = node->string_;
+	uint8_t *data = sq->data;
+	for (int i = 0; i < len; i += 2) {
+		int num = hexbyte2int(hexstr + i);
+		if (num == -1) {
+			free(sq);
+			return NULL;
+		}
+		assert(0x00 <= num && num <= 0xff);
+		*data = num;
+		++data;
+	}
+
+	return sq;
+}
+
+static struct kr_cookie_secret *new_sq_str(const JsonNode *node)
+{
+	assert(node && node->tag == JSON_STRING);
+
+	size_t len = strlen(node->string_);
+
+	struct kr_cookie_secret *sq = new_cookie_secret(len, false);
+	if (!sq) {
+		return NULL;
 	}
+	memcpy(sq->data, node->string_, len);
 
 	return sq;
 }
@@ -147,10 +226,7 @@ static bool apply_secret_shallow(struct kr_cookie_secret **sec,
 
 	switch (node->tag) {
 	case JSON_STRING:
-		sq = new_sq_str(node);
-		break;
-	case JSON_ARRAY:
-		sq = new_sq_array(node);
+		sq = new_sq_from_hexstr(node);
 		break;
 	default:
 		break;
@@ -224,33 +300,55 @@ static bool apply_configuration_shallow(struct kr_cookie_ctx *cntrl,
 	return false;
 }
 
+/**
+ * @brief Creates a new string from secret quantity.
+ * @param sq secret quantity
+ * @return newly allocated string or NULL on error
+ */
+static char *new_hexstr_from_sq(const struct kr_cookie_secret *sq)
+{
+	if (!sq) {
+		return NULL;
+	}
+
+	char *new_str = malloc((sq->size * 2) + 1);
+	if (!new_str) {
+		return NULL;
+	}
+
+	char *tgt = new_str;
+	for (size_t i = 0; i < sq->size; ++i) {
+		if (0 != int2hexbyte(tgt, sq->data[i])) {
+			free(new_str);
+			return NULL;
+		}
+		tgt += 2;
+	}
+
+	*tgt = '\0';
+	return new_str;
+}
+
 static bool read_secret(JsonNode *root, const char *node_name,
                         const struct kr_cookie_secret *secret)
 {
 	assert(root && node_name && secret);
 
-	JsonNode *array = json_mkarray();
-	if (!array) {
+	char *secret_str = new_hexstr_from_sq(secret);
+	if (!secret_str) {
 		return false;
 	}
 
-	for (size_t i = 0; i < secret->size; ++i) {
-		JsonNode *element = json_mknumber(secret->data[i]);
-		if (!element) {
-			goto fail;
-		}
-		json_append_element(array, element);
+	JsonNode *str_node = json_mkstring(secret_str);
+	if (!str_node) {
+		free(secret_str);
+		return false;
 	}
 
-	json_append_member(root, node_name, array);
+	json_append_member(root, node_name, str_node);
 
+	free(secret_str);
 	return true;
-
-fail:
-	if (array) {
-		json_delete(array);
-	}
-	return false;
 }
 
 static bool read_available_hashes(JsonNode *root, const char *root_name,