| 1 | # tough-cookie
|
|---|
| 2 |
|
|---|
| 3 | [RFC 6265](https://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js
|
|---|
| 4 |
|
|---|
| 5 | [](https://nodei.co/npm/tough-cookie/)
|
|---|
| 6 |
|
|---|
| 7 | [](https://travis-ci.org/salesforce/tough-cookie)
|
|---|
| 8 |
|
|---|
| 9 | ## Synopsis
|
|---|
| 10 |
|
|---|
| 11 | ```javascript
|
|---|
| 12 | var tough = require("tough-cookie");
|
|---|
| 13 | var Cookie = tough.Cookie;
|
|---|
| 14 | var cookie = Cookie.parse(header);
|
|---|
| 15 | cookie.value = "somethingdifferent";
|
|---|
| 16 | header = cookie.toString();
|
|---|
| 17 | var cookiejar = new tough.CookieJar();
|
|---|
| 18 |
|
|---|
| 19 | // Asynchronous!
|
|---|
| 20 | var cookie = await cookiejar.setCookie(
|
|---|
| 21 | cookie,
|
|---|
| 22 | "https://currentdomain.example.com/path"
|
|---|
| 23 | );
|
|---|
| 24 | var cookies = await cookiejar.getCookies("https://example.com/otherpath");
|
|---|
| 25 |
|
|---|
| 26 | // Or with callbacks!
|
|---|
| 27 | cookiejar.setCookie(
|
|---|
| 28 | cookie,
|
|---|
| 29 | "https://currentdomain.example.com/path",
|
|---|
| 30 | function (err, cookie) {
|
|---|
| 31 | /* ... */
|
|---|
| 32 | }
|
|---|
| 33 | );
|
|---|
| 34 | cookiejar.getCookies("http://example.com/otherpath", function (err, cookies) {
|
|---|
| 35 | /* ... */
|
|---|
| 36 | });
|
|---|
| 37 | ```
|
|---|
| 38 |
|
|---|
| 39 | Why the name? NPM modules `cookie`, `cookies` and `cookiejar` were already taken.
|
|---|
| 40 |
|
|---|
| 41 | ## Installation
|
|---|
| 42 |
|
|---|
| 43 | It's _so_ easy! Install with `npm` or your preferred package manager.
|
|---|
| 44 |
|
|---|
| 45 | ```sh
|
|---|
| 46 | npm install tough-cookie
|
|---|
| 47 | ```
|
|---|
| 48 |
|
|---|
| 49 | ## Node.js Version Support
|
|---|
| 50 |
|
|---|
| 51 | We follow the [node.js release schedule](https://github.com/nodejs/Release#release-schedule) and support all versions that are in Active LTS or Maintenance. We will always do a major release when dropping support for older versions of node, and we will do so in consultation with our community.
|
|---|
| 52 |
|
|---|
| 53 | ## API
|
|---|
| 54 |
|
|---|
| 55 | ### tough
|
|---|
| 56 |
|
|---|
| 57 | The top-level exports from `require('tough-cookie')` can all be used as pure functions and don't need to be bound.
|
|---|
| 58 |
|
|---|
| 59 | #### `parseDate(string)`
|
|---|
| 60 |
|
|---|
| 61 | Parse a cookie date string into a `Date`. Parses according to [RFC 6265 Section 5.1.1](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1), not `Date.parse()`.
|
|---|
| 62 |
|
|---|
| 63 | #### `formatDate(date)`
|
|---|
| 64 |
|
|---|
| 65 | Format a `Date` into an [RFC 822](https://datatracker.ietf.org/doc/html/rfc822#section-5) string (the RFC 6265 recommended format).
|
|---|
| 66 |
|
|---|
| 67 | #### `canonicalDomain(str)`
|
|---|
| 68 |
|
|---|
| 69 | Transforms a domain name into a canonical domain name. The canonical domain name is a domain name that has been trimmed, lowercased, stripped of leading dot, and optionally punycode-encoded ([Section 5.1.2 of RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.2)). For the most part, this function is idempotent (calling the function with the output from a previous call returns the same output).
|
|---|
| 70 |
|
|---|
| 71 | #### `domainMatch(str, domStr[, canonicalize=true])`
|
|---|
| 72 |
|
|---|
| 73 | Answers "does this real domain match the domain in a cookie?". The `str` is the "current" domain name and the `domStr` is the "cookie" domain name. Matches according to [RFC 6265 Section 5.1.3](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3), but it helps to think of it as a "suffix match".
|
|---|
| 74 |
|
|---|
| 75 | The `canonicalize` parameter toggles whether the domain parameters get normalized with `canonicalDomain` or not.
|
|---|
| 76 |
|
|---|
| 77 | #### `defaultPath(path)`
|
|---|
| 78 |
|
|---|
| 79 | Given a current request/response path, gives the path appropriate for storing in a cookie. This is basically the "directory" of a "file" in the path, but is specified by [Section 5.1.4 of the RFC](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4).
|
|---|
| 80 |
|
|---|
| 81 | The `path` parameter MUST be _only_ the pathname part of a URI (excluding the hostname, query, fragment, and so on). This is the `.pathname` property of node's `uri.parse()` output.
|
|---|
| 82 |
|
|---|
| 83 | #### `pathMatch(reqPath, cookiePath)`
|
|---|
| 84 |
|
|---|
| 85 | Answers "does the request-path path-match a given cookie-path?" as per [RFC 6265 Section 5.1.4](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4). Returns a boolean.
|
|---|
| 86 |
|
|---|
| 87 | This is essentially a prefix-match where `cookiePath` is a prefix of `reqPath`.
|
|---|
| 88 |
|
|---|
| 89 | #### `parse(cookieString[, options])`
|
|---|
| 90 |
|
|---|
| 91 | Alias for [`Cookie.parse(cookieString[, options])`](#cookieparsecookiestring-options).
|
|---|
| 92 |
|
|---|
| 93 | #### `fromJSON(string)`
|
|---|
| 94 |
|
|---|
| 95 | Alias for [`Cookie.fromJSON(string)`](#cookiefromjsonstrorobj).
|
|---|
| 96 |
|
|---|
| 97 | #### `getPublicSuffix(hostname)`
|
|---|
| 98 |
|
|---|
| 99 | Returns the public suffix of this hostname. The public suffix is the shortest domain name upon which a cookie can be set. Returns `null` if the hostname cannot have cookies set for it.
|
|---|
| 100 |
|
|---|
| 101 | For example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.
|
|---|
| 102 |
|
|---|
| 103 | For further information, see the [Public Suffix List](http://publicsuffix.org/). This module derives its list from that site. This call is a wrapper around [`psl`](https://www.npmjs.com/package/psl)'s [`get` method](https://www.npmjs.com/package/psl##pslgetdomain).
|
|---|
| 104 |
|
|---|
| 105 | #### `cookieCompare(a, b)`
|
|---|
| 106 |
|
|---|
| 107 | For use with `.sort()`, sorts a list of cookies into the recommended order given in step 2 of ([RFC 6265 Section 5.4](https://datatracker.ietf.org/doc/html/rfc6265#section-5.4)). The sort algorithm is, in order of precedence:
|
|---|
| 108 |
|
|---|
| 109 | - Longest `.path`
|
|---|
| 110 | - oldest `.creation` (which has a 1-ms precision, same as `Date`)
|
|---|
| 111 | - lowest `.creationIndex` (to get beyond the 1-ms precision)
|
|---|
| 112 |
|
|---|
| 113 | ```javascript
|
|---|
| 114 | var cookies = [
|
|---|
| 115 | /* unsorted array of Cookie objects */
|
|---|
| 116 | ];
|
|---|
| 117 | cookies = cookies.sort(cookieCompare);
|
|---|
| 118 | ```
|
|---|
| 119 |
|
|---|
| 120 | > **Note**: Since the JavaScript `Date` is limited to a 1-ms precision, cookies within the same millisecond are entirely possible. This is especially true when using the `now` option to `.setCookie()`. The `.creationIndex` property is a per-process global counter, assigned during construction with `new Cookie()`, which preserves the spirit of the RFC sorting: older cookies go first. This works great for `MemoryCookieStore` since `Set-Cookie` headers are parsed in order, but is not so great for distributed systems. Sophisticated `Store`s may wish to set this to some other _logical clock_ so that if cookies A and B are created in the same millisecond, but cookie A is created before cookie B, then `A.creationIndex < B.creationIndex`. If you want to alter the global counter, which you probably _shouldn't_ do, it's stored in `Cookie.cookiesCreated`.
|
|---|
| 121 |
|
|---|
| 122 | #### `permuteDomain(domain)`
|
|---|
| 123 |
|
|---|
| 124 | Generates a list of all possible domains that `domainMatch()` the parameter. Can be handy for implementing cookie stores.
|
|---|
| 125 |
|
|---|
| 126 | #### `permutePath(path)`
|
|---|
| 127 |
|
|---|
| 128 | Generates a list of all possible paths that `pathMatch()` the parameter. Can be handy for implementing cookie stores.
|
|---|
| 129 |
|
|---|
| 130 | ### Cookie
|
|---|
| 131 |
|
|---|
| 132 | Exported via `tough.Cookie`.
|
|---|
| 133 |
|
|---|
| 134 | #### `Cookie.parse(cookieString[, options])`
|
|---|
| 135 |
|
|---|
| 136 | Parses a single Cookie or Set-Cookie HTTP header into a `Cookie` object. Returns `undefined` if the string can't be parsed.
|
|---|
| 137 |
|
|---|
| 138 | The options parameter is not required and currently has only one property:
|
|---|
| 139 |
|
|---|
| 140 | - _loose_ - boolean - if `true` enable parsing of keyless cookies like `=abc` and `=`, which are not RFC-compliant.
|
|---|
| 141 |
|
|---|
| 142 | If options is not an object it is ignored, which means it can be used with [`Array#map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
|---|
| 143 |
|
|---|
| 144 | To process the Set-Cookie header(s) on a node HTTP/HTTPS response:
|
|---|
| 145 |
|
|---|
| 146 | ```javascript
|
|---|
| 147 | if (Array.isArray(res.headers["set-cookie"]))
|
|---|
| 148 | cookies = res.headers["set-cookie"].map(Cookie.parse);
|
|---|
| 149 | else cookies = [Cookie.parse(res.headers["set-cookie"])];
|
|---|
| 150 | ```
|
|---|
| 151 |
|
|---|
| 152 | _Note:_ In version 2.3.3, tough-cookie limited the number of spaces before the `=` to 256 characters. This limitation was removed in version 2.3.4.
|
|---|
| 153 | For more details, see [issue #92](https://github.com/salesforce/tough-cookie/issues/92).
|
|---|
| 154 |
|
|---|
| 155 | #### Properties
|
|---|
| 156 |
|
|---|
| 157 | Cookie object properties:
|
|---|
| 158 |
|
|---|
| 159 | - _key_ - string - the name or key of the cookie (default `""`)
|
|---|
| 160 | - _value_ - string - the value of the cookie (default `""`)
|
|---|
| 161 | - _expires_ - `Date` - if set, the `Expires=` attribute of the cookie (defaults to the string `"Infinity"`). See `setExpires()`
|
|---|
| 162 | - _maxAge_ - seconds - if set, the `Max-Age=` attribute _in seconds_ of the cookie. Can also be set to strings `"Infinity"` and `"-Infinity"` for non-expiry and immediate-expiry, respectively. See `setMaxAge()`
|
|---|
| 163 | - _domain_ - string - the `Domain=` attribute of the cookie
|
|---|
| 164 | - _path_ - string - the `Path=` of the cookie
|
|---|
| 165 | - _secure_ - boolean - the `Secure` cookie flag
|
|---|
| 166 | - _httpOnly_ - boolean - the `HttpOnly` cookie flag
|
|---|
| 167 | - _sameSite_ - string - the `SameSite` cookie attribute (from [RFC 6265bis](#rfc-6265bis)); must be one of `none`, `lax`, or `strict`
|
|---|
| 168 | - _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)
|
|---|
| 169 | - _creation_ - `Date` - when this cookie was constructed
|
|---|
| 170 | - _creationIndex_ - number - set at construction, used to provide greater sort precision (see `cookieCompare(a,b)` for a full explanation)
|
|---|
| 171 |
|
|---|
| 172 | After a cookie has been passed through `CookieJar.setCookie()` it has the following additional attributes:
|
|---|
| 173 |
|
|---|
| 174 | - _hostOnly_ - boolean - is this a host-only cookie (that is, no Domain field was set, but was instead implied).
|
|---|
| 175 | - _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.
|
|---|
| 176 | - _creation_ - `Date` - **modified** from construction to when the cookie was added to the jar.
|
|---|
| 177 | - _lastAccessed_ - `Date` - last time the cookie got accessed. Affects cookie cleaning after it is implemented. Using `cookiejar.getCookies(...)` updates this attribute.
|
|---|
| 178 |
|
|---|
| 179 | #### `new Cookie([properties])`
|
|---|
| 180 |
|
|---|
| 181 | Receives an options object that can contain any of the above Cookie properties. Uses the default for unspecified properties.
|
|---|
| 182 |
|
|---|
| 183 | #### `.toString()`
|
|---|
| 184 |
|
|---|
| 185 | Encodes to a Set-Cookie header value. The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.
|
|---|
| 186 |
|
|---|
| 187 | #### `.cookieString()`
|
|---|
| 188 |
|
|---|
| 189 | Encodes to a Cookie header value (specifically, the `.key` and `.value` properties joined with `"="`).
|
|---|
| 190 |
|
|---|
| 191 | #### `.setExpires(string)`
|
|---|
| 192 |
|
|---|
| 193 | Sets the expiry based on a date-string passed through `parseDate()`. If parseDate returns `null` (that is, can't parse this date string), `.expires` is set to `"Infinity"` (a string).
|
|---|
| 194 |
|
|---|
| 195 | #### `.setMaxAge(number)`
|
|---|
| 196 |
|
|---|
| 197 | Sets the maxAge in seconds. Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it correctly serializes to JSON.
|
|---|
| 198 |
|
|---|
| 199 | #### `.expiryDate([now=Date.now()])`
|
|---|
| 200 |
|
|---|
| 201 | `expiryTime()` computes the absolute unix-epoch milliseconds that this cookie expires. `expiryDate()` works similarly, except it returns a `Date` object. Note that in both cases the `now` parameter should be milliseconds.
|
|---|
| 202 |
|
|---|
| 203 | Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` parameter -- is used to offset the `.maxAge` attribute.
|
|---|
| 204 |
|
|---|
| 205 | If Expires (`.expires`) is set, that's returned.
|
|---|
| 206 |
|
|---|
| 207 | Otherwise, `expiryTime()` returns `Infinity` and `expiryDate()` returns a `Date` object for "Tue, 19 Jan 2038 03:14:07 GMT" (latest date that can be expressed by a 32-bit `time_t`; the common limit for most user-agents).
|
|---|
| 208 |
|
|---|
| 209 | #### `.TTL([now=Date.now()])`
|
|---|
| 210 |
|
|---|
| 211 | Computes the TTL relative to `now` (milliseconds). The same precedence rules as for `expiryTime`/`expiryDate` apply.
|
|---|
| 212 |
|
|---|
| 213 | `Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired. Otherwise a time-to-live in milliseconds is returned.
|
|---|
| 214 |
|
|---|
| 215 | #### `.canonicalizedDomain()`
|
|---|
| 216 |
|
|---|
| 217 | #### `.cdomain()`
|
|---|
| 218 |
|
|---|
| 219 | Returns the canonicalized `.domain` field. This is lower-cased and punycode ([RFC 3490](https://datatracker.ietf.org/doc/html/rfc3490)) encoded if the domain has any non-ASCII characters.
|
|---|
| 220 |
|
|---|
| 221 | #### `.toJSON()`
|
|---|
| 222 |
|
|---|
| 223 | For convenience in using `JSON.serialize(cookie)`. Returns a plain-old `Object` that can be JSON-serialized.
|
|---|
| 224 |
|
|---|
| 225 | Any `Date` properties (such as `.expires`, `.creation`, and `.lastAccessed`) are exported in ISO format (`.toISOString()`).
|
|---|
| 226 |
|
|---|
| 227 | > **NOTE**: Custom `Cookie` properties are discarded. In tough-cookie 1.x, since there was no `.toJSON` method explicitly defined, all enumerable properties were captured. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
|
|---|
| 228 |
|
|---|
| 229 | #### `Cookie.fromJSON(strOrObj)`
|
|---|
| 230 |
|
|---|
| 231 | Does the reverse of `cookie.toJSON()`. If passed a string, will `JSON.parse()` that first.
|
|---|
| 232 |
|
|---|
| 233 | Any `Date` properties (such as `.expires`, `.creation`, and `.lastAccessed`) are parsed via [`Date.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse), not tough-cookie's `parseDate`, since ISO timestamps are being handled at this layer.
|
|---|
| 234 |
|
|---|
| 235 | Returns `null` upon a JSON parsing error.
|
|---|
| 236 |
|
|---|
| 237 | #### `.clone()`
|
|---|
| 238 |
|
|---|
| 239 | Does a deep clone of this cookie, implemented exactly as `Cookie.fromJSON(cookie.toJSON())`.
|
|---|
| 240 |
|
|---|
| 241 | #### `.validate()`
|
|---|
| 242 |
|
|---|
| 243 | Status: _IN PROGRESS_. Works for a few things, but is by no means comprehensive.
|
|---|
| 244 |
|
|---|
| 245 | Validates cookie attributes for semantic correctness. Useful for "lint" checking any Set-Cookie headers you generate. For now, it returns a boolean, but eventually could return a reason string. Future-proof with this construct:
|
|---|
| 246 |
|
|---|
| 247 | ```javascript
|
|---|
| 248 | if (cookie.validate() === true) {
|
|---|
| 249 | // it's tasty
|
|---|
| 250 | } else {
|
|---|
| 251 | // yuck!
|
|---|
| 252 | }
|
|---|
| 253 | ```
|
|---|
| 254 |
|
|---|
| 255 | ### CookieJar
|
|---|
| 256 |
|
|---|
| 257 | Exported via `tough.CookieJar`.
|
|---|
| 258 |
|
|---|
| 259 | #### `CookieJar([store][, options])`
|
|---|
| 260 |
|
|---|
| 261 | Simply use `new CookieJar()`. If a custom store is not passed to the constructor, a [`MemoryCookieStore`](#memorycookiestore) is created and used.
|
|---|
| 262 |
|
|---|
| 263 | The `options` object can be omitted and can have the following properties:
|
|---|
| 264 |
|
|---|
| 265 | - _rejectPublicSuffixes_ - boolean - default `true` - reject cookies with domains like "com" and "co.uk"
|
|---|
| 266 | - _looseMode_ - boolean - default `false` - accept malformed cookies like `bar` and `=bar`, which have an implied empty name.
|
|---|
| 267 | - _prefixSecurity_ - string - default `silent` - set to `'unsafe-disabled'`, `'silent'`, or `'strict'`. See [Cookie Prefixes](#cookie-prefixes) below.
|
|---|
| 268 | - _allowSpecialUseDomain_ - boolean - default `true` - accepts special-use domain suffixes, such as `local`. Useful for testing purposes.
|
|---|
| 269 | This is not in the standard, but is used sometimes on the web and is accepted by most browsers.
|
|---|
| 270 |
|
|---|
| 271 | #### `.setCookie(cookieOrString, currentUrl[, options][, callback(err, cookie)])`
|
|---|
| 272 |
|
|---|
| 273 | Attempt to set the cookie in the cookie jar. The cookie has updated `.creation`, `.lastAccessed` and `.hostOnly` properties. And returns a promise if a callback is not provided.
|
|---|
| 274 |
|
|---|
| 275 | The `options` object can be omitted and can have the following properties:
|
|---|
| 276 |
|
|---|
| 277 | - _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects `HttpOnly` cookies.
|
|---|
| 278 | - _secure_ - boolean - autodetect from URL - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` this defaults to `true`, otherwise `false`.
|
|---|
| 279 | - _now_ - Date - default `new Date()` - what to use for the creation or access time of cookies.
|
|---|
| 280 | - _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains. `Store` errors aren't ignored by this option.
|
|---|
| 281 | - _sameSiteContext_ - string - default unset - set to `'none'`, `'lax'`, or `'strict'` See [SameSite Cookies](#samesite-cookies) below.
|
|---|
| 282 |
|
|---|
| 283 | As per the RFC, the `.hostOnly` property is set if there was no "Domain=" parameter in the cookie string (or `.domain` was null on the Cookie object). The `.domain` property is set to the fully-qualified hostname of `currentUrl` in this case. Matching this cookie requires an exact hostname match (not a `domainMatch` as per usual).
|
|---|
| 284 |
|
|---|
| 285 | #### `.setCookieSync(cookieOrString, currentUrl[, options])`
|
|---|
| 286 |
|
|---|
| 287 | Synchronous version of [`setCookie`](#setcookiecookieorstring-currenturl-options-callbackerr-cookie); only works with synchronous stores (that is, the default `MemoryCookieStore`).
|
|---|
| 288 |
|
|---|
| 289 | #### `.getCookies(currentUrl[, options][, callback(err, cookies)])`
|
|---|
| 290 |
|
|---|
| 291 | Retrieve the list of cookies that can be sent in a Cookie header for the current URL. Returns a promise if a callback is not provided.
|
|---|
| 292 |
|
|---|
| 293 | Returns an array of `Cookie` objects, sorted by default using [`cookieCompare`](#cookiecomparea-b).
|
|---|
| 294 |
|
|---|
| 295 | If an error is encountered it's passed as `err` to the callback, otherwise an array of `Cookie` objects is passed. The array is sorted with `cookieCompare()` unless the `{sort:false}` option is given.
|
|---|
| 296 |
|
|---|
| 297 | The `options` object can be omitted and can have the following properties:
|
|---|
| 298 |
|
|---|
| 299 | - _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects `HttpOnly` cookies.
|
|---|
| 300 | - _secure_ - boolean - autodetect from URL - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
|
|---|
| 301 | - _now_ - Date - default `new Date()` - what to use for the creation or access time of cookies
|
|---|
| 302 | - _expire_ - boolean - default `true` - perform expiry-time checking of cookies and asynchronously remove expired cookies from the store. Using `false` returns expired cookies and does **not** remove them from the store (which is potentially useful for replaying Set-Cookie headers).
|
|---|
| 303 | - _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the underlying store (the default `MemoryCookieStore` supports it).
|
|---|
| 304 | - _sameSiteContext_ - string - default unset - Set this to `'none'`, `'lax'`, or `'strict'` to enforce SameSite cookies upon retrieval. See [SameSite Cookies](#samesite-cookies) below.
|
|---|
| 305 | - _sort_ - boolean - whether to sort the list of cookies.
|
|---|
| 306 |
|
|---|
| 307 | The `.lastAccessed` property of the returned cookies will have been updated.
|
|---|
| 308 |
|
|---|
| 309 | #### `.getCookiesSync(currentUrl, [{options}])`
|
|---|
| 310 |
|
|---|
| 311 | Synchronous version of [`getCookies`](#getcookiescurrenturl-options-callbackerr-cookies); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 312 |
|
|---|
| 313 | #### `.getCookieString(...)`
|
|---|
| 314 |
|
|---|
| 315 | Accepts the same options as [`.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies) but returns a string suitable for a Cookie header rather than an Array.
|
|---|
| 316 |
|
|---|
| 317 | #### `.getCookieStringSync(...)`
|
|---|
| 318 |
|
|---|
| 319 | Synchronous version of [`getCookieString`](#getcookiestring); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 320 |
|
|---|
| 321 | #### `.getSetCookieStrings(...)`
|
|---|
| 322 |
|
|---|
| 323 | Returns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as [`.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies). Simply maps the cookie array via `.toString()`.
|
|---|
| 324 |
|
|---|
| 325 | #### `.getSetCookieStringsSync(...)`
|
|---|
| 326 |
|
|---|
| 327 | Synchronous version of [`getSetCookieStrings`](#getsetcookiestrings); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 328 |
|
|---|
| 329 | #### `.serialize([callback(err, serializedObject)])`
|
|---|
| 330 |
|
|---|
| 331 | Returns a promise if a callback is not provided.
|
|---|
| 332 |
|
|---|
| 333 | Serialize the Jar if the underlying store supports `.getAllCookies`.
|
|---|
| 334 |
|
|---|
| 335 | > **NOTE**: Custom `Cookie` properties are discarded. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
|
|---|
| 336 |
|
|---|
| 337 | See [Serialization Format](#serialization-format).
|
|---|
| 338 |
|
|---|
| 339 | #### `.serializeSync()`
|
|---|
| 340 |
|
|---|
| 341 | Synchronous version of [`serialize`](#serializecallbackerr-serializedobject); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 342 |
|
|---|
| 343 | #### `.toJSON()`
|
|---|
| 344 |
|
|---|
| 345 | Alias of [`.serializeSync()`](#serializesync) for the convenience of `JSON.stringify(cookiejar)`.
|
|---|
| 346 |
|
|---|
| 347 | #### `CookieJar.deserialize(serialized[, store][, callback(err, object)])`
|
|---|
| 348 |
|
|---|
| 349 | A new Jar is created and the serialized Cookies are added to the underlying store. Each `Cookie` is added via `store.putCookie` in the order in which they appear in the serialization. A promise is returned if a callback is not provided.
|
|---|
| 350 |
|
|---|
| 351 | The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created.
|
|---|
| 352 |
|
|---|
| 353 | As a convenience, if `serialized` is a string, it is passed through `JSON.parse` first.
|
|---|
| 354 |
|
|---|
| 355 | #### `CookieJar.deserializeSync(serialized[, store])`
|
|---|
| 356 |
|
|---|
| 357 | Sync version of [`.deserialize`](#cookiejardeserializeserialized-store-callbackerr-object); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 358 |
|
|---|
| 359 | #### `CookieJar.fromJSON(string)`
|
|---|
| 360 |
|
|---|
| 361 | Alias of [`.deserializeSync`](#cookiejardeserializesyncserialized-store) to provide consistency with [`Cookie.fromJSON()`](#cookiefromjsonstrorobj).
|
|---|
| 362 |
|
|---|
| 363 | #### `.clone([store][, callback(err, cloned))`
|
|---|
| 364 |
|
|---|
| 365 | Produces a deep clone of this jar. Modifications to the original do not affect the clone, and vice versa. Returns a promise if a callback is not provided.
|
|---|
| 366 |
|
|---|
| 367 | The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created. Transferring between store types is supported so long as the source implements `.getAllCookies()` and the destination implements `.putCookie()`.
|
|---|
| 368 |
|
|---|
| 369 | #### `.cloneSync([store])`
|
|---|
| 370 |
|
|---|
| 371 | Synchronous version of [`.clone`](#clonestore-callbackerr-cloned), returning a new `CookieJar` instance.
|
|---|
| 372 |
|
|---|
| 373 | The `store` argument is optional, but must be a _synchronous_ `Store` instance if specified. If not passed, a new instance of `MemoryCookieStore` is used.
|
|---|
| 374 |
|
|---|
| 375 | The _source_ and _destination_ must both be synchronous `Store`s. If one or both stores are asynchronous, use `.clone` instead. Recall that `MemoryCookieStore` supports both synchronous and asynchronous API calls.
|
|---|
| 376 |
|
|---|
| 377 | #### `.removeAllCookies([callback(err)])`
|
|---|
| 378 |
|
|---|
| 379 | Removes all cookies from the jar. Returns a promise if a callback is not provided.
|
|---|
| 380 |
|
|---|
| 381 | This is a new backwards-compatible feature of `tough-cookie` version 2.5, so not all Stores will implement it efficiently. For Stores that do not implement `removeAllCookies`, the fallback is to call `removeCookie` after `getAllCookies`. If `getAllCookies` fails or isn't implemented in the Store, that error is returned. If one or more of the `removeCookie` calls fail, only the first error is returned.
|
|---|
| 382 |
|
|---|
| 383 | #### `.removeAllCookiesSync()`
|
|---|
| 384 |
|
|---|
| 385 | Sync version of [`.removeAllCookies()`](#removeallcookiescallbackerr); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
|---|
| 386 |
|
|---|
| 387 | ### Store
|
|---|
| 388 |
|
|---|
| 389 | Base class for CookieJar stores. Available as `tough.Store`.
|
|---|
| 390 |
|
|---|
| 391 | ### Store API
|
|---|
| 392 |
|
|---|
| 393 | The storage model for each `CookieJar` instance can be replaced with a custom implementation. The default is `MemoryCookieStore` which can be found in [`lib/memstore.js`](https://github.com/salesforce/tough-cookie/blob/master/lib/memstore.js). The API uses continuation-passing-style to allow for asynchronous stores.
|
|---|
| 394 |
|
|---|
| 395 | Stores should inherit from the base `Store` class, which is available as a top-level export.
|
|---|
| 396 |
|
|---|
| 397 | Stores are asynchronous by default, but if `store.synchronous` is set to `true`, then the `*Sync` methods of the containing `CookieJar` can be used.
|
|---|
| 398 |
|
|---|
| 399 | All `domain` parameters are normalized before calling.
|
|---|
| 400 |
|
|---|
| 401 | The Cookie store must have all of the following methods. Note that asynchronous implementations **must** support callback parameters.
|
|---|
| 402 |
|
|---|
| 403 | #### `store.findCookie(domain, path, key, callback(err, cookie))`
|
|---|
| 404 |
|
|---|
| 405 | Retrieve a cookie with the given domain, path, and key (name). The RFC maintains that exactly one of these cookies should exist in a store. If the store is using versioning, this means that the latest or newest such cookie should be returned.
|
|---|
| 406 |
|
|---|
| 407 | Callback takes an error and the resulting `Cookie` object. If no cookie is found then `null` MUST be passed instead (that is, not an error).
|
|---|
| 408 |
|
|---|
| 409 | #### `store.findCookies(domain, path, allowSpecialUseDomain, callback(err, cookies))`
|
|---|
| 410 |
|
|---|
| 411 | Locates cookies matching the given domain and path. This is most often called in the context of [`cookiejar.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies).
|
|---|
| 412 |
|
|---|
| 413 | If no cookies are found, the callback MUST be passed an empty array.
|
|---|
| 414 |
|
|---|
| 415 | The resulting list is checked for applicability to the current request according to the RFC (domain-match, path-match, http-only-flag, secure-flag, expiry, and so on), so it's OK to use an optimistic search algorithm when implementing this method. However, the search algorithm used SHOULD try to find cookies that `domainMatch()` the domain and `pathMatch()` the path in order to limit the amount of checking that needs to be done.
|
|---|
| 416 |
|
|---|
| 417 | As of version 0.9.12, the `allPaths` option to `cookiejar.getCookies()` above causes the path here to be `null`. If the path is `null`, path-matching MUST NOT be performed (that is, domain-matching only).
|
|---|
| 418 |
|
|---|
| 419 | #### `store.putCookie(cookie, callback(err))`
|
|---|
| 420 |
|
|---|
| 421 | Adds a new cookie to the store. The implementation SHOULD replace any existing cookie with the same `.domain`, `.path`, and `.key` properties. Depending on the nature of the implementation, it's possible that between the call to `fetchCookie` and `putCookie` that a duplicate `putCookie` can occur.
|
|---|
| 422 |
|
|---|
| 423 | The `cookie` object MUST NOT be modified; as the caller has already updated the `.creation` and `.lastAccessed` properties.
|
|---|
| 424 |
|
|---|
| 425 | Pass an error if the cookie cannot be stored.
|
|---|
| 426 |
|
|---|
| 427 | #### `store.updateCookie(oldCookie, newCookie, callback(err))`
|
|---|
| 428 |
|
|---|
| 429 | Update an existing cookie. The implementation MUST update the `.value` for a cookie with the same `domain`, `.path`, and `.key`. The implementation SHOULD check that the old value in the store is equivalent to `oldCookie` - how the conflict is resolved is up to the store.
|
|---|
| 430 |
|
|---|
| 431 | The `.lastAccessed` property is always different between the two objects (to the precision possible via JavaScript's clock). Both `.creation` and `.creationIndex` are guaranteed to be the same. Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are selected for automatic deletion (for example, least-recently-used, which is up to the store to implement).
|
|---|
| 432 |
|
|---|
| 433 | Stores may wish to optimize changing the `.value` of the cookie in the store versus storing a new cookie. If the implementation doesn't define this method, a stub that calls [`putCookie`](#storeputcookiecookie-callbackerr) is added to the store object.
|
|---|
| 434 |
|
|---|
| 435 | The `newCookie` and `oldCookie` objects MUST NOT be modified.
|
|---|
| 436 |
|
|---|
| 437 | Pass an error if the newCookie cannot be stored.
|
|---|
| 438 |
|
|---|
| 439 | #### `store.removeCookie(domain, path, key, callback(err))`
|
|---|
| 440 |
|
|---|
| 441 | Remove a cookie from the store (see notes on [`findCookie`](#storefindcookiedomain-path-key-callbackerr-cookie) about the uniqueness constraint).
|
|---|
| 442 |
|
|---|
| 443 | The implementation MUST NOT pass an error if the cookie doesn't exist, and only pass an error due to the failure to remove an existing cookie.
|
|---|
| 444 |
|
|---|
| 445 | #### `store.removeCookies(domain, path, callback(err))`
|
|---|
| 446 |
|
|---|
| 447 | Removes matching cookies from the store. The `path` parameter is optional and if missing, means all paths in a domain should be removed.
|
|---|
| 448 |
|
|---|
| 449 | Pass an error ONLY if removing any existing cookies failed.
|
|---|
| 450 |
|
|---|
| 451 | #### `store.removeAllCookies(callback(err))`
|
|---|
| 452 |
|
|---|
| 453 | _Optional_. Removes all cookies from the store.
|
|---|
| 454 |
|
|---|
| 455 | Pass an error if one or more cookies can't be removed.
|
|---|
| 456 |
|
|---|
| 457 | #### `store.getAllCookies(callback(err, cookies))`
|
|---|
| 458 |
|
|---|
| 459 | _Optional_. Produces an `Array` of all cookies during [`jar.serialize()`](#serializecallbackerr-serializedobject). The items in the array can be true `Cookie` objects or generic `Object`s with the [Serialization Format](#serialization-format) data structure.
|
|---|
| 460 |
|
|---|
| 461 | Cookies SHOULD be returned in creation order to preserve sorting via [`compareCookie()`](#cookiecomparea-b). For reference, `MemoryCookieStore` sorts by `.creationIndex` since it uses true `Cookie` objects internally. If you don't return the cookies in creation order, they'll still be sorted by creation time, but this only has a precision of 1-ms. See `cookieCompare` for more detail.
|
|---|
| 462 |
|
|---|
| 463 | Pass an error if retrieval fails.
|
|---|
| 464 |
|
|---|
| 465 | **Note**: Not all Stores can implement this due to technical limitations, so it is optional.
|
|---|
| 466 |
|
|---|
| 467 | ### MemoryCookieStore
|
|---|
| 468 |
|
|---|
| 469 | Inherits from `Store`.
|
|---|
| 470 |
|
|---|
| 471 | A just-in-memory CookieJar synchronous store implementation, used by default. Despite being a synchronous implementation, it's usable with both the synchronous and asynchronous forms of the `CookieJar` API. Supports serialization, `getAllCookies`, and `removeAllCookies`.
|
|---|
| 472 |
|
|---|
| 473 | ### Community Cookie Stores
|
|---|
| 474 |
|
|---|
| 475 | These are some Store implementations authored and maintained by the community. They aren't official and we don't vouch for them but you may be interested to have a look:
|
|---|
| 476 |
|
|---|
| 477 | - [`db-cookie-store`](https://github.com/JSBizon/db-cookie-store): SQL including SQLite-based databases
|
|---|
| 478 | - [`file-cookie-store`](https://github.com/JSBizon/file-cookie-store): Netscape cookie file format on disk
|
|---|
| 479 | - [`redis-cookie-store`](https://github.com/benkroeger/redis-cookie-store): Redis
|
|---|
| 480 | - [`tough-cookie-filestore`](https://github.com/mitsuru/tough-cookie-filestore): JSON on disk
|
|---|
| 481 | - [`tough-cookie-web-storage-store`](https://github.com/exponentjs/tough-cookie-web-storage-store): DOM localStorage and sessionStorage
|
|---|
| 482 |
|
|---|
| 483 | ## Serialization Format
|
|---|
| 484 |
|
|---|
| 485 | **NOTE**: If you want to have custom `Cookie` properties serialized, add the property name to `Cookie.serializableProperties`.
|
|---|
| 486 |
|
|---|
| 487 | ```js
|
|---|
| 488 | {
|
|---|
| 489 | // The version of tough-cookie that serialized this jar.
|
|---|
| 490 | version: 'tough-cookie@1.x.y',
|
|---|
| 491 |
|
|---|
| 492 | // add the store type, to make humans happy:
|
|---|
| 493 | storeType: 'MemoryCookieStore',
|
|---|
| 494 |
|
|---|
| 495 | // CookieJar configuration:
|
|---|
| 496 | rejectPublicSuffixes: true,
|
|---|
| 497 | // ... future items go here
|
|---|
| 498 |
|
|---|
| 499 | // Gets filled from jar.store.getAllCookies():
|
|---|
| 500 | cookies: [
|
|---|
| 501 | {
|
|---|
| 502 | key: 'string',
|
|---|
| 503 | value: 'string',
|
|---|
| 504 | // ...
|
|---|
| 505 | /* other Cookie.serializableProperties go here */
|
|---|
| 506 | }
|
|---|
| 507 | ]
|
|---|
| 508 | }
|
|---|
| 509 | ```
|
|---|
| 510 |
|
|---|
| 511 | ## RFC 6265bis
|
|---|
| 512 |
|
|---|
| 513 | Support for RFC 6265bis revision 02 is being developed. Since this is a bit of an omnibus revision to the RFC 6252, support is broken up into the functional areas.
|
|---|
| 514 |
|
|---|
| 515 | ### Leave Secure Cookies Alone
|
|---|
| 516 |
|
|---|
| 517 | Not yet supported.
|
|---|
| 518 |
|
|---|
| 519 | This change makes it so that if a cookie is sent from the server to the client with a `Secure` attribute, the channel must also be secure or the cookie is ignored.
|
|---|
| 520 |
|
|---|
| 521 | ### SameSite Cookies
|
|---|
| 522 |
|
|---|
| 523 | Supported.
|
|---|
| 524 |
|
|---|
| 525 | This change makes it possible for servers, and supporting clients, to mitigate certain types of CSRF attacks by disallowing `SameSite` cookies from being sent cross-origin.
|
|---|
| 526 |
|
|---|
| 527 | On the Cookie object itself, you can get or set the `.sameSite` attribute, which is serialized into the `SameSite=` cookie attribute. When unset or `undefined`, no `SameSite=` attribute is serialized. The valid values of this attribute are `'none'`, `'lax'`, or `'strict'`. Other values are serialized as-is.
|
|---|
| 528 |
|
|---|
| 529 | When parsing cookies with a `SameSite` cookie attribute, values other than `'lax'` or `'strict'` are parsed as `'none'`. For example, `SomeCookie=SomeValue; SameSite=garbage` parses so that `cookie.sameSite === 'none'`.
|
|---|
| 530 |
|
|---|
| 531 | In order to support SameSite cookies, you must provide a `sameSiteContext` option to _both_ `setCookie` and `getCookies`. Valid values for this option are just like for the Cookie object, but have particular meanings:
|
|---|
| 532 |
|
|---|
| 533 | 1. `'strict'` mode - If the request is on the same "site for cookies" (see the RFC draft for more information), pass this option to add a layer of defense against CSRF.
|
|---|
| 534 | 2. `'lax'` mode - If the request is from another site, _but_ is directly because of navigation by the user, such as, `<link type=prefetch>` or `<a href="...">`, pass `sameSiteContext: 'lax'`.
|
|---|
| 535 | 3. `'none'` - Otherwise, pass `sameSiteContext: 'none'` (this indicates a cross-origin request).
|
|---|
| 536 | 4. unset/`undefined` - SameSite **is not** be enforced! This can be a valid use-case for when CSRF isn't in the threat model of the system being built.
|
|---|
| 537 |
|
|---|
| 538 | It is highly recommended that you read RFC 6265bis for fine details on SameSite cookies. In particular [Section 8.8](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02##section-8.8) discusses security considerations and defense in depth.
|
|---|
| 539 |
|
|---|
| 540 | ### Cookie Prefixes
|
|---|
| 541 |
|
|---|
| 542 | Supported.
|
|---|
| 543 |
|
|---|
| 544 | Cookie prefixes are a way to indicate that a given cookie was set with a set of attributes simply by inspecting the first few characters of the cookie's name.
|
|---|
| 545 |
|
|---|
| 546 | Cookie prefixes are defined in [Section 4.1.3 of 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03##section-4.1.3).
|
|---|
| 547 |
|
|---|
| 548 | Two prefixes are defined:
|
|---|
| 549 |
|
|---|
| 550 | 1. `"__Secure-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "\_\_Secure-", then the cookie was set with a "Secure" attribute.
|
|---|
| 551 | 2. `"__Host-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "\_\_Host-", then the cookie was set with a "Secure" attribute, a "Path" attribute with a value of "/", and no "Domain" attribute.
|
|---|
| 552 |
|
|---|
| 553 | If `prefixSecurity` is enabled for `CookieJar`, then cookies that match the prefixes defined above but do not obey the attribute restrictions are not added.
|
|---|
| 554 |
|
|---|
| 555 | You can define this functionality by passing in the `prefixSecurity` option to `CookieJar`. It can be one of 3 values:
|
|---|
| 556 |
|
|---|
| 557 | 1. `silent`: Enable cookie prefix checking but silently fail to add the cookie if conditions are not met. Default.
|
|---|
| 558 | 2. `strict`: Enable cookie prefix checking and error out if conditions are not met.
|
|---|
| 559 | 3. `unsafe-disabled`: Disable cookie prefix checking.
|
|---|
| 560 |
|
|---|
| 561 | Note that if `ignoreError` is passed in as `true` then the error is silent regardless of the `prefixSecurity` option (assuming it's enabled).
|
|---|
| 562 |
|
|---|
| 563 | ## Copyright and License
|
|---|
| 564 |
|
|---|
| 565 | BSD-3-Clause:
|
|---|
| 566 |
|
|---|
| 567 | ```text
|
|---|
| 568 | Copyright (c) 2015, Salesforce.com, Inc.
|
|---|
| 569 | All rights reserved.
|
|---|
| 570 |
|
|---|
| 571 | Redistribution and use in source and binary forms, with or without
|
|---|
| 572 | modification, are permitted provided that the following conditions are met:
|
|---|
| 573 |
|
|---|
| 574 | 1. Redistributions of source code must retain the above copyright notice,
|
|---|
| 575 | this list of conditions and the following disclaimer.
|
|---|
| 576 |
|
|---|
| 577 | 2. Redistributions in binary form must reproduce the above copyright notice,
|
|---|
| 578 | this list of conditions and the following disclaimer in the documentation
|
|---|
| 579 | and/or other materials provided with the distribution.
|
|---|
| 580 |
|
|---|
| 581 | 3. Neither the name of Salesforce.com nor the names of its contributors may
|
|---|
| 582 | be used to endorse or promote products derived from this software without
|
|---|
| 583 | specific prior written permission.
|
|---|
| 584 |
|
|---|
| 585 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|---|
| 586 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|---|
| 587 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|---|
| 588 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|---|
| 589 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|---|
| 590 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|---|
| 591 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|---|
| 592 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|---|
| 593 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|---|
| 594 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|---|
| 595 | POSSIBILITY OF SUCH DAMAGE.
|
|---|
| 596 | ```
|
|---|