Using node.js with Express. This question also pertains to Connect since that's the Express sub-component in question.
I receive a signed cookie from the client over socket.io. Then I take the value of it which is in this format:
s:sessionID.signature
Currently to validate this I had to manually require the cookie-signature module and use its unsign method, which requires me to .slice(2) the s: off of this string, and just feels kludgy.
Is there a convenience method for this? I feel like I ought to be able to just do something like:
mySessionID = express.unsignCookie(thisCookie, forThisSessionIDKey, withThisSecret);
But no such method exists... am I missing something?
Oh, BTW, I can't access res/req due to being in socket.io... Which is why I'm having to pass the session ID over from the client's cookie in the first place...
Here was the solution I ultimately found. Inside socket.js:
var parseSignedCookie = connect.utils.parseSignedCookie;
...
socket.on('taste:cookie', function (data, callback) {
var sid = data.sid;
sid = parseSignedCookie(sid['connect.sid'], "mySecret");
Related
When using ctx.cookies.set(), KOA adds a 'set-cookie' header to the response. However, ctx.cookies.get() retains the cookie (if any) from the original request. This seems counter-intuitive if I'm overwriting it. Is there not a way to have the getter reflect the new value immediately, in the same request?
h = uuidv4();
console.log('set new cookie',h);
ctx.cookies.set('uuid',h,{httpOnly:false,overwrite:true});
//This outputs undefined or the value that came with the request,
//not the newly assigned value:
console.log('cookie is',ctx.cookies.get('uuid'));
I'm fairly new to node.js. What I'm looking for is something like PHP's $_SESSION[], in which values are updated and available immediately as well as being written to the response cookie. I understand I could pile the new uuid into ctx.state, but it seems cleaner to just be able to access ctx.cookies.get() anywhere further down the middleware chain and have access to what I just set it to.
Having a set() that doesn't change the result of its get() seems like code smell to me. Am I missing something?
Let's say I want to pass to an ExpressJS route callback an object.
I know I can append to app:
// router.js
const getFoo = (req, res) => res.json(req.app.foo);
// index.js
const app = express();
app.foo = {};
app.get('/foo', getFoo);
or I can use a higher order function:
// router.js
const getFoo = foo => (req, res) => res.json(foo);
// index.js
const app = express();
const foo = {};
app.get('/foo', getFoo(foo));
Both are easy to write, extend and test.
But, I don't know the implications of the solutions and whether one is better.
Is there anyone knowing real differences between the two approaches?
I think the second solution is more correct, here's why.
imagine you get used to the first solution and one day you need to send something called post or get or anything with the name of app property and you forget that there is already a property named like that, so you override original property without even realizing and when you call app.post() program will crash.
Believe me, you don't want hours of research wasted on something like that and realizing that you simply overrode original method
Also, in my opinion, it's always a bad idea mutating original object which wasn't generated by you
As #vahe-yavrumian mentioned it is not a good idea to mutate the state of the object created by a third party library.
between you can also use app.get() and app.set() methods to pass any data to the other routers in the queue (seems those methods are there just for this purpose.)
more information at https://expressjs.com/en/api.html.
The second solution easily allows you to pass different value for foo on different routes, if you ever found a need to do that.
The first solution essentially puts the value on the app singleton, which has all the implications of using singletons. (And as mentioned by #Anees, for express specifically the app settings with get and set are the proper place to store this, not a custom property)
I wonder how to access req object if there's no 'req' parameter in callback.
This is the scenario:
In ExpressJs, I have a common function, it uses to handle something with 'req' object, but not pass req into it.
module.exports = {
get: function(){
var req = global.currentRequest;
//do something...
}
}
My current solution is that I write a middleware for all request, I put the 'req' in global variable, then I can access the 'req' everywhere with 'global.currentRequest'.
// in app.js
app.use(function (req, res, next) {
global.currentRequest= req;
next();
});
But I don't know if it's good? Can anyone have suggestions?
Thanks a lot!
The only proper way is to pass the req object through as an argument to all functions that need it.
Stashing it in a global simply will not work because multiple requests can be in process at the same time if any requests use async calls as part of their processing and those multiple requests will stomp on each other making a hard to track down bug. There are no shortcuts here. Pass the current request as an argument to any code that needs it.
You cannot put request-specific data into a global in node.js, ever. Doing so will create an opportunity for two requests that are in-flight at the same time to stomp on each other and for data to get confused between requests. Remember, this is a server that is potentially handling requests for many clients. You cannot use synchronous, one-at-a-time thinking for a server. A node.js server may potentially have many requests all in flight at the same time and thus plain globals cannot be used for request-specific data.
There is no shortcut here. You will just have to pass the req object through to the function that needs it. If that means you have to change the function signature of several intervening functions, then so-be-it. That's what you have to do. That is the only correct way to solve this type of problem.
There are some circumstances where you may be able to use a closure to "capture" the desired req object and then use it in inner functions without passing it to those inner functions, but it does not sound like that is your function structure. We'd have to see a lot more of your real/actual code to be able to know whether that's a possibility or not.
Actually, this is possible with something like global-request-context
This is using zone.js which let you persist variables across async tasks.
I'm having a heck of a time here trying to use google OAuth to authenticate users in my node express app. I can successfully do the OAuth, which returns a response like so:
{
access_token: 'token string',
id_token: 'id.string',
expires_in: 3599,
token_type: "Bearer"
}
This all makes sense, but I can't for the life of me figure out how to decode the JWT. I am a bit inexperienced in all this, so this is all a bit foreign to me.
Following the instructions listed here: https://developers.google.com/accounts/docs/OAuth2Login#validatinganidtoken I am attempting to decode the JWT locally in my node app.
I installed https://github.com/hokaccha/node-jwt-simple in my node environment.
And I'm pretty certain I need to use this certificate (https://www.googleapis.com/oauth2/v1/certs) in all this somehow to decode it, but I am at a bit of a loss here. I don't really understand how I get the certificate into my node app, and after that how to use it with node-jwt-simple. And I also don't really understand how I know when I need to pull a fresh certificate, vs using a cached one.
Anyone out there with some experience in this that can help me out?
Thanks for any help. I'm totally at a loss at this point.
** Update **
So I have made some progress... Kind of.
By calling jwt.decode(id_token, certificate, true); I am able to successfully decode the token. Even if the certificate var is an empty object {}. This leaves me with 3 questions still.
1: What is the best way to get the certificate into my express app using the url from google?
2: How will I know when I need to pull in a fresh version of it?
3: It seems like passing in true for noVerify (3rd arg in jwt.decode) is a terrible idea. How can I get that to work without passing that in?
It looks like perhaps jwt-simple is expecting hs256 and the token is using rs256.
Again, I'm super inexperienced in this, so I may be way off base here.
* UPDATE *
Thanks to the help from Nat, I was able to get this working!
I think I tried every single JWT and JWS node module out there. What I finally landed on is as follows:
I found that none of the modules that I looked at did quite what I wanted out of the box. I created the following jwt decoding helper methods that I am using to decode the id_token, so I can get the kid from the header.
module.exports = {
decodeJwt: function (token) {
var segments = token.split('.');
if (segments.length !== 3) {
throw new Error('Not enough or too many segments');
}
// All segment should be base64
var headerSeg = segments[0];
var payloadSeg = segments[1];
var signatureSeg = segments[2];
// base64 decode and parse JSON
var header = JSON.parse(base64urlDecode(headerSeg));
var payload = JSON.parse(base64urlDecode(payloadSeg));
return {
header: header,
payload: payload,
signature: signatureSeg
}
}
}
function base64urlDecode(str) {
return new Buffer(base64urlUnescape(str), 'base64').toString();
};
function base64urlUnescape(str) {
str += Array(5 - str.length % 4).join('=');
return str.replace(/\-/g, '+').replace(/_/g, '/');
}
I am using this decoding to determine if I need to pull in a new public cert from: https://www.googleapis.com/oauth2/v1/certs
Then I am using that public cert and node-jws (https://github.com/brianloveswords/node-jws) jws.verify(id_token, cert) to verify the signature!
Hooray!
Thanks again for the extra explanation you gave in your response. That went a long way in helping me understand what I was even trying to do. Hope this might help others too.
From the specification point of view, what you are encountering is [OpenID Connect].
id_token is a [JWS] signed [JWT]. In this case, it is a "." separated string with three components. The first portion is the header. The second is the payload. The third is the signature. Each of them are Base64url encoded string.
When you decode the header, you will get something like:
{"alg":"RS256","kid":"43ebb53b0397e7aaf3087d6844e37d55c5fb1b67"}
The "alg" indicates that the signature algorithm is RS256, which is defined in [JWA].
The "kid" indicates the key id of the public key that corresponds to the key used to sign.
Now I am ready to answer some of your questions:
2: How will I know when I need to pull in a fresh version of it?
When the kid of the cached cert file (a [JWK] file) does not match the kid in the header, fetch a new cert file. (BTW, the URL from which you pull the certs are called x5u.)
3: It seems like passing in true for noVerify (3rd arg in jwt.decode)
is a terrible idea. How can I get that to work without passing that
in?
Indeed. Perhaps you might want to look at another library such as kjur.github.io/jsjws/ .
References
[OpenID Connect] openid.bitbucket.org/openid-connect-core-1_0.html
[JWS] tools.ietf.org/html/draft-ietf-jose-json-web-signature
[JWT] tools.ietf.org/html/draft-ietf-oauth-json-web-token
[JWK] tools.ietf.org/html/draft-ietf-oauth-json-web-keys
[JWA] tools.ietf.org/html/draft-ietf-jose-json-web-algorithms
How is the 'cookie' global object supposed to work on xPages? It is a map, so I can check the cookie existence easily, but how to create a new cookie? Using cookie.name="value" raises an error because, as supposed, the cookie must be some object with params like expiration etc. But what kind of the object it is? I can't find any suitable documentation for this or I miss something.
cookie object represents a map of cookie values of the request instance. So you cannot use it because 'setting cookie' means 'adding cookie to the response'.
So, as the article suggests, you have to use response object.
var response = facesContext.getExternalContext().getResponse();
var userCookie = new javax.servlet.http.Cookie("name", "value");
userCookie.setMaxAge(60*60*24*365*10); // set age in seconds...
userCookie.setPath("/"); // cookie will be valid under this path
response.addCookie(userCookie);
I can not give an answer on the cookie global object, but the following article shows how to manage cookies in XPages using the javax.servlet.http.Cookie class:
http://www-10.lotus.com/ldd/ddwiki.nsf/dx/cookie-management.html
Maybe the cookie global object expects an object of type javax.servlet.http.Cookie?
Have you tried using resources and defining meta tag as Set-Cookie?