Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"No auth token" using authenticate strategy: 'jwt' (v.1.0.0-beta-2) #366

Closed
foxhound87 opened this Issue Dec 12, 2016 · 25 comments

Comments

Projects
None yet
5 participants
@foxhound87
Copy link

foxhound87 commented Dec 12, 2016

Should strategy: 'jwt' work on v.1.0.0-beta-2 ?

NOT working:

app.authenticate({ strategy: 'jwt', token })

working (as on older version):

app.authenticate({ type: 'token', token })

working:

app.authenticate({ strategy: 'local', email, password })

Module versions

    "feathers": "^2.0.2",
    "feathers-authentication": "^1.0.0-beta-2",
    "feathers-authentication-client": "^0.1.3",
    "feathers-authentication-jwt": "^0.2.0",
    "feathers-authentication-local": "^0.3.0",
    "feathers-configuration": "0.4.1",
    "feathers-errors": "2.5.0",
    "feathers-hooks": "^1.7.0",
    "feathers-hooks-common": "^2.0.2",
    "feathers-mongoose": "3.6.1",
    "feathers-permissions": "^0.1.1",
    "feathers-rest": "1.5.2",
    "feathers-socketio": "1.4.2",

NodeJS version:
v7.2.0

Operating System:
MacOS Sierra

Browser Version:
Chrome 54.0.2840.98 (64-bit)

Module Loader:
webpack 2.1.0-beta.27

@bertho-zero

This comment has been minimized.

Copy link
Contributor

bertho-zero commented Dec 12, 2016

I have the same issue

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 12, 2016

It seems related to the auth.authenticate(['jwt', 'local']) hook.

When I use it in any hook, I always get Unhandled rejection NotAuthenticated: No auth token.

For example on the authentication service hooks I have:

  app.service('authentication').hooks({
    before: {
      create: [
        auth.hooks.authenticate(['jwt', 'local']),
        customJWTPayload(),
      ],
    },
  });

then (with session enabled in configs) no error using app().authenticate() (without arguments) from the client side using sockets.

But if I try to call the REST endpoint POST /authentication with username/password params I get Missing credentials:

  feathers-authentication:passport:authenticate Authentication strategy 'local' failed +1ms { message: 'Missing credentials' } 400
  feathers-errors NotAuthenticated(401): No auth token +0ms
  feathers:rest Error in REST handler: `No auth token` +8ms
  feathers-authentication:middleware:failure-redirect Clearing old 'feathers-jwt' cookie +2ms
  express:router <anonymous>  : /authentication?email=email@test.com&password=12345 +10ms
  express:router <anonymous>  : /authentication?email=email@test.com&password=12345 +0ms
error:   (401) Route: /authentication?email=email@test.com&password=12345 - No auth token
info:    NotAuthenticated: No auth token
    at NotAuthenticated.ExtendableBuiltin (node_modules/feathers-errors/lib/index.js:21:28)
    at NotAuthenticated.FeathersError (node_modules/feathers-errors/lib/index.js:96:116)
    at new NotAuthenticated (node_modules/feathers-errors/lib/index.js:149:117)
    at node_modules/feathers-authentication/lib/hooks/authenticate.js:80:31
    at process._tickCallback (internal/process/next_tick.js:103:7)

and if I remove auth.hooks.authenticate(['jwt', 'local']) from the authentication hooks, the POST /authentication works, the token and the cookie are created.

@foxhound87 foxhound87 closed this Dec 12, 2016

@foxhound87 foxhound87 reopened this Dec 12, 2016

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 12, 2016

And what's the real purpose of the auth.hooks.authenticate() hook?
It is used to enable the auth for certain strategy or it require the auth for specified strategies? It's unclear.

Should it be removed from the before.create of the authentication service?
I found it in the migration guide

Then if we suppose its purpose is for block some service I do:

  • I remove it from the authentication service (so I can able to generate the token/session)
  • set it into others service to restrict the access.

then if I generate the token/session from the rest and I use the token to call these restricted service, the access is grant. But the same configuration, from the client side (logged with cookie using app().authenticate() - without arguments), the service are blocked, I get Unhandled rejection NotAuthenticated: No auth token. It seems it want a token authentication in this case.

@ekryski

This comment has been minimized.

Copy link
Member

ekryski commented Dec 12, 2016

@foxhound87 it should be accessToken not token that you pass from the client.

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 12, 2016

Other issues:

  • The payload contains the user ID only if I call the the services from the client side using the socket. Even the customizeJWTPayload will not work if I call the authorization from the rest.

  • The verifyJWT should be in the app.passport object. But in the client side is missing.

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 12, 2016

@ekryski thank you for your answer.

I tried both:

.authenticate({ type: 'accessToken', token })
.authenticate({ strategy: 'accessToken', token })

not working.

But now I'm not using the token anymore, I'm using .authenticate() without params for sessions.

Still errors: NotAuthenticated: No auth token.

@ekryski

This comment has been minimized.

Copy link
Member

ekryski commented Dec 12, 2016

@foxhound87 the reason you are getting unhandled rejection is because the auth client is trying to authenticate automatically on initialization. @marshallswain added this for SSR but I need to tidy it up a bit so that it doesn't just throw an error. It has nothing to do with the server side.

@ekryski

This comment has been minimized.

Copy link
Member

ekryski commented Dec 12, 2016

Your client should be .authenticate({ strategy: 'jwt', accessToken: token }).

Server side should be:

  app.service('authentication').hooks({
    before: {
      create: [
        auth.hooks.authenticate(['jwt', 'local'])
      ],
    },
  });
@bertho-zero

This comment has been minimized.

Copy link
Contributor

bertho-zero commented Dec 14, 2016

I have no auth token when I log in with rest instance of feathers and I use socket instance later.

bertho-zero added a commit to bertho-zero/feathers-authentication-client that referenced this issue Dec 14, 2016

@marshallswain

This comment has been minimized.

Copy link
Member

marshallswain commented Dec 14, 2016

@bertho-zero, the feathers client only works with one provider at a time, so you'd have to have two app instances to switch providers. It could still work, but each app would have to authenticate individually.

@bertho-zero

This comment has been minimized.

Copy link
Contributor

bertho-zero commented Dec 14, 2016

Ah ok, I was absolutely looking to share the token between the 2 instances.
Why not try to take it to the localStorage if it is there?

@ekryski

This comment has been minimized.

Copy link
Member

ekryski commented Dec 14, 2016

@bertho-zero it will do that but the problem is that since you are authenticating with effectively 2 different apps the tokens will be different. You'd likely want to give one a different localstorage key name. Otherwise they would overwrite each other every time you successfully authenticate.

@foxhound87 did you get your stuff working? We just pushed a bunch of updates and bug fixes so if you are still having issues you might want to try moving to the official 1.0.x and the latest version of all plugins.

@marshallswain

This comment has been minimized.

Copy link
Member

marshallswain commented Dec 14, 2016

With feathers-rest , setting up the client to look for the token in localStorage will work without having to call feathersClient.authenticate(). Since socket connections are flagged as authenticated on the server side, you'll have to for sure call feathersClient.authenticate() with the instance that uses feathers-socketio.

@bertho-zero

This comment has been minimized.

Copy link
Contributor

bertho-zero commented Dec 14, 2016

@ekryski I authenticate with a single instance, there is no problem with the token itself, but I would like to share the token between the two instances. For that it would be enough that the client's hook would look in the localStorage no?

@marshallswain If I use the socket everything works, it's just for practical questions that I preferred to see the query, it's less practical with socket.

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 15, 2016

@bertho-zero are you talking about the logs? I'm getting no logs on server terminal when calling a service from the feathers-client with socket, the logs are shown only from the rest api (I'm using postman). I mean when not using DEBUG.

@ekryski I updated all feathers dependencies:

    "feathers": "^2.0.3",
    "feathers-authentication": "^1.0.2",
    "feathers-authentication-client": "^0.1.6",
    "feathers-authentication-jwt": "^0.3.0",
    "feathers-authentication-local": "^0.3.2",
    "feathers-configuration": "^0.4.1",
    "feathers-errors": "^2.5.0",
    "feathers-hooks": "^1.7.0",
    "feathers-hooks-common": "^2.0.2",
    "feathers-mongoose": "^3.6.1",
    "feathers-permissions": "^0.1.1",
    "feathers-rest": "^1.5.2",
    "feathers-socketio": "^1.4.2",

Using the cookie on the feathers configs and authenticate() without params: first of all, the cookie is never set in the browser, from the server side I cannot access the cookie in the request, and the authenticate() without params is always failing on the server side.

Anyway, I don't think that is the way to go, I think that the API Server should be completely stateless, accessible with the JWT token strategy or the local (username/password) strategy.
The SSR Server (which will call the same feathers-client apis both on client and server), instead, should be stateful, should handle the JWT token in the cookie, and proxy all request to the API Server using the JWT strategy and the feathers-client authenticate({ strategy: 'jwt', accessToken: token }) both on client side and server side. I Think every request to the API Server should be authenticated before calling a service (both on client side and server side).

As feathers is not able to set a cookie properly (even with the latest versions), I disabled it on the feathers config and implemented myself on the SSR Server (some workaround was needed but I'm now able to authenticate with that process).

Now assume we have a restricted service using the auth.authenticate(['jwt', 'local']), hook.
It seems that after the logout is done on the browser, and I reload the page, on the server side I don't get anymore the cookie with the jwt, the authentication is not done - and it's ok - but the service request is served (data is retrieved, the auth hook is bypassed, no auth error thrown!!!).

How feathers keeps the subsequent requests authenticated if the feathers cookie is not present in the request?

To avoid this behavior, I have to force logout with app.logout() on the server side on every request if a cookie/token is not present.

Other Issues:

  • I'm not able to use local stragety from the REST
    It's like the jwt and local strategies on the same endpoint are overlapping, for example, if I switch the order of the authenticate hook array to ['local', 'jwt'] says Missing credentials (even if the username/password params are provided).
    Otherwise - using ['jwt', 'local'] - calling POST /authentication with username/password params will throw always: No auth token.
    Maybe the required headers or params are changed with the latest updates? Would be nice to have a complete documentation to clarify all params for the requests, right now I'm getting all the info around the github issues because the current state of the doc is not sufficiently comprehensive (maybe for me as Italian is more difficult, but sometimes is a matter of lack of info).

  • I setup a customJWTPayload in the before.create hook of the authentication service (as shown in the migration guide). From the feathers-client calls all services gets the additional ID data (which was set by customJWTPayload with hook.params.user.id) even if the customJWTPayload is not present on others services hooks. I think this is not so good behavior to mix data from the hooks of authentication service into other services. In fact, if I call a service from the REST I don't get the extra data because the authentication service and customJWTPayload are never executed on a single REST call (Which I initially thought was the wrong behavior). Even in this case, like the force logout() issue, seems like feathers keeps it's own internal state when using the feathers-client. (this is tested using the jwt strategy - not tested with feathers cookies config as I still cant make it working).

I hope this can help you to understand better the needs of the users or improve the feathers experience, as we don't know how feathers works under the hood and if some behaviors are correct and works as expected.

Thank You.

@marshallswain

This comment has been minimized.

Copy link
Member

marshallswain commented Dec 15, 2016

@foxhound87 we fixed some cookie-related bugs, yesterday. The latest versions of all packages should hopefully set cookies properly.

As for the first bullet point, where the order of the strategies matters, that's a PassportJS issue. It's a little annoying because all of the strategies actually do run, but when they all fail, only the error for the first one in the list is returned.

@marshallswain

This comment has been minimized.

Copy link
Member

marshallswain commented Dec 15, 2016

If you have all of the latest packages, please post an example repo. I had one ready for debugging OAuth login and it made it much easier to get a fixed release out.

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 15, 2016

@marshallswain

https://bitbucket.org/foxhound87/rfx-stack-ssr-test/src/master

https://bitbucket.org/foxhound87/rfx-stack-ssr-test/src/ssr-cookie

The master branch is with the feathers cookie config (not working so well).

The ssr-cookie branch is my attempt with my own implementation of the cookie on the SSR server (which is working pretty well)

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 15, 2016

Another issue is that app.logout() is never resolved,
and this was causing unexpected behaviors on the server side.

@marshallswain

This comment has been minimized.

Copy link
Member

marshallswain commented Dec 15, 2016

@foxhound87 is that the case in the example you posted above? We merged a fix for that which should have been published yesterday.

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 15, 2016

@marshallswain yes, I'm using proper git comments to help you to fix these issues,
I shared this repo with @daffl on slack too some days ago.

https://bitbucket.org/foxhound87/rfx-stack-ssr-test/branch/ssr-cookie

I see that there was a related merge 2 days ago, but maybe is not completely fixed,
I get Warning: .then() only accepts functions but was passed: [object Undefined]

@foxhound87

This comment has been minimized.

Copy link
Author

foxhound87 commented Dec 15, 2016

And from the feathers-client authenticate() I'm getting Warning: a promise was created in a handler but was not returned from it. I see these warnings using bluebird, I suggest to use it to highlight some strangeness, I think it can ensure a more stable implementation of promises.

@ekryski

This comment has been minimized.

Copy link
Member

ekryski commented Dec 30, 2016

^ @foxhound87 regarding that warning from Bluebird. Some promises are intentionally created that way but I also have a fix coming for the error around automatic authentication throwing an unhandled promise rejection error.

As for the first bullet point, where the order of the strategies matters, that's a PassportJS issue. It's a little annoying because all of the strategies actually do run, but when they all fail, only the error for the first one in the list is returned.

This is now partially resolved. If you specify the strategy on the client the server will only attempt to use that one. It won't run through them all now and will return the proper error.

Another issue is that app.logout() is never resolved

This has been fixed in #369.


@ekryski I authenticate with a single instance, there is no problem with the token itself, but I would like to share the token between the two instances. For that it would be enough that the client's hook would look in the localStorage no?

@bertho-zero it should do that yes. If that is still an issue maybe create a separate issue with a simple example that demonstrates that problem and we'll see if we can fix it up! 😄


Honestly, I'm getting a bit lost in this thread as to what the actual issues are anymore. I'm going to close this issue. @foxhound87 please open new ones for each individual issue you are having with a simple reproducible example and feel free to copy-paste the relevant info from this thread for each one. Your RFX stack stuff is awesome but it's a lot to sift through to figure out what could be the issue and it will be much faster to solve any problems if we can quickly reproduce the issue. 😄

@derencel20

This comment has been minimized.

Copy link

derencel20 commented Aug 26, 2017

Hello, is it normal to use client.authenticate() every time I use a service? I have to add client.authenticate() everytime I use a service.

@derencel20

This comment has been minimized.

Copy link

derencel20 commented Aug 26, 2017

Oh nevermind, I found the answer the answer already. It's on #68

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.