-
Notifications
You must be signed in to change notification settings - Fork 118
JWT Cookie #389
Comments
On a side note, I wanted to ask if the Authentication 1.0.2 should populate the Users' table with more than the {provider}Id column. Currently I can only see the that column getting populated while the others are null. I'm using mySQL and Sequelize to back up the Users service. |
Addressing your side note first:
OAuth plugins will populate a column that matches the provider name. So with GitHub auth, you'd see a |
@muvhaus-sl I'm not experienced with React Native, yet. Last month we created the feathers-authentication-popups module that helps handle the auth workflow for web apps. We've discussed how to use it for React Native, but we have yet to implement it. It's one of the very next things on the list, though. Maybe @ekryski can pitch in when he returns. |
The reason that it only adds |
@daffl , Is there any example that I can refer to? Sorry if I'm being too demanding. It has been a very steep learning curve to get where I am, hopefully I can gain understanding and contribute back soon enough. |
@marshallswain Perhaps the viable solution would be for the feathers client to have a widget like Auth0's lock? However, I must say, its a lot of trouble and I think it is not part of the scope of what Feathers is trying to do? I don't think there is a clean way of doing a client side "widget" if OAuth providers start having different requirements... |
experiencing the same issue as in the original question. In my case, I'm trying to migrate the 0.7.x
The redirect part works. However, after trying for a couple hours I too couldn't get the authToken to show up in the cookie after redirect. Tried manually setting All of that to say, I'm pretty confused |
@jiangts,
Then, the other thing I did to find out the reasons was to set the debug flag for "feathers-authentication*" |
Hi @muvhaus-sl, I followed your suggestion and got the following log:
Still not sure where setCookie failed... Did you get something similar? |
@jiangts I did not use Express, so the Expose-cookies is not triggered. On my case it uses Set-cookies. |
I figured it out. However, I haven't gotten a flow that's as easy/simple as the version in 0.7.x with both setting the cookie and also redirecting the user. In fact, I had to write quite a bit of code on my own instead of just "glue" code over feathers-auth. I'm not sure if this is intentional for such a common use case (just a normal login), or maybe I'm missing something, but in either case, this wasn't anything like pleasant experience I've had so far with feathers :( For future people, my solution was to create a new service called |
So @marshallswain can probably explain this much better than me but the problem of allowing the JWT in a cookie for all API endpoints (and why it has been removed) is that the API will become vulnerable to Cross Site Request Forgery (CSRF), so if someone hijacks a users browser they can make any authorized requests to the API. This is why only specific routes should be explicitly enabled for cookies. Maybe @ekryski can weight in if there is something else that can be done better for your usecase though. |
@muvhaus-sl @jiangts can you post a link to a github repo? Quite frankly, there might be a bug in setting the cookie but it also might be that you just have things set up a different way. @jiangts the intention is for it to work the same as 0.7.x but there are a few more scenarios that we are covering now so we have those extra guards in the set-cookie middleware. |
I also was having a similar issue. Perhaps I am misunderstanding something. One of the purposes of enabling cookies is to have non-SPAs (old school apps) be able to authenticate without having to set up tokens in the header, correct? Otherwise I don't see the purpose of the cookie being saved in the browser and resent along with every request. And yet you say that due to CSRF cookies are disabled on all routes (if I'm understanding you.) I thought that enabling the cookie option in the config allows cookies on all routes, and the authentication schemes/providers should be able to read it like normal. When I use the provided middleware, a cookie does NOT get set (both cookies and sessions have been enabled, confirmed via debugging):
I have also tried something like the following:
Additionally, I've tried setting up the setCookie middleware manually to no avail:
If I do a POST request directly to the Further digging shows that the setCookie middleware gets to this point:
There is no My apologies if this should be obvious, I'm quite new to Express, let alone feathers. But nowhere in the documentation do I see where Thanks in advance. EDIT: Just noticed that even with the cookie being set properly if using the standard |
@eblanshey For a speedy solution, I commented that part of the condition and it looks like everything is working as expected. I'm also not sure why it was undefined to start with. If I understood it right, on the You need to include 'cookie' on that array. I had to include "facebook" if I wanted to allow facebook authentication, for instance. And as far as I understand, cookie becomes a strategy if enabled, so you need to allow it on the list of possible "authenticate" strategies. Looking forward for a more elegant solution on the set-cookie, as well as some corrections from the more experienced people when it comes to the setup. |
@muvhaus-sl unfortunately adding "cookie" or "cookies" to the array doesn't work: I did a quick fix by adding a middleware that adds the Authorization header from the value of the cookie (using cookie-parser library):
As for actually setting the cookie, since that only needs to be done once on one route, I'll just make the login an ajax request to To the core devs: I understand feathers is mainly geared towards creating APIs, but full support and documentation for "old school" apps would great, especially since the docs guide you through how to set up view engines and what not. My use case for using feathers is to quickly create a server-side rendered app, under the hood using the services to fetch data. That way I'd have a fairly easy roadmap to changing it to an SPA down the road when I have more time (just using the service endpoints that the traditional routes use). This could be a great selling point for devs to use Feathers for their next project. As it stands now, authentication using traditional methods is very difficult to understand. I suppose adding built-in CSRF protection would be needed, which could be a matter of using https://github.com/expressjs/csurf and automatically applying it to all non-service routes. |
I believe I have got the same issue as seeing the following debug statement on my feathers server, and my cookies are not being set following a successful authentication:
My "cookie": {
"enabled": true,
"name": "feathers-jwt",
"httpOnly": false,
"secure": false
} |
I'm really short on time, today, so this is going to kind of come out as a stream of consciousness, but I'll do my best. It's pretty common to conflate enabling cookies with turning on "old-school" auth for routes. With Feathers auth we separate the two. Turning cookies on in the config just creates a cookie. It doesn't automatically enable old school, CSRF-vulnerable routes. It's important to keep the SSR server and API server as distinct entities. The SSR server can pull the JWT from the cookie, decode it to get the payload. This will include whatever entity data you've populated inside the JWT (like import decode from 'jwt-decode';
app.use(function(req, res, next) {
let jwt = req.cookies[app.get('auth').cookie.name];
let payload = decode(jwt);
// Only use service.find and service.get for GET requests
app.service('todos').get({query: {}, user: payload.userId})
.then(response => {
// Use the response data and assemble your HTML.
});
}); You probably don't want to expose that cookie value to be used by the rest of the API server. At least, I wouldn't want to deal with CSRF at all. Even a good CSRF library is only going to mitigate CSRF attacks, not eliminate them. If you keep the cookie auth data away from the API server, you've eliminated the risk of CSRF completely. If your goal is to enable SSR it's just not necessary to expose cookie auth data to the API server. The example above works more like an auth proxy to get authenticated data from the server in order to form HTML content. (You'd want to make sure CORS is disabled for SSR routes) We chose to keep the API server distanced from cookie auth because most people aren't aware of the risks or how to mitigate them. And in most cases I've seen where people want to turn cookie support on, there's an alternative method that doesn't introduce security or privacy issues. From my perspective, an API server should probably only expect a cookie for auth as an additional check on top of requiring a header. Otherwise, API servers shouldn't be able to consume auth data from a cookie. |
Running into the same issue as well upgrading a React Native app from feathers-auth 0.7.x to 1.0. The app uses the cookie from an OAuth webview flow purely to obtain and store the JWT. Subsequent calls to services use sockets and bearer token authentication. Is it possible to have the cookie set just for the /auth/{provider} request and subsequent redirect? |
I'll take a look at this today. There must be a bug somewhere as you should be able to send back a cookie with the JWT in it and parse it your React Native webview and set it back in AsyncStorage yourself. So long as you are making calls after all that is completed it should work. You should NOT be relying on the JWT inside the cookie to authenticate with your app. (ie. client sends cookie with JWT in it and server verifies it from there). In order to do that you need to enable the A simple reproducable example from someone sure would be helpful... 😁 |
For myself, a working chat app update would answer many questions. Using the standard chat app from the Feathers book, I attempted to update to auth 1.0.2 and related packages using the migration guide. ##386 Here is my services/authentication/index.js:
I get this in the body when I authenticate: |
tldr; I can get token, what do I do with it to validate the logged in user on subsequent routes/navigations? I'm authenticating users with front-facing login form My set up is a little complicated (MySQL + Feathers + VueJS SSR (really pre-rendering, but I haven't gotten that to work so I'm just using I can use the feathersClient to authenticate users, but I don't know what to do with the response. I can authenticate, but then if I manually go to a page that is behind an auth check it fails. I assume this is because cookie check fails? This is my
Here is my authentication service and hooks
From the client's perspective, am I supposed to be able to use feathersClient to authenticate and then future navigation just works? Because this is not so 😢 I add routes with a function like so (I can just pass this to a forEach over an array of routes, makes it trivially easy to add new routes)
Ideally, wouldn't the feathers server set the header for the client? I'm at a loss of what I'm supposed to do... To repro - set up normal feathers app, latest authentication - I'm using username and password as opposed to email (and only that, no OAuth for this project) - client landing page is I think I'm just missing something though... This should be easy, right? Logging users in? 😭 I found these two issues, so I think I'll have something to try tomorrow. I'm probably just doing something wrong. |
Is there any update on the topic? feathersjs-ecosystem/authentication-local#17 (comment) not sure if the issue is the same, but I assume so. Do I understand right, that the use case of the Regards, |
If you're going to use the feathers client with Socket.io to make requests, authentication has to happen on every refresh. This is a limitation of the socket auth. |
@marshallswain therefore the fact of setting the |
I also tracked that this piece of code: is never called (in my case at least), however the |
Correct. We left it out on purpose to avoid CSRF attacks. You have to manually register it. The cookie is still useful in SSR scenarios without that middleware enabled, so it's not enabled automatically when you turn on the cookie option. |
Ah that's the case. @marshallswain could you, please, confirm that I understood it right. And the option |
Oops. I meant the expose-cookie middleware. set-cookie should run with the options you posted. On a development machine, you'll need these options to get a cookie: enabled: false, // whether the cookie should be enabled
name: 'feathers-jwt', // the cookie name
httpOnly: false, // whether the cookie should not be available to client side JavaScript
secure: false // whether cookies should only be available over HTTPS That middleware should run on successful authentication. Do you have your before hooks on the authentication service setup? |
@marshallswain here I describe more about the issue: Regards, |
It looks like this issue has become a little bit of a kitchen sink of authentication cookie issues but I think the main issue of authenticating Express routes by storing the JWT in the cookie has now been addressed and there is a guide at https://docs.feathersjs.com/guides/auth/recipe.express-middleware.html |
My experience to fix this kind of issue. It may help => #541: |
First, sorry if I've got things wrong. This is my first project with feathersJS/react native...so I'have been struggling a bit, and trying to make things work.
I have been trying to get OAuth2 (Facebook) and Local authentication to work using the latest feathers-authentication(1.0.2)
I managed to get up to a point where I would see the accessToken being delivered as body of a GET request to the server, in the format as follows:
http://{my local dev server}/auth/facebook/callback?code={ a facebook generated code here...}#=
The accessToken, when decoded using JWT does include userID and the other properties. So, after I got this right, I tried to use it on the React Native App. The sample I found (https://github.com/sscaff1/hopePing) used CookieManager, for the simple reason that we cannot get the content of the response (inside the WebView) and we cannot run "fetch" on the same URL. I did not understand how to setup a "successRedirect"...so I went on to enable Cookies.
This is how my default.json looks like:
But then, the cookie would not show up on Chrome, no matter how I changed any of the above Cookie settings.
I set the Debug=feathers-authentication* and then I realized the last log I got for the Set-Cookie.js was
debug('Running setCookie middleware with options:', options);
I've put a temporary log after:
if (options.enabled && options.name) {
and it would show.
I pinpointed that the following condition was not met:
if (res.hook && res.hook.method !== 'remove' && res.data && res.data.accessToken) {
res.hook was undefined. If I remove res.hook && res.hook.method!=='remove', it works as expected, but I get 2 cookies for the same name/content.
Sorry for the long text, I hope I have explained everything properly. I wanted to know if I'm doing something wrong.
thanks in advance.
The text was updated successfully, but these errors were encountered: