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

Wrong ObjectId passed to service methods on nested routes #106

Closed
thosakwe opened this issue Jul 25, 2016 · 8 comments
Closed

Wrong ObjectId passed to service methods on nested routes #106

thosakwe opened this issue Jul 25, 2016 · 8 comments

Comments

@thosakwe
Copy link

thosakwe commented Jul 25, 2016

I have a REST/WebSockets backend that I set up with feathers-cli. It uses feathers-mongoose as a data store.

It has three main tables -users, products and subscriptions. Subscriptions belong to products, and users own both products and subscriptions.

Supplementing the products service I have a nested service to query subscriptions based on their productId.

app.use("/products/:id/subscriptions", {
  find: (params) => app.service("subscriptions").find({
    query: {
      productId: params.id
    }
  }),
  create: (data, params) => app.service("subscriptions").create(Object.assign(data, {
    productId: params.id
  }))
});

The data that I am posting to the server looks like this:

{"name":"Lifetime","duration":"0","price":"10","desc":"A lifetime subscription to FooBar.","productId":"57924101232cfaed5ff125c2"}

However, the server responds with the following 404 error: No record found for id '57964d07ecaf8e915bee9108'. This is puzzling. No product, user or subscription in the database has the ObjectId 57964d07ecaf8e915bee9108. So I am wondering why the ID magically transforms on the server-side.

@daffl
Copy link
Member

daffl commented Jul 26, 2016

Can you create a breaking example? The strange object id you're getting makes me think it has something to do with the setup of related services. Also, in this case it shouldn't matter but id is reserved for get routes in services (it sets up a servicename/:id route). I'd go with /products/:productId/subscriptions.

@thosakwe
Copy link
Author

@daffl Apologies for the late response. Not really sure what a good example would be here, but here's the situation as of now. I did change from :product_id to :productId, but that unfortunately did not resolve the issue.

Anyways, on the front-end, I am using Dart and Polymer. I have a class with the following code:

void loadSubscriptions(appId) {
  var subs = _feathers.service("products/$appId/subscriptions");
  subs.index().then((subscriptions) {
    _appDetail.set("subscriptions", subscriptions);
  });
}

The _feathers object you see is an instance of a Feathers client library I whipped up by forking the Angel client. (If you'd like, I can open-source this?). My FeathersService classes have this method, index, that is the same as find. Looks like this:

// TL;DR - Send authed request and return 'data'
@override
Future<List> index([Map params]) {
  var completer = new Completer();
  // buildRequest basically just adds the JWT to an XHR
  // 'basePath' in this case is '/api/v1/products/<id>/subscriptions
  var request = buildRequest("$basePath", method: "GET", write: false);
  request.onLoad.listen((_) {
    completer.complete(request.response["data"]);
  });
  request.send();
  return completer.future;
}

Anyways, when I look in Chrome's 'Network' tab, I see a that the request is sent correctly, correct JWT in the Authorization header, etc.

The response is just very confusing to me. The URL I first found the error on was /api/v1/products/57924101232cfaed5ff125c2/subscriptions. However, the error was about id '579adf3acf609b905a8b37fd', and I have no real idea where that comes from.

Here is relevant output from server.js:

OPTIONS /api/v1/products/57924101232cfaed5ff125c2/subscriptions 204 1.161 ms - -
info: (404) Route: /products/57924101232cfaed5ff125c2/subscriptions - No record found for id '579adf3acf609b905a8b37fd'
GET /api/v1/products/57924101232cfaed5ff125c2/subscriptions 404 20.463 ms - 128

I am running Mac OS X El Capitan 10.11.

Hopefully this is detailed enough, if you need any more, I will provide. Thanks in advance. I really dig Feathers a lot.

@daffl
Copy link
Member

daffl commented Jul 29, 2016

Are you using authentication on this service? The error message could also come from sending a token that is valid but has the id of a user that doesn't exist.

@thosakwe
Copy link
Author

Yes, indeed, I am using authentication of this service. I'm wondering, is there any way to see the JWT attached to the request after it is decoded? Is there such thing as a params.token?

However, I'm not really sure why the JWT would have the ID of a user who doesn't exist. The JWT is from an XHR to /ap/v1/auth/local, so I'm still confused.

@daffl
Copy link
Member

daffl commented Jul 30, 2016

Yes, the token should be in params.token after the authentication hooks. One way the id could be invalid is when you re-initialize the database and then re-use an old token (instead of getting a new one).

@thosakwe
Copy link
Author

Ah, that makes sense. I store the token and user data in localStorage, like the official client.
When I initialize my client I POST the stored token to /auth/token to see if it is still valid. Perhaps that is the wrong practice.

Regardless, I will check out params.token when I get home and see.

@thosakwe
Copy link
Author

Update - I added a simple hook to the service:

productSubscriptions.before({
  all: [
    hook => {
      console.log("Dumping token: ", hook.params.token);
    },
    auth.verifyToken(),
    auth.populateUser(),
    auth.restrictToAuthenticated(),
    auth.associateCurrentUser()
  ]
});

And now the error I receive changed, and you were right, the JWT is expired.

error: (401) Route: /products/57924101232cfaed5ff125c2/subscriptions - jwt expired
info: NotAuthenticated: jwt expired
at NotAuthenticated.ExtendableBuiltin (/Users/tobe/Source/Node.js/shield-min/api/v1/node_modules/feathers-errors/lib/index.js:21:28)
at NotAuthenticated.FeathersError (/Users/tobe/Source/Node.js/shield-min/api/v1/node_modules/feathers-errors/lib/index.js:99:87)
at new NotAuthenticated (/Users/tobe/Source/Node.js/shield-min/api/v1/node_modules/feathers-errors/lib/index.js:152:85)
at /Users/tobe/Source/Node.js/shield-min/api/v1/node_modules/feathers-authentication/lib/hooks/verify-token.js:47:25
at /Users/tobe/Source/Node.js/shield-min/api/v1/node_modules/jsonwebtoken/index.js:155:18
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)

I took a look back at my code, and although I thought I had a POST to /auth/token, it's not there. I'm going to put it in my client constructor and see how it goes. Hopefully that is the fix.

@daffl
Copy link
Member

daffl commented Aug 4, 2016

Looks like we figured it out 😄

@daffl daffl closed this as completed Aug 4, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants