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 Overflow
🌐
URL Decode
urldecoder.org › dec › cookie
URL Decoding of "cookie" - Online
Decode cookie from URL-encoded format with various advanced options. Our site has an easy to use online tool to convert your data.
🌐
Scrapfly
scrapfly.io › web-scraping-tools › cookie-parser
Cookie Header Parser - Parse & Decode HTTP Cookies
Parse, decode, and analyze HTTP Cookie and Set-Cookie headers for web scraping and debugging. This tool parses Cookie request headers and Set-Cookie response headers, showing each cookie with its value, attributes, and decoded version.
Discussions

Using decodeURI with cookies javascript - Stack Overflow
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, ... More on stackoverflow.com
🌐 stackoverflow.com
How to see unserialised/decoded cookie value instead of unserialized value in chrome dev tools? - Stack Overflow
In chrome, I can see cookies in Application section but it's showing raw data as follows: But I want it to see the value, not raw data, I mean the data in form of array or JSON, is this possible in More on stackoverflow.com
🌐 stackoverflow.com
Decoding Cookie Using cookie-parser
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. More on stackoverflow.com
🌐 stackoverflow.com
Browser.cookie.get decoding url encoded cookie values?
It seems to me that setting a url encoded cookie with browser.cookie.set works great at saving the value in it’s url encoded state. However, getting the same cookie decodes the value for some reason? Is this expected? I could not find any documentation on it. let cookie = `bizbaz=${encod... More on community.shopify.dev
🌐 community.shopify.dev
1
1
February 20, 2025
People also ask

What are cookie attributes?
Cookie attributes control scope and security: Path limits which URLs receive the cookie, Domain specifies which hosts can read it, Expires/Max-Age sets the lifetime, HttpOnly blocks JavaScript access, Secure restricts transmission to HTTPS, and SameSite controls cross-site sending behavior (Strict, Lax, or None).
🌐
theproductguy.in
theproductguy.in › home › blogs › cookie parser: decode browser cookies
Cookie Parser: Decode Browser Cookies | theproductguy.in
How do I parse a cookie string?
To parse a cookie string, split the string on semicolons — the first segment is the name=value pair, and each subsequent segment is an attribute. Online cookie parsers automate this: paste a raw Set-Cookie or Cookie header value and get each attribute annotated with its meaning and security impact.
🌐
theproductguy.in
theproductguy.in › home › blogs › cookie parser: decode browser cookies
Cookie Parser: Decode Browser Cookies | theproductguy.in
What is an HttpOnly cookie?
An HttpOnly cookie has the HttpOnly flag set, which prevents client-side JavaScript from reading it via document.cookie. This is the primary defense against session token theft via XSS attacks — even if an attacker injects JavaScript, they cannot exfiltrate the token. All session cookies should be HttpOnly.
🌐
theproductguy.in
theproductguy.in › home › blogs › cookie parser: decode browser cookies
Cookie Parser: Decode Browser Cookies | theproductguy.in
🌐
Reddit
reddit.com › r/webdev › how to decode cookie value in javascript?
r/webdev on Reddit: how to decode cookie value in javascript?
March 13, 2019 -

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,

🌐
Degoogle
kirsle.net › wizards › flask-session.cgi
Flask Session Cookie Decoder
if "css" in form: return css() # Print the header for all HTML pages. print("Content-Type: text/html\n\n",) # Template variables. action = form.get("action", "index") cookie = form.get("cookie", "") contents = None pretty = None code = pygments.highlight(source(), PythonLexer(), HtmlFormatter()) # Submitted the form? if action == "decode": contents = decode(cookie) # Test whether it's JSON data. try: json_contents = flask_loads(contents) # Pretty-print it. pretty = json.dumps(json_contents, sort_keys=True, indent=4, separators=(',', ': ')) pretty = pygments.highlight(pretty, JsonLexer(), HtmlF
🌐
Theproductguy
theproductguy.in › home › blogs › cookie parser: decode browser cookies
Cookie Parser: Decode Browser Cookies | theproductguy.in
February 3, 2026 - Parse and inspect cookie strings — decode values, check attributes, and understand SameSite, HttpOnly, Secure.
🌐
Base64Encode.org
base64encode.org › enc › cookies
Base64 Encoding of "cookies" - Online
Encode cookies to Base64 format with various advanced options. Our site has an easy to use online tool to convert your data.
Find elsewhere
Top answer
1 of 2
12

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.

2 of 2
2

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.

🌐
GitHub
github.com › chmike › securecookie
GitHub - chmike/securecookie: Fast, secure and efficient secure cookie encoder/decoder · GitHub
This package provides functions to encode and decode secure cookie values.
Starred by 87 users
Forked by 12 users
Languages   Go
Top answer
1 of 2
2

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.

2 of 2
0

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.

🌐
Shopify Developer Community
community.shopify.dev › web pixels
Browser.cookie.get decoding url encoded cookie values? - Web Pixels - Shopify Developer Community Forums
February 20, 2025 - It seems to me that setting a url encoded cookie with browser.cookie.set works great at saving the value in it’s url encoded state. However, getting the same cookie decodes the value for some reason? Is this expected? I could not find any documentation on it. let cookie = `bizbaz=${encodeURIComponent('foo:bar')}` // cookie = 'bizbaz=foo:bar' browser.cookie.set(cookie); const cookie2 = await browser.cookie.get('bizbaz'); // cookie2 = 'foo:bar'
🌐
Quora
quora.com › Is-it-possible-to-decode-a-session-cookie
Is it possible to decode a session cookie? - Quora
Below is a concise breakdown of typical cases, what “decoding” means in each, how to proceed, and security/ethical considerations. ... Opaque identifier: a random token (e.g., "sid=3f2a...") that maps to server-side session data stored in a database or in-memory store. The cookie itself contains no usable state. Signed cookie: contains data (JSON, key-value...
🌐
Ktor
api.ktor.io › ktor-http › io.ktor.http › decode-cookie-value.html
decodeCookieValue
Decode cookie value using the specified encoding · Report a problem · Generated by Dokka · © 2026 JetBrains s.r.o and contributors.
Top answer
1 of 2
1

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

2 of 2
0

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

Top answer
1 of 2
31

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.

2 of 2
-1

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.

🌐
Toolsfornerds
toolsfornerds.net › cookie-parser
HTTP Cookie Parser & Decoder | ToolsForNerds
name1=value1; name2=value2; name3=value3 · Set-Cookie format (with attributes): sessionid=abc123; expires=Wed, 09 Jun 2025 10:18:14 GMT; path=/; Secure; HttpOnly · Parse and decode HTTP cookie strings from browser DevTools or request headers into readable JSON format.
🌐
GitHub
github.com › Moustachauve › cookie-editor › discussions › 130
base64 encode or decode cookie values · Moustachauve/cookie-editor · Discussion #130
Cookies are typically base64 or URL encoded. As a software developer, displaying the decoded value would significantly enhance efficiency. Moreover, having the capability to swiftly encode a provid...
Author   Moustachauve