Expiring cookies in native NodeJS - node.js

I'm trying to expire a cookie with native NodeJS, specifically for the chrome browser. However, the expiration date that I place doesn't cause the cookie to go away.
As of right now, here's my code:
var cookie = 'Expires=' + new Date();
response.setHeader('Set-Cookie', cookie);
I ended up getting cookies with the expiration date like so even after subsequent requests:
cookie: Expires=Wed Mar 22 2017 02:14:52 GMT-0400 (EDT)

You can set cookie expires and httpOnly using the below code.
res.cookie(myCookie, myValue, { expires: new Date(Date.now()+10000), httpOnly: true };
https://expressjs.com/en/api.html#res.cookie

Try This, It may work for you.
'Set-Cookie':'sesh=wakadoo; expires='+new Date(new Date().getTime()+86409000).toUTCString();
Replace sesh=wakadoo with your variable.

Related

Postman receive cookies with expires: never

I use express to create cookie like this
res.cookie(user[0].email, token, {expire: new Date(Date.now()) + 1200, httpOnly: true})
It works fine when receive cookie from server as well as send cookie in the request. The only problem is that when I open cookies tab in post man it shows the expires is never.
A few things are wrong here.
You're not setting the expiry correctly: the property is named expires.
Using the + operator on Date doesn't add time, it converts to a string and concatenates a number onto the end, which is not what you want.
Check your math. JavaScript date units are typically milliseconds. Do you really want this cookie to expire 1200 milliseconds (1.2 seconds) after it's set?
This will fix the first two points:
res.cookie('abc#d.com', 'foo', { expires: new Date(Date.now() + 1200), httpOnly: true })

How to maintain a cache of the public keys from Google's OpenID Connect discovery document

I am working on a Node.js server side validation of json web tokens received from cross origin ajax clients. Presumably the tokens are generated by Google OpenID Connect which states the following:
To use Google's OpenID Connect services, you should hard-code the Discovery-document URI into your application. Your application fetches the document, then retrieves endpoint URIs from it as needed.
You may be able to avoid an HTTP round-trip by caching the values from the Discovery document. Standard HTTP caching headers are used and should be respected.
source: https://developers.google.com/identity/protocols/OpenIDConnect#discovery
I wrote the following function that uses request.js to get the keys and moment.js to add some timestamp properties to a keyCache dictionary where I store the cached keys. This function is called when the server starts.
function cacheWellKnownKeys(uri) {
var openid = 'https://accounts.google.com/.well-known/openid-configuration';
// get the well known config from google
request(openid, function(err, res, body) {
var config = JSON.parse(body);
var jwks_uri = config.jwks_uri;
var timestamp = moment();
// get the public json web keys
request(jwks_uri, function(err, res, body) {
keyCache.keys = JSON.parse(body).keys;
keyCache.lastUpdate = timestamp;
keyCache.timeToLive = timestamp.add(12, 'hours');
});
});
}
Having successfully cached the keys, my concern now is regarding how to effectively maintain the cache over time.
Since Google changes its public keys only infrequently (on the order of once per day), you can cache them and, in the vast majority of cases, perform local validation.
source: https://developers.google.com/identity/protocols/OpenIDConnect#validatinganidtoken
Since Google is changing their public keys every day, my idea with the timestamp and timeToLive properties of keyCache is to do one of two things:
Set a timeout every 12 hours to update the cache
Deal with the case where Google changes their public keys in between my 12 hour update cycle. The first failed token validation on my end triggers a refresh of the key cache followed by one last attempt to validate the token.
This seems like a viable working algorithm until I consider an onslaught of invalid token requests that result in repeated round trips to the well known config and public keys while trying to update the cache.
Maybe there's a better way that will result in less network overhead. This one line from the first quote above may have something to do with developing a more efficient solution but I'm not sure what to do about it: Standard HTTP caching headers are used and should be respected.
I guess my question is really just this...
Should I be leveraging the HTTP caching headers from Google's discovery document to develop a more efficient caching solution? How would that work?
The discovery document has property jwks_uri which is the web address of another document with public keys. This other document is the one Google is referring to when they say...
Standard HTTP caching headers are used and should be respected.
An HTTP HEAD request to this address https://www.googleapis.com/oauth2/v3/certs reveals the following header:
HTTP/1.1 200 OK
Expires: Wed, 25 Jan 2017 02:39:32 GMT
Date: Tue, 24 Jan 2017 21:08:42 GMT
Vary: Origin, X-Origin
Content-Type: application/json; charset=UTF-8
X-Content-Type-Options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
Content-Length: 1472
Server: GSE
Cache-Control: public, max-age=19850, must-revalidate, no-transform
Age: 10770
Alt-Svc: quic=":443"; ma=2592000; v="35,34"
X-Firefox-Spdy: h2
Programmatically access these header fields from the response object generated by request.js and parse the max-age value from it, something like this:
var cacheControl = res.headers['cache-control'];
var values = cacheControl.split(',');
var maxAge = parseInt(values[1].split('=')[1]);
The maxAge value is measured in seconds. The idea then is to set a timeout based on the maxAge (times 1000 for millisecond conversion) and recursively refresh the cache upon every timeout completion. This solves the problem of refreshing the cache on every invalid authorization attempt, and you can drop the timestamp stuff you're doing with moment.js
I propose the following function for handling the caching of these well known keys.
var keyCache = {};
/**
* Caches Google's well known public keys
*/
function cacheWellKnownKeys() {
var wellKnown= 'https://accounts.google.com/.well-known/openid-configuration';
// get the well known config from google
request(wellKnown, function(err, res, body) {
var config = JSON.parse(body);
var address = config.jwks_uri;
// get the public json web keys
request(address, function(err, res, body) {
keyCache.keys = JSON.parse(body).keys;
// example cache-control header:
// public, max-age=24497, must-revalidate, no-transform
var cacheControl = res.headers['cache-control'];
var values = cacheControl.split(',');
var maxAge = parseInt(values[1].split('=')[1]);
// update the key cache when the max age expires
setTimeout(cacheWellKnownKeys, maxAge * 1000);
});
});
}

determine when cookie will expire with node Request module

I'm writing an app that builds an API through scraping an external domain. In order to scrape the domain, my server must be authorized ( with a session cookie ).
I'm using the request module with a cookie jar to maintain the cookies across requests.
I want to set up some Node router middleware so that, if/when the session expires, I can re-run my authentication method. Think something like this:
export function validate(req, res, next) {
const cookie = cookieJar.getCookie('**target domain**');
const COOKIE_IS_EXPIRED = // ???
if ( COOKIE_IS_EXPIRED ) {
authenticate().then(next);
} else {
next();
}
}
When I log out the contents of cookieJar.getCookies() my result is something like the following:
[ Cookie="lw_opac_1=1483019929431275955; Expires=Wed, 29 Mar 2017 13:58:49 GMT; Max-Age=7776000; Path=/opac; hostOnly=true; aAge=0ms; cAge=6345ms",
Cookie="lw_opac=ta4tscsejs6c94ngikt7hlbcn0; Path=/; hostOnly=true; aAge=0ms; cAge=6347ms" ]
how can I validate when that both cookies are close to / have expired, and then re-run my auth function?
Thanks!
You can use the cookie module from npm to parse the cookies.
So, for example when you have a string like you posted:
var c = "lw_opac_1=1483019929431275955; Expires=Wed, 29 Mar 2017 13:58:49 GMT; Max-Age=7776000; Path=/opac; hostOnly=true; aAge=0ms; cAge=6345ms";
then running:
console.log(cookie.parse(c));
will result in printing:
{ lw_opac_1: '1483019929431275955',
Expires: 'Wed, 29 Mar 2017 13:58:49 GMT',
'Max-Age': '7776000',
Path: '/opac',
hostOnly: 'true',
aAge: '0ms',
cAge: '6345ms' }
You can use the Max-Age and Expires fields and use moment to parse them and compare them to the current time.
With moment you can compare the given date with today and get the number of hours or days of the difference. For example this:
moment().isAfter(someDate);
will tell you if that date has already passed (so if it's the expiration date then it will tell you if the cookie has expired).
See:
https://www.npmjs.com/package/cookie
https://www.npmjs.com/package/moment
#rsp answer correct. But if you are going to maintain access security token you should move on csrf token which automatically maintain client side cookie and generate token for new session. For more detail http://www.senchalabs.org/connect/csrf.html

Making successful requests but cookies are not being set

When I make requests to a server with Postman(an api service), chrome automatically makes a cookie. However, when I make a request with my nodejs server, the cookie is not being made even thought the request is successful.
//Headers
var options = {
method: 'GET'
};
options.headers = {};
options.headers.Authorization = auth;
options.url = urlm;
console.log(options);
request(options, function(error,response,body) {
res.status(200).send(response.headers);
});
The response header is
{"date":"Tue, 23 Feb 2016 20:06:57 GMT","server":"Jetty(9.2.1.v20140609)","x-csrf-header":"X-CSRF-TOKEN","expires":"Thu, 01 Jan 1970 00:00:00 GMT","x-csrf-token":"xxxxxxxxxxx","cache-control":"no-store","content-type":"audio/mpeg","set-cookie":["JSESSIONID=uiqwnksadbohqjkq675d;Path=/;HttpOnly"],"connection":"close","transfer-encoding":"chunked"}
Pass { jar: true } in your request options.
From the documentation:
jar - If true, remember cookies for future use (or define your custom cookie jar; see examples section)

Destroy cookie NodeJs

I am using Cookies module for setting cookie. Here is following my code:
var options = {
maxAge: ALMOST_ONE_HOUR_MS,
domain: '.test.com',
expires: new Date(Date.now() + ALMOST_ONE_HOUR_MS)
};
var value = userInfo.token;
cookies.set("testtoken", value, options);
But in documentation I haven't found how to destroy this cookie.
Any suggestion would be appreciated.
For webapp you can just set cookie in response as :
res.cookie("key", value);
and to delete cookie :
Ref: https://expressjs.com/en/api.html#res.clearCookie
res.clearCookie("key");
and don't forget to:
res.end()
to avoid the web request hanging.
There is no way to delete a cookie according to the HTTP specification. To effectively "delete" a cookie, you set the expiration date to some date in the past. Essentially, this would result in the following for you (according to the cookies module documentation):
cookies.set('testtoken', {maxAge: 0});
Or according to the HTTP specification:
cookies.set('testtoken', {expires: Date.now()});
Both of which should work. You can replace Date.now() with new Date(0) for a really old date.
While one other answer is correct, deleting a cookie from an express.js webapp is done by invocing the following method:
res.clearCookie("key");
But there's a caveat!
Your cookie options (except expires) need to be the same as when you set it. Otherwise browsers will NOT remove the cookie. So use the same domain, security setting etc. (reference: https://expressjs.com/en/4x/api.html#res.clearCookie)
I'm using this with cookie-parser module:
router.get('/logout', function(req, res){
cookie = req.cookies;
for (var prop in cookie) {
if (!cookie.hasOwnProperty(prop)) {
continue;
}
res.cookie(prop, '', {expires: new Date(0)});
}
res.redirect('/');
});
I was going through the same problem a few days ago. After discussing it with a friend, I think this is the best solution.
res.setHeader('set-cookie', 'mycookie=; max-age=0');
Advantages:
only use node
simple to understand
credits: #andy
To delete any http cookie if we just try to clear it from response [using res.clearCookie("key")], it is definitely not going to work. In reality, to delete http cookie, domain and path are very important.
Domain and path define the scope of the cookie. In face, they essentially tell the browser what website the cookie belongs to.
Sending the same cookie value with ; expires appended is also a bad idea since you want the content to be destroyed, but that is not going to happen.
The best idea would be invalidating the cookie by setting the value to empty and include an expires field as well like below:
res.cookie("key","empty the key content", {expires:old date, domain:'.example.com', path:'/'});
res.cookie("token", "", { expires: new Date(0),domain:'.test.com', path: '/' });
Hope this helps!!!
I am using cookie-parser as well, and upper answers lead me to the solution. In my case I needed to add overwrite: true as well, otherwise new cookie key was added.
So my final solution looks like:
res.cookie('cookieName', '', {
domain: 'https://my.domain.com',
maxAge: 0,
overwrite: true,
});
When using in production with SSL, you need to specify the domain. This domain must correspond to the one, which is used to store the cookie!
For example:
res.clearCookie('sid', {domain: ".somedomain"})
create cookie with expires time
res.cookie("keyname", data, {
expires: new Date(Date.now() + 1000 * 60 * 15),
})
Remove cookie
res.clearCookie("key name here");
I have tried all the solutions, and none worked until I found this one.
I set up my cookie like this:
res.writeHead(200, {
"Set-Cookie": `token=${accessToken}; HttpOnly; path=/`,
"Access-Control-Allow-Credentials": "true",
});
res.end();
Then destroyed it like this:
res.writeHead(200, {
"Set-Cookie": `token=; HttpOnly; path=/; max-age=0`,
});
res.end();
Another way to destroying cookies from the server. Just set negative integer as a maxAge. One more thing that keep in mind, don't forget to set a path when will set or destroy cookie.
The Best way to doing this
before you set the like token you should remove that first
like that
res.clearCookie('token');
res.cookie('token',token, { maxAge: 900000, httpOnly: true });

Resources