pejmanjohn
pejmanjohn

Reputation: 1057

Oauth2 flow to request a token using Facebook uid for credentials

I am building an iPhone client with a Rails backend. The client communicates with the server through an Oauth2 API. I've set this up using the oauth2 and doorkeeper gems.

Every API request must be sent with a token. I currently support two token "types":

This is all working fine but I'm hitting an issue now that I'm allowing a user to also log into the app using Facebook.

Upon the user logging into FB, my client responds by passing the Facebook UID to my server (using a Client token). I then do some checks on my server to match this UID to an existing user in my database.

Here's the issue: I want to respond to this request with a User Token. This token is needed as the user will now be logged into the app, and any subsequent requests will need this token. However, currently I feel like the only way for me to do this is:

Respond with the username and password. Then have the client make a request for a User Token following the Password Credentials flow. I don't like this because I'm passing a password, and it requires multiple trips.

I feel like I may be missing something basic. Is there another way I should be handling this flow?

Upvotes: 3

Views: 801

Answers (2)

Timo
Timo

Reputation: 166

The resource owner password credentials type defined by OAuth 2.0 doesn't really fit to external logins, e.g., Facebook, since the authentication is done through the external site and not from the username and password on your own authorization server.

One solution is to switch to the implicit grant type of OAuth 2.0 (https://www.rfc-editor.org/rfc/rfc6749#section-4.2). This type is supported by Doorkeeper too.

From your app you have to open a web view and redirect the user to the authorization endpoint of Doorkeeper (default: /oauth/authorize) with the parameters: client_id=..., redirect_uri=... and response_type=token. Additionally you have to tell Doorkeeper to redirect the user to FB login.

Therefore add this to doorkeeper.rb:

resource_owner_authenticator do   
  user_from_session || begin
    session[:return_to] = request.fullpath

    fb_login_url = "..." # add here your facebook login url 
    redirect_to(fb_login_url)
  end
end

After the user logged in via FB and you authenticated the user on your server, you have to redirect the user back to session[:return_to] what points to /oauth/authorize and that redirects to the initially given redirect_uri including the access_token in the url.

Upvotes: 0

pejmanjohn
pejmanjohn

Reputation: 1057

I think I have a solution but it's definitely a hack.

Basically I'm hijacking the Password Credentials flow to also handle this Facebook scenario.

The client makes the call like so (formatting may be off as I tested in ruby):

curl -i http://www.example.com/oauth/token   -F grant_type=password   -F client_id=(client id)-F client_secret=(client secret) -F username=(email address) -F password=(password) -F provider="facebook" -F uid=(fb uid) -F token=(fb token)

On my server I check for the "provider" parameter. If found, instead of password authentication it uses the facebook uid to find a match in the user table. I also pass the FB token as a security measure (I verify that this token belongs to the uid before looking for a match). If a match is found, the user is set as the resource owner of the token, meaning I end up with a User Token.

This is the code block from my doorkeeper.rb:

resource_owner_from_credentials do |routes|
 if params[:provider]
    // FB uid authentication path code here
 else
   // password authentication
   user = User.find_by_email(params[:username])
   user if user && user.authenticate(params[:password])
 end
end

Upvotes: 1

Related Questions