Isomorphic Cookies
Isomorphic and bulletproof 🍪 cookies for meteor.js
applications with support of Client, Server, Browser, Cordova, and other Meteor-supported environments.
- 👨💻 Stable codebase, 80.000+ downloads;
- 👨🔬 ~96% Tests coverage;
- 📦 No external dependencies, no
underscore
, nojQuery
, noBlaze
; - 🖥 Full support with same API on both Server and Client environments;
- 📱 Compatible with Cordova, Browser and other Meteor's Client environments;
- ㊗️ Unicode support as cookies' value;
- 👨💻
String
,Array
,Object
, andBoolean
are supported cookies' value types; - ♿ IE support, thanks to @derwok;
- 📦 Looking for Client's (Browser) persistent storage? Try
ClientStorage
package.
Install:
meteor add ostrio:cookies
ES6 Import:
1import { Cookies } from 'meteor/ostrio:cookies';
FAQ:
- Cordova compatible? Cordova usage — This recommendation is only for outgoing
Client -to-> Server
Cookies;Server -to-> Client
cookies work out-of-the-box. Enable withCredentials. Enable{allowQueryStringCookies: true}
and{allowedCordovaOrigins: true}
on bothClient
andServer
. When those two options are set totrue
Cookies going to be transfered to server via get-query. As security measure only whenOrigin
header matches^http://localhost:12[0-9]{3}$
expression. Meteor/Cordova connect throughlocalhost:12XXX
, local server, for outgoing requests, this also instructs the server to respond with the requested cookies (sent as GET-Parameters) in the response asSet-Cookie
header. The reason for this workaround is the general lack of cookie support in Meteor/Cordova when setting in the client — but cookies set by the server are always sent along with every request; - Cookies are missing on Server — In 99% cases it's caused by Meteor's
webapp
http server callback-chain disorder. Make surenew Cookies()
is called before Routes are registered. Routing packages usually take care of*
(e.g. catch-all or 404) route, not passing request further to callback-chain. And as freshly installed package it would be placed at the end of.meteor/packages
file, where list-order matters. We recommend to placeostrio:cookies
package above all community packages in.meteor/packages
list.
API:
- Note — On a server, cookies will be set only after headers are sent (on next route or page reload). To send cookies from Client to Server without a page reload use
send()
method. - Server Usage Note — On a server Cookies implemented as a middleware. To get access to current user's cookies use
req.Cookies
instance. For more - see examples section below.
Fetch cookies new Cookies(opts)
[Isomorphic]
Create new instance of Cookies
opts.auto
{Boolean} - [Server] Auto-bind in middleware asreq.Cookies
, by defaulttrue
opts.handler
{Function} - [Server] Middleware function (e.g. hook/callback called within middleware pipeline) with single argumentcookies
asCookies
instance. See "Alternative Usage" sectionopts.onCookies
{Function} - [Server] Callback/hook triggered after.send()
method called on Client and received by Server, called with single argumentcookies
asCookies
instance. Note: this hook available only ifauto
option istrue
opts.TTL
{Number|Boolean} - Default cookies expiration time (max-age) in milliseconds, by default -false
(session, no TTL)opts.runOnServer
{Boolean} - Set tofalse
to avoid server usage (by default -true
)opts.allowQueryStringCookies
{Boolean} - Allow passing Cookies in a query string (in URL). Primary should be used only in Cordova environment. Note: this option will be used only on Cordovaopts.allowedCordovaOrigins
{Regex|Boolean} - [Server] Allow setting Cookies from that specific origin which in Meteor/Cordova is localhost:12XXX. Set to default^http:\/\/localhost:12[0-9]{3}$
if set totrue
. Default:false
1import { Cookies } from 'meteor/ostrio:cookies'; 2const cookies = new Cookies();
cookies.get(key)
[Isomorphic]
Read a cookie. If the cookie doesn't exist a null
will be returned.
key
{String} - The name of the cookie to read
cookies.set(key, value, [opts])
[Isomorphic]
Create/overwrite a cookie.
key
{String} - The name of the cookie to create/overwritevalue
{String|Number|Boolean|Object|Array} - The value of the cookieopts
{Object} - [Optional]opts.expires
{Number|Date|Infinity} - [Optional] Date, Number as milliseconds or Infinity for a never-expires cookie. If not specified the cookie will expire at the end of session (number as milliseconds or Date object)opts.maxAge
{Number} - [Optional] The max-age in seconds (e.g.31536e3
for a year)opts.path
{String} - [Optional] The path from where the cookie will be readable. E.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). The path must be absolute (see RFC 2965). For more information on how to use relative paths in this argument, see: docsopts.domain
{String} - [Optional] The domain from where the cookie will be readable. E.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not specified, defaults to the host portion of the current document location (string or null)opts.secure
{Boolean} - [Optional] The cookie will be transmitted only over secure protocol ashttps
opts.httpOnly
{Boolean} - [Optional] An HttpOnly cookie cannot be accessed by client-side APIs, such as JavaScript. This restriction eliminates the threat of cookie theft via cross-site scripting (XSS)opts.sameSite
{Boolean} {String: None, Strict, or Lax} - [Optional] Cross-site cookies usage policy. Read more on wikipedia, web.dev, and ietf. Default:false
opts.firstPartyOnly
{Boolean} - [Optional] Deprecated usesameSite
instead
cookies.remove([key], [path], [domain])
[Isomorphic]
remove()
- Remove all cookies on current domainremove(key)
- Remove a cookie on current domainremove(key, path, domain)
:key
{String} - The name of the cookie to create/overwritepath
{String} - [Optional] The path from where the cookie was readable. E.g., "/", "/mydir"; if not specified, defaults to the current path of the current document location (string or null). The path must be absolute (see RFC 2965). For more information on how to use relative paths in this argument, read moredomain
{String} - [Optional] The domain from where the cookie was readable. E.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not specified, defaults to the host portion of the current document location (string or null)
cookies.has(key)
[Isomorphic]
Check whether a cookie exists in the current position, returns boolean value
key
{String} - The name of the cookie to check
cookies.keys()
[Isomorphic]
Returns an array of all readable cookies from this location
cookies.send([callback])
[Client]
Send all current cookies to server.
Examples:
1/* Both Client & Server */ 2import { Meteor } from 'meteor/meteor'; 3import { Cookies } from 'meteor/ostrio:cookies'; 4const cookies = new Cookies(); 5 6/* Client */ 7if (Meteor.isClient) { 8 cookies.set('locale', 'en'); //true 9 cookies.set('country', 'usa'); //true 10 cookies.set('gender', 'male'); //true 11 12 cookies.get('gender'); //male 13 14 cookies.has('locale'); //true 15 cookies.has('city'); //false 16 17 cookies.keys(); //['locale', 'country', 'gender'] 18 19 cookies.remove('locale'); //true 20 cookies.get('locale'); //undefined 21 22 cookies.keys(); //['country', 'gender'] 23 24 cookies.remove(); //true 25 cookies.keys(); //[""] 26 27 cookies.remove(); //false 28} 29 30/* Server */ 31if (Meteor.isServer) { 32 const { WebApp } = require('meteor/webapp'); 33 34 WebApp.connectHandlers.use((req, res, next) => { 35 cookies = req.Cookies; 36 37 cookies.set('locale', 'en'); //true 38 cookies.set('country', 'usa'); //true 39 cookies.set('gender', 'male'); //true 40 41 cookies.get('gender'); //male 42 43 cookies.has('locale'); //true 44 cookies.has('city'); //false 45 46 cookies.keys(); //['locale', 'country', 'gender'] 47 48 cookies.remove('locale'); //true 49 cookies.get('locale'); //undefined 50 51 cookies.keys(); //['country', 'gender'] 52 53 cookies.remove(); //true 54 cookies.keys(); //[""] 55 56 cookies.remove(); //false 57 58 next(); // Pass request to the next handler 59 }); 60}
Alternative Usage
1/* Both Client & Server */ 2import { Meteor } from 'meteor/meteor'; 3import { Cookies } from 'meteor/ostrio:cookies'; 4 5/* Client */ 6if (Meteor.isClient) { 7 const cookies = new Cookies(); 8 cookies.set('gender', 'male'); //true 9 cookies.get('gender'); //male 10 cookies.has('city'); //false 11 cookies.keys(); //['gender'] 12} 13 14/* Server */ 15if (Meteor.isServer) { 16 const { WebApp } = require('meteor/webapp'); 17 18 const cookie = new Cookies({ 19 auto: false, // Do not bind as a middleware by default (recommended, but not required) 20 handler(cookies) { 21 cookies.set('gender', 'male'); //true 22 cookies.get('gender'); //male 23 cookies.has('city'); //false 24 cookies.keys(); //['gender'] 25 } 26 }); 27 28 WebApp.connectHandlers.use(cookie.middleware()); 29}
Running Tests
- Clone this package
- In Terminal (Console) go to directory where package is cloned
- Then run:
Meteor/Tinytest
# Default meteor test-packages ./ # With custom port meteor test-packages ./ --port 8888
Support our open source contributions
- Sponsor via GitHub
- Support via PayPal — support my open source contributions once or on regular basis
- Use ostr.io — Monitoring, Analytics, WebSec, Web-CRON and Pre-rendering for a website