-
Notifications
You must be signed in to change notification settings - Fork 2k
Conversation
}, | ||
jwt: { | ||
secret: process.env.TOKEN_AUTH_SECRET || 'M3@N_R0CK5!', | ||
expiresInSeconds: process.env.TOKEN_AUTH_EXPIRES_SECONDS || 200 * 60 * 60 // 200 hours |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 200 hours?
Did a quick read through, didn't comment on everything. @trainerbill can you give the pros and cons of JWT and any limitations of this implementation? |
@trainerbill This looks pretty good. I'm gonna pull it down and play around with it. The other day, I started looking at using the passport-http-bearer module. I think the module you're using is probably better, but what are the advantages of this one over the bearer? One thing I started playing around with, mostly in thought, was to think of MEAN Token-auth as just another Provider. If we use a passport module for authenticating the JWT Token, can we merely treat it as a new Provider, and have it behave the same (just as Google, Twitter, GitHub, etc)? Think of having a MEAN.JS logo mixed in with the other providers at time of sign in or sign up. The project user could decide if they want to allow either authentication method, or both. It think it could allow the project to be easily switched to and from JWT & Session based authentication. Any thoughts on that approach? |
@ilanbiala Thanks for the feedback. This is more of a rough draft than a code review so don't worry about new lines etc. I am just looking for an overall discussion on the topic. My goal is to get away from the current AuthService that reads from window.user and JWT is kinda the norm right now. JWT is becoming the defacto standard for authenticating REST services. The biggest pro is that it will work with mobile. Session based auth will not. A mobile app could be coded to hit the auth/sigin URL store the token and then make additional calls to the MEAN backend. Most applications are going away from Session based authentications as they are not mobile friendly. I am sure there are other benefits but those are the 2 I can think of off hand. With JWT the client holds the keys instead of the server. As for limitations, I am not aware of any. Perfomance should be the same as it is the same amount of DB calls, just an added token decode which isn't much. @mleanos The module you linked looks more like an oAuth strategy. I like the passport-jwt strategy as it works with our current auth procedure and you can make it route based. So if I have a public endpoint I don't do the passport.authenticate. How I implemented it really is just another provider. As far as switching between session and JWT, I don't see the point. If you look at how passport and express currently work, only the _id is stored and there is a DB call to get the rest of the info: So the JWT approach is the same DB calls, as you decode the token, get the ID and find the user. Plus it has the added benefit of being client independent. Mobile devices, and any other client would be able to authenticate and use the REST interfaces. For your question on if we can treat it as another provider, the answer would probably be no. You still need a user/pass combo to authenticate a user and the token is merely a reflection of that authentication. The "local" strategy now just checks the user/pass combo and returns the user info and the token. This will be how providers work when I get to them. The same steps as far as auth, but when it comes back we send a token to the AuthService and everything works as normal. Like the discussion, lets keep it up. Want everything ironed out before doing more work! |
I'm totally onboard with this PR. I like token auth vs. session auth. It makes scaling the app to more than 1 server much easier. |
@codydaig awesome, I will continue to work on this then. I think it will solve a lot of the other open issues as well What do you all think of changing up the routes a bit: Pros:
Cons:
I personally like it, but want some feedback. |
I personally am not usually a fan of the express router because it usually adds unnecessary complexity. However, I think it could be of benefit here to help keep things more modular. I think that is a huge undertaking though because I would like to keep it consistent throughout the framework. |
@codydaig Yeah I know... but this whole PR is gonna be a huge undertaking... I know in one of my apps the app.param collision screwed me. |
@trainerbill Doing things in smaller PRs is what I usually like to go for. It makes it easier to review, discuss, and get merged. My vote would be to have the router refactor be its own PR. |
@codydaig True. However adding passport.authenticate(jwt) to every route is going to be kind of a pain. |
@trainerbill if possible, @codydaig's suggestion of keeping changes in smaller PRs will definitely speed up the whole conversion process. @mleanos has a PR (#1121) that seems to also implement JWT instead of sessions and his is slightly smaller in impact. @trainerbill can you and @mleanos can combine PRs to create a better one that has less impact and incorporates the changes of both? |
@ilanbiala I understand that smaller PR's are easier and will try to keep it as small as possible, but this is a large change. I have spoken with @mleanos and offered for him to assist. His current PR isn't close to being complete, and will need 90% of the changes in this PR. On the plus side I am almost done. I need some help on the chat module. Anyone familiar enough with the module and socket.io to make the auth changes? I found this article but I am not at all familiar with this module or socket.io http://wmyers.github.io/technical/nodejs/Simple-JWT-auth-for-SocketIO/ |
@trainerbill I can help out with the Socket.IO changes My intentions with my PR was to keep the server-side implementation independent from the client-side. Really those two things are separate. It looks like most of your server-side changes are the same that I implemented in my PR. My suggestion from the beginning of working on this, was to work on a shared branch; with client-side & server-side changes made independent of one another. So shall I submit PR's to your branch? |
@mleanos Absolutely. I don't think you can really keep client/server in independent PR's. In order to make sure that it is working you have to remove the session authentication. Otherwise the app will continue to use session and JWT so you really don't know if the changes you are making are working as expected with JWT. I will be AWK till a little later tonight and will check back in. Can some of you pull the branch and take it for a spin? It should be in a semi workable state. Whats currently working:
Whats not working:
@mleanos If you are working on specific items let me know and I will stay away from them. Thanks Everyone! |
@trainerbill |
+1 on this. Have been waiting for token based auth for awhile now (main use case is sharing of REST APIs with mobile). |
Can someone look into CSRF with JWT? I don't think we need the CSRF PR's after this goes in. |
Anyone have any thoughts on the following file: config/lib/jwtAuthentication.js I think it should go in the users module since that is where the authentication is taking place. Just not sure where to put it, controllers?, and what to name it. |
var token = jwt.sign(payload, config.jwt.secret, options); | ||
|
||
resolve(token); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra newline
All. I have this PR about ready. I will do the Password Reset this afternoon:
The coverall tests decreased because it looks like there is a duplicate in the user tests |
@@ -60,8 +60,8 @@ module.exports = { | |||
callbackURL: '/api/auth/github/callback' | |||
}, | |||
paypal: { | |||
clientID: process.env.PAYPAL_ID || 'CLIENT_ID', | |||
clientSecret: process.env.PAYPAL_SECRET || 'CLIENT_SECRET', | |||
clientID: process.env.PAYPAL_ID || 'AVWxUS4uQVfXAzKdCQKrIkczdPxixgKQ-SA7Ewodn9UmLOjHSCkftB6D9Wj_lVjRZpF9VCanp7thMCeG', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These probably shouldn't be here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol. good thing that wasn't production...
@trainerbill I managed to run the branch. As soon as nodemon has started got this error:
Am I doing it wrong or did I find an issue to resolve? |
@trendzetter Tests still pass so this should not be an issue. MY guess is that you have a dependency issue. Pull the branch and make sure you NPM Install |
You are correct. I forgot in all the rush to get this going.. |
I tested this and hope to see this merged. It would improve greatly on security. |
@trainerbill ok, a lot has been going on in this PR so I'd need to free up some time to get it resolved in several PRs. |
@@ -37,5 +37,12 @@ module.exports = { | |||
fileSize: 1*1024*1024 // Max file size in bytes (1 MB) | |||
} | |||
} | |||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jwt: { secret: process.env.TOKEN_AUTH_SECRET || 'M3@N_R0CK5!', options: { //Anything From https://www.npmjs.com/package/jsonwebtoken expiresIn: process.env.TOKEN_EXPIRES || '1d' } }
Basically not a big deal but gives a formatting warning.
@trainerbill maybe you know if you tested for this?/If I messed it up ? |
I am getting forbidden when trying to access articles/create when signed out. |
If I use 2 tabs and log out in one I can continue my session with my token in the other tab as long as I do not refresh the page. |
@@ -85,7 +85,7 @@ module.exports = function (app, db) { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stuff above here talks about sessionSecret sessionId not sure if that's need/was causing my problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the above code (everything about Session and cookies and everything worked just fine! Except the tests I guess... so might have to change those
FYI one issue is that signout has to kill the token in the $http header. |
@trainerbill I've just read your comment about CSRF protection. If meanjs no longer use cookies, you don't need to worry about cross requests. In other words, with JWT you don't need CSRF protection. |
@trainerbill Saw your comment above you are working on a fork with JWTAuth and Material design. Any chance you're willing to share that branch? It's exactly what I'm after. |
@jameslegue I do. Hit me up on gitter |
Let's rebase this and finalize everything. @mleanos @trainerbill @codydaig can we work out the rest of the kinks? |
Hey guys, I think I've found an issue. req.user is undefined in articles.server.policy.js so it always defaults to 'guest' role. |
Fixed it by adding this to the articles.server.routs.js file just before the routes are declared
|
Just realized that the get route intentionally doesn't have authentication. What do you guys think about authenticating if there's a token, but continuing if there isn't. This would leave the policy to decide whether the route should be accessible to guests |
@avingochea IMO, we should attempt to authenticate on each request. Thus, the responsibility of API access will solely reside in the server policies. |
That adds to much logic to the policy. Just attached the passport Middleware to the route that you want to secure like it's designed to do. |
@trainerbill this by far adds so much code that I'm incapable of code reviewing that. |
I took a stab at redoing the Authentication in favor of JWT. I am using passport-jwt to leverage the existing authentication structure. The Authentication service now holds a user and token and uses localStorage to store the token. I am only storing the token. If you refresh the page the AuthService will look for a token in local storage and if it exists hits the users/me route to get the user. The auth service also sets the $http header for Authorization if the token exists so you don't have to add it to other services. Currently working:
I want to get buy in from contributors before going any further. This PR will touch a lot of files and I don't want to get all the way done and someone has a problem and this ends up in PR hell. If I can get some feedback and +1's I will have this done by Friday this week. Also would like a volunteer to help fix the tests when this is done and ready. Thanks to @mleanos for the server side kick start.
@mleanos @lirantal @ilanbiala @codydaig
Fixes #389
Fixes #1086