I'm making a FB Canvas app.
The problem: After users authenticate, they are returned to the non-Canvas version of the app. Here's my code:
provider :facebook, CONFIG['app_id'], CONFIG['secret_key'], :scope => "publish_stream, rsvp_event"
match "/auth/facebook/callback" => "sessions#oauth_create"
match "/auth/facebook", :as => "facebook"
match "/auth/failure" => "sessions#oauth_failure"
When the user is returned from Facebook, they are sent to oauth_create (below)- however, they are sent to it via the normal (non-Canvas) app url (localhost:3000), rather than the canvas app (apps.facebook.com/my-app-namespace) so the redirect_to root_path below just sends them to the regular app.
def oauth_create
auth = request.env["omniauth.auth"]
t = auth["credentials"]["token"]
session[:facebook_token] = t
redirect_to root_path
end
I'm using omniauth-facebook gem.
How can I tell FB to send users to the canvas app after authentication?
Related
I am getting Signet::AuthorizationError in LoginController#callback and Authorization failed. Server message: { "error" : "redirect_uri_mismatch" } on the line auth_client.fetch_access_token! when I click "Allow" on the OAuth screen and execute my callback method during the OAuth process.
I have checked out this: Google OAuth 2 authorization - Error: redirect_uri_mismatch, but I still can't figure it out.
I am trying to get a login with Google set up like this:
User goes to /login and clicks on the "sign in with google" button.
The Google login prompt comes up, user signs in with Gmail, and then gets redirected to /home.
I have the following uris in my web application credentials in Google consoles:
http://localhost:3000
http://localhost:3000/login/callback
http://localhost/login/callback
http://localhost
routes.rb
get '/home' => 'home#index'
get '/login' => 'login#prompt'
get '/login/callback' => 'login#callback'
login_controller.rb
require 'google/api_client/client_secrets'
class LoginController < ApplicationController
GOOGLE_CLIENT_SECRET_FILE = Rails.root.join('config/google_oauth2_secret.json')
def prompt
if session[:credentials]
redirect_to '/home'
else
auth_client = get_auth_client
auth_client.update!(
:scope => ['profile', 'email'],
:redirect_uri => 'http://localhost:3000/login/callback'
)
#auth_uri = auth_client.authorization_uri.to_s
render layout: false
end
end
def callback
auth_client = get_auth_client
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
session[:credentials] = auth_client.to_json
redirect_to '/home'
end
private
def get_auth_client
Google::APIClient::ClientSecrets.load(GOOGLE_CLIENT_SECRET_FILE).to_authorization
end
end
I also have a concern. In my prompt method, how do I verify that session[:credentials] is the correct session code? Couldn't anyone just put some bogus string into the credentials session and gain access?
I have been following this guide: https://developers.google.com/api-client-library/ruby/auth/web-app
This happens because localhost is not a valid domain name. Instead of using localhost, you need to use lvh.me
In Google consoles the url will become
http://lvh.me:3000
http://lvh.me:3000/login/callback
Trying accessing your application in the browser using http://lvh.me:3000 instead of http://localhost:3000
lvh.me is a valid domain name with is pointing to 127.0.0.1
I realize the issue is I am setting the scope in the prompt function when I am generating the auth uri but in my callback function, I am not setting the scope.
It should be like this:
def callback
auth_client = get_auth_client
auth_client.update!(
:scope => ['profile', 'email'],
:redirect_uri => 'http://localhost:3000/login/callback'
)
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
session[:credentials] = auth_client.to_json
redirect_to '/home'
end
I'm using Rails 4.1 and already have devise configured but now would like to add sign up through Facebook and Twitter. Devise is fully set up and working for a user to sign up via email.
I've gone ahead and added the "omniauth-facebook" gem to my gemlist.
I've set up my api key and api secret
#config/initializers/devise.rb
config.omniauth :facebook, "API KEY", "API SECRET"
My Route file
#routes.rb
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks", :registrations => "registrations" }
My omniauth_callbacks_controller.rb
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
and my user model
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
if user
return user
else
registered_user = User.where(:email => auth.info.email).first
if registered_user
return registered_user
else
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20],
)
end
end
end
I also added the link to the signup page but when i click on the button I'm getting the following error
{
error: {
message: "Invalid redirect_uri: Given URL is not allowed by the Application configuration.",
type: "OAuthException",
code: 191
}
}
It looks like Facebook is objecting to the url you've told it to redirect to after someone has logged in via Facebook. Check what you've specified in your Facebook app setup in "Manage Apps" -> Your App via your Facebook developer account. Check that one of your App Domains on the Settings->Basic tab matches the domain you want to redirect to after Facebook login. Also check that you're redirecting to a URL you've specified in "Valid OAuth redirect URIs" (if any) on the Settings -> Advanced tab.
My relevant config (with real domain name changed) is as follows:
On Settings -> Basic:
App Domains: mydomain.com
A web platform with URL: http://www.mydomain.com/
On Settings -> Advanced:
Client OAuth login: YES
App Secret Proof for Server API calls: YES (optional, but I like security and I don't think it'll exacerbate your problem - conversely, if you've got it as NO, then I don't think it'll matter if you leave it like that for the purposes of this problem)
Valid OAuth redirect URLs: https://www.mydomain.com/users/auth/facebook/callback https://staging.mydomain.com/users/auth/facebook/callback http://dev.mydomain.com:3000/users/auth/facebook/callback
So you can see I allow redirects to production, staging and dev environments. Your paths might vary depending on how you've set up your routes.
Then, I add an alias for the dev domain to my /etc/hosts file:
127.0.0.1 localhost dev.mydomain.com
so when Facebook tells my browser to redirect to dev.mydomain.com, it goes to the rails app on my machine.
If you specify the redirect urls, you should double-check that you're definitely supplying one of them to Facebook when you send the user there when they click on the button (I found devise/omniauth needed a bit of bludgeoning to get the paths as I wanted).
I am trying to fetch the list of friends from Facebook. Sign in through Facebook is not a problem, but the problem is to fetch person's friends - because of access token.
puts request.env["omniauth.auth"].inspect
puts '==='
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
#fb_user = FbGraph::User.fetch(#user.uid).friends
puts #fb_user.inspect
The problem is on the #4 line - in this case I am getting error
OAuthException :: An access token is required to request this resource.
When I put there something like this:
#fb_user = FbGraph::User.fetch(request.env["omniauth.auth"].credentials.token).friends
I'll get
OAuthException :: (#803) Some of the aliases you requested do not exist: PRINTED OUT TOKEN
What's the proper way to obtain the access token?
EDIT: Current flow
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
#fb_user = FbGraph::User.fetch(request.env["omniauth.auth"].credentials.token).friends
if !#user
flash[:error] = 'This email address is already used in the system.'
redirect_to :back
elsif #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
In User model:
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token.extra.raw_info
if user = User.where(:provider => 'facebook', :uid => data.id).first
user
elsif user = User.where('email = ? AND provider IS NULL', data.email).first
return false
else
...saving data...
end
return user if user
end
You can get an access token for test purposes via the Facebook Graph API Explorer. Make sure you select the proper fields that you want access to, and click "get access token". A more permanent solution is to register your app with Facebook so that you will be able to continually make requests without the token dying.
You should look into the Facebook OAuth dialogue.
I'm assuming you're trying to use the OAuth2 strategy instead of the Javascript SDK. Make sure you have set up a callback url like so:
client.redirect_uri = "http://your.client.com/facebook/callback"
In the controller that handles your callback, you should do something like this:
client.authorization_code = params[:code]
access_token = client.access_token! :client_auth_body
FbGraph::User.me(access_token).fetch
Make sure you've let fb_graph know what your app's id and secret are. You should look into this stackoverflow to keep your apps info safe.
I'll also plug the koala gem
everybody.
I'm working with a simple Facebook authentication system on my platform (with Rails and Koala) and it's almost working as expected. But there's this one critical bug that's driving me nuts.
Given I am NOT logged into my platform and I am NOT registered and I have NOT yet authorized my app on my Facebook profile.
I go signing up with a Facebook account
Facebook asks me to log in
I successfully log in
The Facebook application requests permission
I authorize the app
I'm redirected to the correct redirect_uri
Koala fails in the client.get_access_token(params[:code]) step with a OAuthException: Code was invalid or expired. Session is invalid. This could be because the application was uninstalled after the session was created.
In short, Facebook is complaining about a code it has just provided. Here are the methods for authentication:
Login Action for OAuth
def login
reset_session
session[:facebook_client] = get_client
redirect_to session[:facebook_client].url_for_oauth_code(:callback => FacebookAPI.oauth_callback_url, :permissions => "email, user_status, publish_stream, publish_actions")
rescue => err
end
Callback action
def terminate
client = session[:facebook_client]
if client.nil?
redirect_to '/', notice: 'Error on FacebookAPI'
else
access_token = client.get_access_token(params[:code]) if params[:code] # IT FAILS HERE
# omitting the rest
end
So I'm using Omniauth to authenticate with the likes of Twitter and Foursquare. Twitter works fine, but Foursquare doesn't appear to return a secret.
Anyone know what's going wrong?
Here's the create action in the controller, Foursquare is passing the user back to this, but as I said, it's not getting the secret, just the token
def create
omniauth = request.env["omniauth.auth"]
unless current_user.authentications.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
current_user.apply_omniauth(omniauth)
current_user.save
end
flash[:notice] = "Authentication Successfull"
redirect_to authentications_url
end
Here is the apply omniauth method:
def apply_omniauth(omniauth)
authentications.build(
:provider => omniauth['provider'],
:uid => omniauth['uid'],
:token => omniauth['credentials']['token'],
:secret => omniauth['credentials']['secret']
)
end
Foursquare should not pass back a secret, just the token. The foursquare api key and and secret are provided to you by foursquare when you register your app on their developers site. You must use these values in your omniauth.rb
Twitter uses Oauth 1.0 and foursquare uses 2.0
That could be your issue there