Using multiple authentication strategies #11
Comments
Could you give more details about what you are trying to achieve? Thanks |
I want the user to have the options of logging in with an email/password or a social account (Facebook). I store the social account info differently than the email/password. Didn't look like there was a way to differentiate the type of credentials using knock. |
By more details I meant are you using knock inside a rails API interacting with a single page javascript application? Something else? If you could try to describe more precisely what you already have and what you are missing I could give you better answers. This is how you can customize how you retrieve the user when signing in: inside ## Current user retrieval from handle when signing in
## --------------------------------------------------
##
## This is where you can configure how to retrieve the current user when
## signing in.
##
## Knock uses the `handle_attr` variable to retrieve the handle from the
## AuthTokenController parameters. It also uses the same variable to enforce
## permitted values in the controller.
##
## You must raise ActiveRecord::RecordNotFound if the resource cannot be retrieved.
##
## Default:
# self.current_user_from_handle = -> (handle) { User.find_by! Knock.handle_attr => handle } Note that this will be deprecated in future versions of Knock in favour of a method in the user model. But the general idea will stay the same. Is this helping you? If not, don't hesitate to provide code samples or anything that could help me understand better what your exact use case is. I never implemented OAuth with knock myself, but it would be interesting to see if there is a way to provide something in future versions that would make it easier. |
I will be using Knock for an SPA and 2 mobile apps. The problem is that I'm storing the social ids and the email and password differently. So the fact that the I'm not actually storing the OAuth token as I don't really need to interact with their API other than to log them in. Now, I understand that I may not be approaching this correctly which is why I'm having issues thinking through this. I appreciate the help! |
Social authentication is out of the scope of knock for the moment. Although it is definitely something I'd like to implement in the future. For the moment, what you can do is implement your own controller that retrieves (or creates) a user from social authentication and responds with a JWT token. Here's how you can generate a JWT token using Knock: # Create the token
knock_token = Knock::AuthToken.new payload: { sub: user.id }
# Access the JWT token
knock_token.token The "flow" would probably be something similar to this: (source: http://madhatted.com/2014/6/17/authentication-for-single-page-apps) Hope this helps! And please let us know how you ended up implementing this :) |
Honestly, I see this as a flexibility issue and not something specific to social auth. If you were to make params available when finding and authenticating a user you'd provide a lot more flexibility. I'm excited to see where this gem goes. I would love to see a solid JWT implementation for Rails. Thanks again for putting time into my problem. I'll give your suggestion a shot. I really appreciate the help! |
The v2 is already providing more flexibility as you can access the params to retrieve a user if you need to. Have a look at the changelog if you're interested! This has not been released yet and it is still subject to change. |
Awesome! I'll give v2 a look. Would you say it's beta? Alpha? |
Alpha, it's stable but the design could change.
|
Hey, I created a sample application for facebook login + jwt. I'm not sure if its the best approach but it works: https://github.com/muZk/rails5-api-jwt-facebook-auth It was designed for getting the FB accessToken "client" side (which could be a JS application or Mobile app). @nsarno any thoughts? The key files are: facebook_user_token_controller.rb class FacebookUserTokenController < ActionController::API
before_action :authenticate
def create
render json: auth_token, status: :created
end
private
def authenticate
unless entity.present?
raise Knock.not_found_exception_class
end
end
def auth_token
if entity.respond_to? :to_token_payload
Knock::AuthToken.new payload: entity.to_token_payload
else
Knock::AuthToken.new payload: { sub: entity.id }
end
end
def entity
@entity ||=
if FacebookService.valid_token?(auth_params[:access_token])
data = FacebookService.fetch_data(auth_params[:access_token])
User.find_or_create_by uid: data['id'] do |user|
user.first_name = data['first_name']
user.last_name = data['last_name']
user.email = data['email']
end
end
end
def auth_params
params.require(:auth).permit :access_token
end
end And facebook_service.rb which has the logic for facebook token validation and data retrieval: class FacebookService
def self.valid_token?(access_token)
status = false
begin
# We need to check if the access_token is valid for our FB APP. Source: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken
debug_token = Koala::Facebook::API.new(access_token).debug_token(app_access_token_info['access_token'])
status = true if debug_token['data']['is_valid']
ensure
return status
end
end
def self.fetch_data(access_token)
Koala::Facebook::API.new(access_token).get_object('me', fields: 'name,first_name,last_name,email') if valid_token?(access_token)
end
def self.app_access_token_info
@app_access_token ||= Koala::Facebook::OAuth.new.get_app_access_token_info
end
end |
@muZk it seems that you have mixed things up here in this line: debug_token = Koala::Facebook::API.new(access_token).debug_token(app_access_token_info['access_token']) You should be using debug_token = Koala::Facebook::API.new(app_access_token_info['access_token']).debug_token(access_token) |
- debug_token was failing due to incorrect access token and hidden by ensure block - nsarno/knock#11, last comment is correct, fetch debug token using app_access_token to allow root access to FB API
How would you provide authentication using email/password and facebook login?
The text was updated successfully, but these errors were encountered: