5
votes

I am using Devise auth token gem and ng-token auth for authenticating my single page app. Besides registering with email there is the option to sign-up via Facebook. It works.

My problem is that as for my Fb request scope I set to get the user_friends, email and public_info, however when I get the request I don't see the auth_hash request.env['omniauth.auth']. This is described in the omniauth-facebook gem documentation.

Basically I want to save what FB gives back about the user in my database. How would you do it?

2
github.com/plataformatec/devise/wiki/OmniAuth:-Overview Here you can find some info. I don't know how this would work with angular, but basically you have to implement a callback action in which you'll have the facebook response hash, and from there you can use as needed. - lcguida
Thanks @Icguida. On that wiki page I noticed that one is supposed to get request.env["omniauth.auth"] in the controller action. The specific controller in the Devise auth token gem is DeviseTokenAuth::OmniauthCallbacksController . And the action is omniauth_success. But request.env["omniauth.auth"] returns as nil. - Gustavo Guimaraes

2 Answers

1
votes

I use this end-point with Ionic2 app, for Facebook Login requests on Rails 5 API, using Koala and Devise Token Auth so you should be able to replicate on any Rails 5 app:

def facebook
  @graph = Koala::Facebook::API.new(oauth_params[:token], ENV["FACEBOOK_SECRET"])
  @profile = @graph.get_object("me?fields=email,first_name,last_name,picture.type(large)")

  unless @user = User.where(email: @profile["email"])&.first
    @user = User.new(email: @profile["email"])
  end
  #
  # Here you will make your logic for saving Facebook's data on your User model,
  # customize accordingly
  #
  if @user.new_record?
    p = SecureRandom.urlsafe_base64(nil, false)
    @user.password = p
    @user.password_confirmation = p
    #
    # "Passwordless" login, user must set password after registering,
    # or be forever haunted by indecipherable SecureRandom value
    #
    @user.name = @profile["first_name"]+ " " + @profile["last_name"]
    @user.remote_avatar_url = @profile["picture"]["data"]["url"]
    @user.confirmed_at = Time.now
    @user.uid = @profile["id"]
    @user.provider = 'Facebook'
  end

  @client_id = SecureRandom.urlsafe_base64(nil, false)
  @token     = SecureRandom.urlsafe_base64(nil, false)
  @user.tokens[@client_id] = {
    token: BCrypt::Password.create(@token),
    expiry: (Time.now + DeviseTokenAuth.token_lifespan).to_i
  } 
  auth_header = @user.build_auth_header(@token, @client_id)
  # update the response header
  response.headers.merge!(auth_header)
  @user.save!
  if sign_in(:user, @user, store: false, bypass: false)
    render json:  {
      data: @user.token_validation_response 
    }
  end
end

Point a POST route to this and pass authResponse.accessToken from Facebook request as params[:token]. VoilĂ , authentication magic!

0
votes

I don't have how to do this with Angular and Rails, but this is how I did it in my Rails app.

def show 
 #controller action
 @FbInfoforFrontEnd = FbModel.from_omniauth(request.env["omniauth.auth"])
end

and in the FbModel model, I'd implement the mechanism to save the token and rest of the info like this

def self.from_omniauth(auth)
 #FbModel model method
 oauth = Koala::Facebook::OAuth.new(AppId, AppSecret)
 new_access_info = oauth.exchange_access_token_info auth.credentials.token
 new_access_token = new_access_info["access_token"]
 new_access_expires_at = DateTime.now + new_access_info["expires"].to_i.seconds
 return FbModel.where(provider: auth.provider,
                      uid: auth.uid)
               .first_or_create(provider: auth.provider,
                         uid: auth.uid,
                         name: auth.info.name)
               .update_attributes(oauth_expires_at: new_access_expires_at,
                                  oauth_token: new_access_token)
end

I hope this answers your query