Knock: Can't rely on `current_user_from_token` in authenticate method

Created on 20 Aug 2015  路  11Comments  路  Source: nsarno/knock

If you change default config.current_user_from_token from

User.find(claims['sub'])

to some code not raising an exception like

User.where(id: claims['sub'])

or something more useful

User.find_or_create_by(auth_id: claims['sub'])

Then the following method used to check authenticity won't work anymore https://github.com/nsarno/knock/blob/master/lib/knock/authenticable.rb#L5-L9

Most helpful comment

@SpencerCDixon not sure if you've already found the answer to your question but if not, you can specify a scope when authenticating your user on Auth0. The fields you specify in your scope (i.e. email, nickname, etc) will be contained in your token. Here's Auth0's official documentation. Hope this helps!

All 11 comments

In the current implementation, you need to raise an exception. I will update the documentation to reflect this.

You can use find_or_create_by! in your example to make it work.

Do you see any reason not to do this?

Thanks for the explanation. I find this pretty fragile since the developer could forget to raise an exception and it will not trigger the forbidden http request :-/

I think it would be safe to check user presence in your side and raise a custom exception. In general, it's not a bad idea to catch framework exceptions and to re-raise your own ones directly after.

BTW find_or_create_by! would not work here since it would just make sure the new instance about to be created is `valid?. It would defeat the purpose to raise an exception if a record is not found since if that's the case, well, you want to create one :)

Thanks for the feedback.

I definitely agree this could improve in future versions.

I'm not sure I understand why you would want to use a find_or_create_by here. Could you give me a more detailed use case?

I only use auth0 social authentication strategies. There is no registration steps. The user only logins using one of his social account. So the first time I need to create a user entity in my database. I am not sure it the place to do that but after talking with someone on the auth0 chan this is what he told me to do.

@gottfrois Did you have a final solution for this? I'm trying to implement Auth0 + Knock as well.

Did you end up going with:
User.find_or_create_by(auth_id: claims['sub'])

I've noticed that coming back from Auth0, my claims has actually has auth0| prepended to the user_id
Example:
{"iss"=>"https://domain.auth0.com/", "sub"=>"auth0|1", "aud"=>"...", "exp"=> 9999, "iat"=> 999}

How are you mapping the claim['sub'] of auth0|1 to a user? Are you parsing left of the bar (|) or have a new column called something like auth0_key?

This is what I have:

config.current_user_from_token = -> (claims) { User.find_or_create_by(auth_id: claims['sub']) }

Are you parsing left of the bar (|) or have a new column called something like auth0_key?

Yeah, simply storing the claims['sub'] value into an attribute called auth_id in my case.

@gottfrois Thank you!!

So what about getting the meta data about users saved in your Users table? I ideally want to save the user email, name, etc. Would one approach be to make another request to Auth0 API with the user ID to get that meta data before doing the find_or_create_by?

@SpencerCDixon not sure if you've already found the answer to your question but if not, you can specify a scope when authenticating your user on Auth0. The fields you specify in your scope (i.e. email, nickname, etc) will be contained in your token. Here's Auth0's official documentation. Hope this helps!

Awesome thanks @brandonmanson I will prob refactor my approach when I find the time to just do that. 馃憤 appreciate it

Was this page helpful?
0 / 5 - 0 ratings