Create a cookie in JavaScript
Tested on |
Firefox (3.0, 3.6, 30, 31) |
Chrome (5, 34, 36) |
IE (6, 7, 8, 11) |
Objective
To create a cookie from within a web page using JavaScript
Scenario
Suppose that you wish to create a session cookie named foo
. Its value should be set to the content of the variable named cookieValue
, which contains a Unicode character string. You would normally expect the string to be composed of printable characters from the Basic Latin block (%20 to %7E), however you want to avoid placing any hard constraints on its content.
The cookie need only be readable from the page that created it, and does not contain security-sensitive information.
Method
Overview
The basic method described here has three steps:
- Optionally, encode the cookie value to avoid forbidden characters.
- Express the cookie as a name-value pair.
- Assign the resulting string to
document.cookie
.
For example:
document.cookie = 'foo=' + encodeURIComponent(cookieValue);
You may also need to do some or all of the following:
- Define the scope of the cookie (path and/or domain).
- Specify when the cookie should expire.
- Limit the cookie to transmission over secure channels.
Note that a cookie created via HTTP with the httponly
attribute cannot be overwritten using the JavaScript API.
Optionally, encode the cookie value to avoid forbidden characters
For portability the value of a cookie should be limited to printable US-ASCII characters and should not include any of the following:
Code | Name |
---|---|
%20 | space |
%22 | quotation mark |
%2C | comma |
%3B | semicolon |
%5C | backslash |
It may be that the nature of the content ensures this as a matter of course, but otherwise the value will need to be encoded in some way. Commonly-used methods include:
- URI encoding. This is quite efficient if most of the characters are already in the allowed range, but very inefficient in the worst case. JavaScript provides the function
encodeURIComponent
, which had been part of the ECMAScript standard since 1999 (3rd edition), and which escapes all of the characters that need to be. Unicode strings are handled appropriately. - Base 64 encoding. This causes US-ASCII text to expand by a fixed factor of 4/3 (approximately 33%) regardless of content. Both of the common variants (base64 and base64url as defined by RFC 4648) use cookie-safe character sets. Some implementations of JavaScript provide the function
Window.atob
for encoding to the base64 variant. At the time of writing it had not been formally standardised, however brower support is generally good (with the notable exception of Internet Explorer prior to IE10).Window.btoa
does not support the encoding of arbitrary Unicode characters without first converting them to UTF-8.
Since cookies do not normally need to be readable by third-party code you are free to choose an encoding scheme to suit your needs. RFC 6265 offers base64 as an example, but does not mandate any particular method.
In this instance, given the nature of the cookie value described in the scenario above, encodeURIComponent
would be an appropriate choice:
encodeURIComponent(cookieValue);
Express the cookie as a name-value pair
The cookie should then be expressed as a name-value pair of the form <name>=<value>
:
var cookieString = 'foo=' + encodeURIComponent(cookieValue);
This is the textual representation of a cookie with no attributes, and could be used (for example) in an HTTP Set-Cookie
header.
Assign the name-value pair to document.cookie
From JavaScript, cookies can be set or inspected using the cookie
property of the global document
object. Be aware that this does not behave like an ordinary variable:
- When read it returns a semicolon-separated list of all cookies that are associated with the current document.
- When written to it expects data for a single cookie, which is created or updated as appropriate. Other cookies are left unchanged.
There is no need to splice the new cookie into the existing list (and in fact you must not do that). Rather, assignment of the key-value pair prepared above will suffice:
document.cookie = cookieString;
If there is an existing cookie with the same name, path and domain then it will be replaced. Otherwise, a new cookie is created.
Variations
Define the scope of the cookie (path and/or domain)
By default, a cookie created by a web page at a given URI is accessible to other pages in the same directory, and to pages in subdirectories of the same directory. For example, a cookie created by /foo/bar.html
is accessible to /foo/baz.html
and /foo/qux/baz.html
, but not to /baz.html
.
This behavior has the virtue of being safe when there are multiple independent websites operating from the same domain, but in practice most modern websites place cookies at the root of the domain so that they are visible from all paths. You can arrange this by setting the path
attribute:
var cookieString = 'foo=' + encodeURIComponent(cookieValue); cookieString += ';path=/'; document.cookie = cookieString;
With regard to the domain, the default behaviour is to make the cookie visible only to pages within the same domain and not to any subdomains. This is appropriate for most websites. The alternative is to explicitly set the domain
attribute, in which case subdomains are included. For example:
var cookieString = 'foo=' + encodeURIComponent(cookieValue); cookieString += ';path=/'; cookieString += ';domain=example.com'; document.cookie = cookieString;
would make the cookie visible from subdomains such as www.example.com
in addition to example.com
itself. This would be appropriate if, for example, you wanted to implement cookie-based single sign-on authentication throughout a collection of subdomains.
(Be aware that most web browsers will prevent you from setting cookies on domains such as com
or co.uk
for security reasons. As a rule of thumb, you should not try to associate domains in this way unless you own the parent domain.)
Specify when the cookie should expire
Cookies are non-persistent by default, meaning that they live for the duration of a browser session. They can be made to live longer by appending a max-age
attribute which specifies the required lifespan in seconds. For compatibility with Internet Explorer you may also want to append an expires
attribute. (max-age
takes precedence if it is present and supported.)
The required attribute formats are max-age=<max-age>
and expires=<date>
, where <max-age>
is the maximum number of seconds for which the cookie should live, and <date>
is the date when the cookie should expire. The preferred format for the expiry date is an RFC 1123 date string. For example, if a cookie were being set at Sun, 20 Jul 2014 12:00:00 GMT and was supposed to last for one day then the appropriate attribute strings would be max-age=86400
and expires=Mon, 21 Jul 2014 12:00:00 GMT
.
For expiry after maxAge
seconds:
var cookieString = 'foo=' + encodeURIComponent(cookieValue); var maxAge = 3600; // the required lifespan in seconds var expiryDate = new Date(); expiryDate.setTime(expiryDate.getTime() + maxAge * 1000); cookieString += ';max-age=' + maxAge; cookieString += ';expires=' + expiryDate.toUTCString(); document.cookie = cookieString;
You should avoid using Date.toGMTString
to encode the expiry date, as that method is deprecated.
Be aware that web browsers are not obliged to keep cookies until their requested expiry dates (or indeed, to accept them in the first place). RFC 6265 cautions against gratuitously long expiry periods, due to the adverse effect on user privacy.
Limit the cookie to transmission over secure channels
By default, a cookie will be presented as part of any HTTP request with a matching domain and path. Consequently, it is possible for information sent to the client via a secure connection to be returned using plain HTTP. This is obviously not a desirable outcome if the content is security sensitive.
Setting the secure
attribute of the cookie prevents this from happening:
var cookieString = 'foo=' + encodeURIComponent(cookieValue); cookieString += ';secure'; document.cookie = cookieString;
See Also
Further Reading
- Document.cookie, Web API Interfaces, Mozilla Developer Network
- A. Barth, HTTP State Management Mechanism, RFC 6265, IETF, April 2011
- Persistent Client State HTTP Cookies, Netscape (historical specification)
- Cookies, QuirksMode
(Note that RFC 6265 and the Netscape specification technically refer to setting cookies via HTTP and not from JavaScript. In practice you can overlook this distinction for most purposes, and must do if you want more detail than the very limited amount of documentation available for the JavaScript API.)
Tags: cookie | javascript