You're not supposed to encode 'expires='. It will turn into 'expires%3D', which is not what you want. In addition to that, it might be a bad idea to use 'encodeURI', because it does not encode ';' and ',' as required.
You can use encodeURIComponent for encoding the cookie value, but it would be technically correct to use escape() to encode the cookie value.
So...
document.cookie = "count=" + encodeURIComponent(count.toString()) + "; expires=" + exDate.toUTCString();
...should do what you want.
The cookie consists of several parts; we're mostly interested in the name, the value and the expiry date.
(End of official answer)
Let's clear up the confusion on encoding cookies
If ever in doubt, contact the RFC, do not just pick anything you find on the Web that seems to work.
The cookie-name is of type token, which means that only these values are allowed within it:
0x21-0x27, 0x2A-0x2B, 0x2D-0x2E, 0x30-0x39, 0x41-0x5A, 0x5E-0x7A and 0x7E.
In other words: The following values should be percent-encoded:
0x00-0x20, '(', ')', ',', '/', ':', ';', '<', '=', '>', '?', '@', '', '[', ']', '{', '}' and 0x7F-0xFF.
The cookie-value is of type cookie-octet, which means that only these values are allowed within it:
0x21, 0x23-0x2B, 0x2D-0x3A, 0x3C-0x5B, 0x5D-0x7E.
In other words: The following values should be percent-encoded:
0x00-0x20, 0x22, ',', ';', '' and 0x7F-0xFF.
Now, the expiry date is encoded using toUTCString(), as you're correctly doing.
The result looks something like this: Wed, 09 Jun 2021 10:18:14 GMT
-So it will contain a comma. BUT! You're not supposed to encode anything, except the cookie-name and cookie-value strings.
Note: W3Schools says that escape() was deprecated in JavaScript 1.5, but it is technically incorrect to use encodeURI() or encodeURIComponent() for cookies. It is technically correct to use escape() for cookies.
RFC 6265 section 5.4 clearly states:
NOTE: Despite its name, the cookie-string is actually a sequence of
octets, not a sequence of characters. To convert the cookie-string
(or components thereof) into a sequence of characters (e.g., for
presentation to the user), the user agent might wish to try using the
UTF-8 character encoding [RFC3629] to decode the octet sequence.
This decoding might fail, however, because not every sequence of octets is valid UTF-8.
As decodeURIComponent() is for unicode strings, and choke on byte values between 0x00 and 0xFF, they can not safely be used. On the other hand, unescape() is not for strings, but for 8-bit byte-sequences, aka. octets, but only if your byte-sequences do not contain unicode characters.
If your cookie value contains unicode characters, you should however, use encodeURIComponent()/decodeURIComponent(), but you should also catch any exceptions, because the server may not send you exactly what you want to receive.
Answer from user1985657 on Stack OverflowUsing decodeURI with cookies javascript - Stack Overflow
How to see unserialised/decoded cookie value instead of unserialized value in chrome dev tools? - Stack Overflow
Decoding Cookie Using cookie-parser
Browser.cookie.get decoding url encoded cookie values?
What are cookie attributes?
How do I parse a cookie string?
What is an HttpOnly cookie?
in PHP, I use setCookie to store a cookie. The value of the cookie contains embedded spaces, so the cookie is being stored with "+" in place of the embedded spaces.
$cookieName = 'steve25' ; $cookieValue = 'non wave item' ; setcookie( $cookieName, $cookieValue, time() + (86400 * 30), "/"); // 86400 = 1 day
Then in javascript I use document.cookie to access all the cookies. And I run decodeURIComponent, hoping to convert those embedded "+" characters back to spaces. But the "+" characters remain.
function getCookie(name)
{
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length == 2)
{
const vlu = parts.pop().split(";").shift();
const decode_vlu = decodeURIComponent(vlu) ;
console.log('decode_vlu') ;
const replace_vlu = decode_vlu.replace(/[+]/g, ' ');
return replace_vlu ;
}
else
return '' ;
}What is the browser API I should use to decode a cookie value?
thanks,
You're not supposed to encode 'expires='. It will turn into 'expires%3D', which is not what you want. In addition to that, it might be a bad idea to use 'encodeURI', because it does not encode ';' and ',' as required.
You can use encodeURIComponent for encoding the cookie value, but it would be technically correct to use escape() to encode the cookie value.
So...
document.cookie = "count=" + encodeURIComponent(count.toString()) + "; expires=" + exDate.toUTCString();
...should do what you want.
The cookie consists of several parts; we're mostly interested in the name, the value and the expiry date.
(End of official answer)
Let's clear up the confusion on encoding cookies
If ever in doubt, contact the RFC, do not just pick anything you find on the Web that seems to work.
The cookie-name is of type token, which means that only these values are allowed within it:
0x21-0x27, 0x2A-0x2B, 0x2D-0x2E, 0x30-0x39, 0x41-0x5A, 0x5E-0x7A and 0x7E.
In other words: The following values should be percent-encoded:
0x00-0x20, '(', ')', ',', '/', ':', ';', '<', '=', '>', '?', '@', '', '[', ']', '{', '}' and 0x7F-0xFF.
The cookie-value is of type cookie-octet, which means that only these values are allowed within it:
0x21, 0x23-0x2B, 0x2D-0x3A, 0x3C-0x5B, 0x5D-0x7E.
In other words: The following values should be percent-encoded:
0x00-0x20, 0x22, ',', ';', '' and 0x7F-0xFF.
Now, the expiry date is encoded using toUTCString(), as you're correctly doing.
The result looks something like this: Wed, 09 Jun 2021 10:18:14 GMT
-So it will contain a comma. BUT! You're not supposed to encode anything, except the cookie-name and cookie-value strings.
Note: W3Schools says that escape() was deprecated in JavaScript 1.5, but it is technically incorrect to use encodeURI() or encodeURIComponent() for cookies. It is technically correct to use escape() for cookies.
RFC 6265 section 5.4 clearly states:
NOTE: Despite its name, the cookie-string is actually a sequence of
octets, not a sequence of characters. To convert the cookie-string
(or components thereof) into a sequence of characters (e.g., for
presentation to the user), the user agent might wish to try using the
UTF-8 character encoding [RFC3629] to decode the octet sequence.
This decoding might fail, however, because not every sequence of octets is valid UTF-8.
As decodeURIComponent() is for unicode strings, and choke on byte values between 0x00 and 0xFF, they can not safely be used. On the other hand, unescape() is not for strings, but for 8-bit byte-sequences, aka. octets, but only if your byte-sequences do not contain unicode characters.
If your cookie value contains unicode characters, you should however, use encodeURIComponent()/decodeURIComponent(), but you should also catch any exceptions, because the server may not send you exactly what you want to receive.
Most browsers also support btoa for encoding in Base64 and atob for decoding Base64. All characters in Base64 are legal cookie-octets (when interpreted in ASCII or UTF-8). So you can (at the cost of additional storage space) store a Base64 encoding of your persistent value as the cookie value, encoding (and decoding) as you persist (and retrieve) the value.
It was not developed yet in Chrome, So I opened a ticket at Chromium and it was implemented after a year in next releases.
Link to the ticket: https://bugs.chromium.org/p/chromium/issues/detail?id=997625
Now I have the required feature in Chrome and Edge Browsers also.

Tab => Application => Storage => Cookies

It seems the signature could not be validated between the string and the supplied secret. Note the syntax is:
cookieParser.signedCookie(str, secret);
See this reference, which says both,
If the value was not signed, the original value is returned.
and
If the value was signed but the signature could not be validated, false is returned.
TL;DR: Your cookie value is URL encoded and that won't work with cookie-parser until you decode it.
I'm assuming you used express's res.cookie() method to set and sign the original cookie. This requires you also make use of the second-party cookie-parser middleware, per express's documentation for res.cookie:
When using cookie-parser middleware, this method also supports signed cookies. Simply include the signed option set to true. Then res.cookie() will use the secret passed to cookieParser(secret) to sign the value.
When express signs a cookie, it appends a ":s" to the front of the cookie. Here's the bit of code from express's response.js on GitHub:
if (signed) {
val = 's:' + sign(val, secret);
}
So. It appears your cookie value was encoded when it was originally set (by default, express uses encodeURIComponent). The encoded value of ":s" becomes "%3s", and your cookie value you provided begins s%3Ak0tBm...
Providing an encoded value to cookie-parser.signedCookie will not work, as you can see if you inspect its code:
if (str.substr(0, 2) !== 's:') {
return str
}
If you're using cookie-parser as express middleware upstream from the code in question, cookie values will be properly decoded by the middleware and available to you at req.signedCookies. But if you're using the signedCookie method ad-hoc, you'll need to decode it yourself first, i.e. decodeURIComponent.
Lastly, you can also take a look at the encode option you can provide to res.cookie for a roll-your-own encoding option.
Once you're able to provide a properly decoded value to cookie-parser, it'll properly parse your signed cookie value.
my guess is missing URI decode/encode
The decodeURIComponent() function decodes a Uniform Resource Identifier (URI) component previously created by encodeURIComponent or by a similar routine.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent
I ended up with this :
let x = document.cookie
let decodit = decodeURIComponent(x).split(":").toString()
let sliceit = decodit.slice(7, 31)
Thanks csx.cc ...your answer led me in the right direction.
I'm using express and cookie parser. After reading about how they encode the cookie, I found an answer on stackoverflow.com and here is the answer (I upvoted the answer and anyone reading this should do the same. Link to the answer at the end)
Note on external libraries: If you decide to use the express, cookie-parser, or cookie, note they have defaults that are non-standard. Cookies parsed are always URI Decoded (percent-decoded). That means if you use a name or value that has any of the following characters: !#$%&'()*+/:<=>?@[]^`{|} they will be handled differently with those libraries. If you're setting cookies, they are encoded with %{HEX}. And if you're reading a cookie you have to decode them.
For example, while [email protected] is a valid cookie, these libraries will encode it as email=name%40domain.com. Decoding can exhibit issues if you are using the % in your cookie. It'll get mangled. For example, your cookie that was: secretagentlevel=50%007and50%006 becomes secretagentlevel=507and506. That's an edge case, but something to note if switching libraries.
Also, on these libraries, cookies are set with a default path=/ which means they are sent on every url request to the host.
If you want to encode or decode these values yourself, you can use encodeURIComponent or decodeURIComponent, respectively.
Answer by ShortFuse: Get and Set a Single Cookie with Node.js HTTP Server
Since Chrome version 80 and higher, cookies are encrypted using AES-256 in GCM mode. The applied key is encrypted using DPAPI. The details are described here, section Chrome v80.0 and higher.
The encrypted key starts with the ASCII encoding of DPAPI (i.e. 0x4450415049) and is Base64 encoded, i.e. the key must first be Base64 decoded and the first 5 bytes must be removed. Afterwards a decryption with win32crypt.CryptUnprotectData is possible. The decryption returns a tuple whose second value contains the decrypted key:
import os
import json
import base64
import win32crypt
from Crypto.Cipher import AES
path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = base64.b64decode(encrypted_key) # Base64 decoding
encrypted_key = encrypted_key[5:] # Remove DPAPI
decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1] # Decrypt key
The encryption of the cookies is performed with AES-256 in GCM mode. This is authenticated encryption, which guarantees confidentiality and authenticity/integrity. During encryption an authentication tag is generated, which is used for integrity verification during decryption. The GCM mode is based on the CTR mode and uses an IV (nonce). In addition to the 32 bytes key, the nonce and the authentication tag are required for decryption.
The encrypted data start with the ASCII encoding of v10 (i.e. 0x763130), followed by the 12 bytes nonce, the actual ciphertext and finally the 16 bytes authentication tag. The individual components can be separated as follows:
data = bytes.fromhex('763130...') # the encrypted cookie
nonce = data[3:3+12]
ciphertext = data[3+12:-16]
tag = data[-16:]
whereby data contains the encrypted data. The decryption itself is done using PyCryptodome with:
cipher = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie
Note: Generally, there are also cookies stored that have been saved with Chrome versions below v80 and are therefore DPAPI encrypted. DPAPI encrypted cookies can be recognized by the fact that they start with the sequence 0x01000000D08C9DDF0115D1118C7A00C04FC297EB, here and here, section About DPAPI. These cookies can of course not be decrypted as described above, but with the former procedure for DPAPI encrypted cookies. Tools to view cookies in unencrypted or encrypted form are ChromeCookiesView or DB Browser for SQLite, respectively.
Probably you have copied the DPAPI encrypted key value from one user account on Windows and are trying to call CryptUnprotectData WinAPI while logged on as another user. This will not work, by nature of DPAPI.