Universal cookies for React
Universal cookies for JavaScript
Load and save cookies within your Web application
License: MIT License
Universal cookies for React
Universal cookies for JavaScript
I store my user's ID & auth token in cookies and send them with requests via headers. I save the ID & token upon successful login, delete the ID & token upon logout. After logging in & out several times, I inspected document.cookie
and noticed that the same key value pairs (__myapp:userID
and __myapp:authenticationToken
) appear over and over again. It appears that remove
isn't actually removing the cookie correctly. Furthermore, once the value for a cookie is saved, shouldn't subsequent calls to saving that cookie override the value?
document.cookie
"__myapp:userID=2; __myapp:authenticationToken=AgXsUmhMRZYPLePhxcyc; userID=2; authenticationToken=NzMZ915j5bz2gbs99Hhm; __myapp:userID=2; __myapp:authenticationToken=xrSDsTZtUB-dbqsXFZYX; __myapp:userID=2; __myapp:authenticationToken=xrSDsTZtUB-dbqsXFZYX;"
I'd like to be able to import specific members from the library.
import { select } from 'react-cookie';
This would enable tree shaking to work in bundlers like Webpack 2.0, Rollup, ect.
See export
cookie-parser
populates req.cookies
(plural) and plugToRequest
incorrectly checks req.cookie
(singular).
Parse Cookie header and populate req.cookies with an object keyed by the cookie names.
https://github.com/expressjs/cookie-parser
function plugToRequest(req, res) {
if (req.cookie) {
_rawCookie = req.cookie;
} else if (req.headers && req.headers.cookie) {
setRawCookie(req.headers.cookie);
} else {
_rawCookie = {};
}
_res = res;
}
https://github.com/eXon/react-cookie/blob/master/index.js#L67-L77
Not really breaking since req.headers.cookie
is a fallback and that exists but I thought I would point it out.
I believe I am not understanding the whole scope behind plugToRequest
feature, as I can't retrieve cookie on a server side.
Assume we are setting a cookie like:
cookie.save(
'userSession',
'123,
{ path: '/', httpOnly: true, secure: true }
)
First of all I am not able to see this cookie using extensions for chrome like EditThisCookie I am not sure if I am not setting it correctly or if thats intended behaviour of httpOnly cookies (as omitting httpOnly parameter, displays that cookie through extension)
After reading other issues I realised that I can't set httpOnly cookies from non server env, so that explains why I don't see them. This raises another question of how would such cookies be handled to be set from the server based on user actions on the client side? i.e. user logs in and receives successful response from auth api.
Secondly on my server:
cookie.plugToRequest(req, res)
const history = createMemoryHistory()
const store = configureStore({
authentication: {
authenticated: cookie.load('userSession'),
fetching: false,
error: false,
message: ''
}
}, history)
and I am also using cookieParser middleware for express.
The history and store bits are related to redux
Please add option domain
to remove function.
"_jwt_token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=.example.com;"
In my react app I'm setting cookies based on the url, for example '../page-one'.
If I enter the app on page '../page-one', cookie.load('cookieName') works fine and I can check if the cookie exists; but I then need to check for another cookie when I navigate to another page (using react-router).
I've tried running cookie.load('cookieName') in componentDidUpdate() to make sure I'm on the new page with new params, i.e. '../page-two', but it still returns the cookie value from the previous check.
The only way I can get it to work is by refreshing the page and it checks for the cookie against the '../page-two' path.
Are there any solutions to get the expected results from cookie.load('cookieName') when the component receives new props?
Thanks.
cookie.save('memberID', resp.member.id, 'memberName', resp.member.fullname)
cookie.save('memberName', resp.member.fullname, {secure: true, httpOnly: true})
Setting a cookie without expiry like so
cookie.save(
'sessionToken',
'123',
{ path: '/', secure: true }
)
Doesn't work as expected (cookie being destroyed if tab it was created in is closed or browser is closed). Instead I can only remove it by completely quitting my browser (om mac, right click on chrome and quit)
Am I not setting this up correctly?
NOTE: Using cookie inspector I am able to see that cookie expiration is set to 1 minute after it was created and once it reaches expiration it is updated to be +1 minute and so on.
EDIT: This might be caused by chromes "Continue from where I left off feature", although issue persists in firefox and safari
It seems that long numeric strings are converted to integers which can cause overflow. For example: 4823425323423554889
becomes 4823425323423554000
.
If the implicit string -> integer conversion is by design, the library should check Number.MAX_VALUE
to make sure there is no information lost in the conversion.
When in browser we have many tabs with one application, and we remove cookie in one tab, then it clear _rawCookie
in https://github.com/eXon/react-cookie/blob/master/index.js#L45 but in other tabs _rawCookie
still has value. And when we call cookie key by load method there is line : https://github.com/eXon/react-cookie/blob/master/index.js#L13, where of course there is no cookie, but this condition then works as var cookieVal = _rawCookie[name];
and therefore we get cookie value.
When I am trying to set the maxAge of the cookie, it does not work. Instead, the cookie expiry is set to session. This is how I am doing it:
cookie.save('Tachyon-API-Token', response.token, maxAge='3600', path='/');
cookie.save('loginName',state.username,{ expires: 7 ,path: "/"});
It seems that react-cookie's mechanism is manipulating the _rawCookie
object. But for every request on server side, react-cookie uses the same _rawCookie
object. I guess this might randomly cause error like below:
timeline | user A | user B | _rawCookie |
---|---|---|---|
time 1 | save('token', tokenA) | { token: tokenA } | |
time 2 | save('token', tokenB) | { token: tokenB } | |
time 3 | res.end(...) | { token: tokenB } | |
time 4 | res.end(...) | { token: tokenB } | |
result | receive tokenB | receive tokenB |
Is my guessing possible?
Hi!
One issue I've been experiencing is that if I create a new cookie on the server side (express middleware), call plugToRequest
before renderToString, the first render run on the server-side doesn't see the new cookie.
If I refresh the page, it works correctly.
This makes sense since the plug is done on the request's cookies not the request's + the new ones in the Set-Cookie header
function plugToRequest(req, res) {
if (req.cookie) {
_rawCookie = req.cookie;
} else if (req.headers && req.headers.cookie) {
setRawCookie(req.headers.cookie);
} else {
_rawCookie = {};
}
_res = res;
}
What do you suggest for that scenario so that both server and client can access the most up-to-date cookies or is a hard refresh really necessary?
Thanks.
hi I upgrade to the latest version[1.0.1] but there's something problem. I didn't see what's difference between the older version, but I saw IS_NODE
always true both in browser or node environment. It might be the problem why cookie.parse wasn't executed.
https://github.com/thereactivestack/react-cookie/blob/master/src/cookie.js#L13
Hey, I've been trying to get Isomorphic cookies to work on my solution without a success. I am using https://github.com/janoist1/universal-react-redux-starter-kit starter kit and I keep getting "React attempted to reuse markup in a container..." warning message. I am saving my login info in a cookie and the page rendered on the server is different than the page rendered on the client because the client is logged in. I tried both plugToRequest and setRawCookie options but I must be doing something wrong. Below is the file I am trying to add the setRawCookie to. Can anyone try to help me figure out what to do? Thanks!
import React from 'react'
import { match } from 'react-router'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import { syncHistoryWithStore } from 'react-router-redux'
import createMemoryHistory from 'react-router/lib/createMemoryHistory'
import { getStyles } from 'simple-universal-style-loader'
import Helmet from 'react-helmet'
import createStore from './store/createStore'
import AppContainer from './containers/AppContainer'
import _debug from 'debug'
import * as Assetic from './modules/Assetic'
import defaultLayout from '../config/layout'
// import { renderHtmlLayout } from 'helmet-webpack-plugin'
import { renderHtmlLayout } from 'modules/RenderHtmlLayout'
import PrettyError from 'pretty-error'
import config from '../config'
import { Resolver } from 'react-resolver'
import cookie from 'react-cookie'
global.localStorage = require('localStorage')
const debug = _debug('app:server:universal:render')
export default getClientInfo => async (ctx, next) => {
await new Promise((resolve, reject) => {
const initialState = {}
const memoryHistory = createMemoryHistory(ctx.req.url)
const store = createStore(initialState, memoryHistory)
const routes = require('./routes/index').default(store)
const history = syncHistoryWithStore(memoryHistory, store, {
selectLocationState: (state) => state.router
})
match({history, routes, location: ctx.req.url}, async (err, redirect, props) => {
debug('Handle route', ctx.req.url)
let head, content
let {app, vendor} = getClientInfo().assetsByChunkName
let links = Assetic
.getStyles(([vendor, app]))
.map(asset => ({
rel: 'stylesheet',
href: `${asset}`
}))
const handleError = ({status, message, error = null, children = null}) => {
if (error) {
let pe = new PrettyError()
debug(pe.render(error))
}
let title = `${status} - ${message}`
content = renderToStaticMarkup(
<div>
<Helmet {...{...layout, title}} />
<h3>{title}</h3>
{children}
</div>
)
head = Helmet.rewind()
ctx.status = 500
ctx.body = renderHtmlLayout(head, <div dangerouslySetInnerHTML={{__html: content}} />)
reject()
}
// This will be transferred to the client side in __LAYOUT__ variable
// when universal is enabled we need to make sure the client to know about the chunk styles
let layoutWithLinks = {
...defaultLayout,
link: links
}
// React-helmet will overwrite the layout once the client start running so that
// we don't have to remove our unused styles generated on server side
let layout = {
...layoutWithLinks,
style: getStyles().map(style => ({
cssText: style.parts.map(part => `${part.css}\n`).join('\n')
})),
script: [
...defaultLayout.script,
{type: 'text/javascript', innerHTML: `___INITIAL_STATE__ = ${JSON.stringify(store.getState())}`},
{type: 'text/javascript', innerHTML: `___LAYOUT__ = ${JSON.stringify(layoutWithLinks)}`}
]
}
// ----------------------------------
// Internal server error
// ----------------------------------
if (err) {
handleError({status: 500, message: 'Internal server error', error: err})
return
}
// ----------------------------------
// No route matched
// This should never happen if the router has a '*' route defined
// ----------------------------------
if (typeof err === 'undefined' && typeof redirect === 'undefined' && typeof props === 'undefined') {
debug('No route found.')
// We could call our next middleware maybe
// await next()
// return
// Or display a 404 page
handleError({status: 404, message: 'Page not found'})
return
}
// ----------------------------------
// Everything went fine so far
// ----------------------------------
let scripts = Assetic
.getScripts(([vendor, app]))
.map((asset, i) => <script key={i} type='text/javascript' src={`${asset}`} />)
Resolver
.resolve(() => (
<AppContainer
history={history}
routerKey={Math.random()}
routes={routes}
store={store}
layout={layout} />
)) // Pass a render function for context!
.then(({Resolved, data}) => {
cookie.setRawCookie(ctx.req.headers.cookie)
content = renderToString(
<Resolved />
)
head = Helmet.rewind()
let body = <div key='body' {...config.app_mount_point} dangerouslySetInnerHTML={{__html: content}} />
ctx.status = 200
ctx.body = renderHtmlLayout(head, [body, scripts], data)
resolve()
}).catch(err => handleError({status: 500, message: 'Internal Server Error', error: err}))
})
})
}
Maybe we can implement a clearAll method.
I can make a pull-request if you want.
i have strange problem i am use react-cookie and its work only in android .. i am using chrom in iphone and its not work , i am using chrom in android its work , what can be the problem ?
I can retrieve the cookie values in my react application except for one httpOnly cookie called "connect.sid". So I wonder if this is the problem?
Am using the following to create a httpOnly cookies. However the cookies is not created, Inspect mode in Chrome showing "The site has no cookies". The cookies should be visible with a tick on the HTTP column right? Cookies was created once I removed "httpOnly: true".
cookie.save('loginResult', user.token, { path: '/', httpOnly: true})
Any help would be appreciated. Thanks!
hi! I am saving a user id of 1 in my cookies with the name id. However, on some occasions, the cookie.load('id') gave me a totally different value such as 3. I checked the cookie on my browser and it is clearly 1. Do you happen to know what is wrong?
I am expecting cookie.save to save a cookie. The following code shows how document.cookies is empty after using the save function.
import cookie from 'react-cookie'
cookie.save('session', 'SESSIONTOKEN')
console.log(document.cookies) // => ""
console.log(cookie.load('session', true)) // => "SESSIONTOKEN"
What am I doing wrong or understanding wrong?
src=>cookie.js
const IS_NODE = typeof document === 'undefined' || (typeof module !== 'undefined' && module.exports);
When you are defining IS_NODE constant you have module and module.exports available, so the code sets wrong value to IS_NODE (it is always not 'false')
Also please check how logical operators work
typeof document === 'undefined' --> false
typeof module !== 'undefined' --> true
module.exports --> object
(false || (true && object)) === object
So as a result IS_NODE is always a reference to module.exports
And cookie would never be saved to document because of this code
if (!IS_NODE) {
document.cookie = cookie.serialize(name, _rawCookie[name], opt);
}
Please Make Is_Node checking as a function, something like that
function IS_NODE(){
return typeof document === 'undefined' || (typeof module !== 'undefined' && !!module.exports);
}
https://github.com/eXon/react-cookie/blob/master/index.js#L42
By default, it will execute JSON.parse
to parse the value. the problem is here. for example.
JSON.parse('99999999999999999'); //-> 100000000000000000
JSON.parse('10209033848396525'); //-> 10209033848396524
it is confused when I just want to set a cookie but getting the wrong value. I think it should not execute JSON.parse
by default. Or keep it simple and just leave this transform function to others.
If the cookie is updated in the browser, react-cookie won't see it since it doesn't detect/react to an updated cookie. For example, making an AJAX request that sets cookies, they won't be available by the load function. It looks like there's an up front loading of the cookie. Any new cookie data will just mean we're holding stale data.
What is the correct approach to set multiple paths for a cookie
{ path: [ '/path1', '/path2', ... ] }
or
{ path: '/path1, /patch2', ... }
My isomorphic react app uses cookies to authenticate users. When a user tires to access a private route that requires authentication a loginReferrer cookie is set. This is not done when rendering on the server. As a workaround I replace
the cookie.save
method with the express method (res.cookie) on each request. Check the example below.
// ExpressJS middleware for rendering react app on the server (react-router, alt, iso).
function render(req, res, next) {
cookie.setRawCookie(req.headers.cookie);
cookie.save = res.cookie;
let location = new Location(req.path, req.query);
Router.run(routes, location, (error, state, transition) => {
if (error) return next(error);
if (transition.isCancelled) return res.redirect(transition.redirectInfo.pathname);
Alt.bootstrap({});
let markup = ReactDomServer.renderToString(<Router {...state}/>);
let html = Iso.render(markup, Alt.flush());
res.render('index', {html});
});
}
I'm posting this question to see if others have a better solution to this problem. Maybe we could add a method that would patch the library on every request similar to the above.
// example ...
function render(req, res, next) {
cookie.patchHandler(req);
...
}
Hi,
i had the following issue that when i write cookies at the Servers they vanished nearly immediately.
It turned out that when i multiplied maxAge with 1000 it was correct (but still very ugly).
So at the client maxAge is in seconds and at the server in ms.
I am storing some integer values in cookies but the values being store and retrieved seem to be modified or rounded by React-Cookie.
I have created an example of the issue as well as a jsFiddle (https://jsfiddle.net/f1f6ae89/1/)
As can be seen in the example, the value 888565000007389097
is being stored/retrieved by React-Cookie as 888565000007389000
Any ideas why this is occurring?
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length,c.length);
}
}
return "";
}
class Test extends React.Component {
constructor(props) {
super(props);
}
handleSaveCookie() {
console.log("Cookie Saved");
reactCookie.save("mycookie", 888565000007389097, {maxAge: 60*60*24*7, path: "/"})
document.cookie="othercookie=888565000007389097"
}
handleLoadCookie() {
console.log(document.cookie);
console.log("mycookie from reactCookie:", reactCookie.load("mycookie"));
console.log("othercookie from ReactCookie:", reactCookie.load("othercookie"));
console.log("othercookie without ReactCookie:", getCookie("othercookie"));
}
render() {
return (
<div>
<button onClick={this.handleSaveCookie}>Save Cookie</button>
<button onClick={this.handleLoadCookie}>Load Cookie</button>
</div>
);
}
}
ReactDOM.render(<Test/>,
document.getElementById('container')
);
Hi.
When i try to load user id which is a large integer cookie.load will drop the last 4 digits of the id.
Expected value: "108858650188719526842"
Cookie.load output: 108858650188719520000
Any ideas how to fix this ?
Is cookie
dependency verision being used (0.1.x) a deliberate decision?
Current version is 0.3.x
https://github.com/jshttp/cookie/blob/master/HISTORY.md
Are there any drawbacks against updating it?
Hello,
when I do cookie.save('myCookie', 'test')
, I got this %22test%22
.
What is the reason to do JSON.strignify even if val is a string ?
Thanks!
So far this plugin is awesome. But I ran into a snag.
This alert gives me back an object no problem:
const obj = cookie.load("person", {}); alert( obj );
Parsed data in the alert box:
{"primary_name":{"full":"Ryan Mitch Smith","prefix":"Mr","first":"Ryan","middle":"Mitch","last":"Smith"}
However, when I do alert ( obj.primary_name );
it returns as undefined.
I feel like I'm missing something simple.
Cookies get destroyed when browser is closed.
This is my code snippet.
const rssPageLoadCount = cookie.load('rssPageLoadCount-hash'); if (rssPageLoadCount) { if (rssPageLoadCount < 5) { cookie.save('rssPageLoadCount-hash', rssPageLoadCount + 1, {path: '/'}); } } else { cookie.save(rssPageLoadCount-hash', 1, {path: '/'}); }
Until browser is open, the cookie behaviour works fine. Once I close and open browser again, and check in storage tab of developer console, I cannot find the cookie there
Just wanted to start off with saying this is a great minimal cookie library, but that is exactly what it is, just a cookie library. It doesn't have anything to do with React?
For the sake of making this package more accessible universally can I suggest that the package be renamed to something which doesn't include a framework.
How do I read cookies on server?
I save cookie in action creator:
cookie.save('userId', userId);
How do I load it on server? I know that I can access cookies in req.cookies
but I want to keep the logic in the right place. I do not want to edit server.js file.
When I do console.log(cookie.load('userId')
I get undefined in server console.
Is there a way to remove the cookie that was set via cookie.save() when the tab closes? Also how is it possible to set a session cookie. I set the cookie on the client side. I use this extension chrome-extension://iphcomljdfghbkdcfndaijbokpgddeno/editor.html to see my cookies and in the one that is set, the session check is not there.
Thanks
I set my cookies in 2 ways, note cookie
comes from var cookie = require('react-cookie')
Cookie for localhost:
cookie.save('sessionToken', '123')
Cookie for production
cookie.save('sessionToken', '123, { domain: 'my.domain.io', secure: true })
These set cookies correctly, the only strange observation I can see is that in production case, cookies domain is set to .my.domain.io
(has additional dot in front)
I then try to remove the cookie like so: cookie.remove('sessionToken')
which works as expected on localhost, but doesn't get rid of the cookie on production.
When i try to remove an cookie, i get the following error
Object.remove
/var/www/qm_2016/webapp2/node_modules/react-cookie/index.js:61:15
I can see that you are trying to access a variable named "path" that is not defined within that function.
Kind Reagrds,
Raymond
It seems to me an object is not saved as the "stringified" version.
https://github.com/eXon/react-cookie/blob/master/index.js#L29
Shouldn't it be ?
document.cookie = cookie.serialize(name, _rawCookies[name], opt);
Wouldn't it be useful to return saved value on react-cookie.save
call?
I want to write it as this:
export const getGuestId = () => (
cookie.load('guestId') || cookie.save('guestId', uuid.v1(), { maxAge: 31536000 })
);
But I have to write it as something like this:
export const getGuestId = () => {
const guestId = cookie.load('guestId');
if (guestId) {
return guestId;
}
const uniqueId = uuid.v1();
return cookie.save('guestId', uniqueId, { maxAge: 31536000 }) || uniqueId;
};
May be I'm missing something?
cookie.save('cookiename', JSON.stringify(data), {
path: '/',
expires: fortNightAway,
domain: 'https://*.mydomain.com',
})
My cookie is not being generated with the above code. fortNightAway is fine, the expiration is setting itself to the variable and the path is working well.
(Running on Chrome on a Mac, though I assume its a syntax issue.)
--- EDIT ------------------------------
cookie.save('cookiename', JSON.stringify(data), {
path: '/',
expires: fortNightAway,
},
{domain: 'https://*.mydomain.com'});
This code is now generating a cookie at least, but it isn't being passed on to the subdomain.
Correct me if I am wrong:
You have this : https://github.com/eXon/react-cookie/blob/master/index.js#L3
So you have only one place where the cookie are stored on the server.
If I call the plugToRequest
and then I have a one or more async requests on server before the rendering, there is the chance that the request of another user will overwrite the cookies. so a load
will read the cookie of another user.
In isomorphic environment, in order to fix this it is necessary either not to call plugToRequest
is a async context or the cookies need to be store in the context.
Hi,
Thanks for making this library, it is super helpful.
Right now when I try to use this with Hapi, it looks like the cookies are not stored when using plugToRequest
.
I think this is because hapi stores the cookies on request.state
and the function is not looking there.
Any thoughts on this?
Cheers
I can't believe this is actually a problem with the library, but is there some condition in my application that could be causing behavior like what I'm observing in this console screenshot?
https://www.dropbox.com/s/805pyfznabpyr54/Screenshot%202016-02-02%2012.57.18.png?dl=0
Other pages in the application appear to be working as expected.
Along with client side Example https://github.com/thereactivestack/react-cookie#example
would be great to see full example of server-side.
(sorry for duplicate #39 but would be really great to update readme)
Hi,
JSON.stringify ()
is not enough for me. For example, when l want to save a array to cookie, '[' and ']' will be Filtered.
If you use reactCookie to save a cookie in node whilst using plugToRequest
with express, then maxAge
requires milliseconds, not seconds
From the express 4.x docs:
...Convenient option for setting the expiry time relative to the current time in milliseconds.
See: http://expressjs.com/en/api.html#res.cookie
I can submit a PR with the fix if you like.. let me know!
Hi,
Great library! After trying out the SSR functionality I noticed that the library could potentially ignore Set-Cookie
header entries if the Cookie already came in with the request and is exactly the same as the one to be set.
Another thought I had was that it would probably make sense to ignore redundant Set-Cookie
entries with the same name. Right now every cookie action results with a Set-Cookie
, even if they are for a cookie with the same name.
I have an clientside / serverside setup.
When an user logs in an token cookie is set.
When i refresh the page to get all data fresh from the servers, this works correctly,
After logout and thus removing the cookie, somehow the servercode still see's the cookie.
I can see clearly ion the request that no cookie is send. The only way right now for me to get it working correctly is as below
if (typeof(req.headers.cookie) !== 'undefined') {
cookie.setRawCookie(req.headers.cookie);
} else {
//Force empty cookie
cookie.setRawCookie('cookie:');
}
I did not notice this behavior earlier on.
I am running
nodejs - 4.1.2
webpack: 1.12.2
react: 0.14
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.