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
Related
I'm working on authentication with LinkedIn. I don't know why but LinkedIn don't allow to sign in with suddenly. I can allow LinkedIn app but I can't get authentication information.
{"provider"=>"linkedin",
"uid"=>nil,
"info"=>
{"name"=>nil,
"email"=>nil,
"nickname"=>nil,
"first_name"=>nil,
"last_name"=>nil,
"location"=>nil,
"description"=>nil,
"image"=>nil,
"phone"=>nil,
"headline"=>nil,
"industry"=>nil,
"urls"=>{"public_profile"=>nil}},
"credentials"=>{"token"=>"facdxxx-xxx-xxxx-xxxx-xxxxxxxxx", "secret"=>"2xxxxx-xxxx-xxxx-xxxx-xxxxxxx"}}
omniauth_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def linkedin
#user = User.from_omniauth(request.env["omniauth.auth"].except("extra"))
if #user.persisted?
sign_in_and_redirect #user, event: :authentication
else
session["devise.user_attributes"] = #user.attributes
redirect_to new_user_registration_url
end
end
end
Should I update LinkedIn application settings? I wonder it doesn't matter to the rails application...
Gemfile
gem 'omniauth-linkedin'
I use omniauth-linkedin.
When I register in February, I have permission like below.
But currently, Just three.
How can I add permissions on LinkedIn?
There's so many things that this could actually be, but here's one thing you can try; you may not have requested the correct access when you configured your application. Per the docs:
When requesting an authorization code in Step 2 of the OAuth 2.0 Guide, make sure to request the r_liteprofile and/or r_emailaddress scopes!
Per the documentation you can set these via the request, or thru the developer portal
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).
Short version
Is there a way to have facebook POST back to your return url from their oauth dialog after logging in?
With background story
I am developing a Rails application in which a user can buy products. In order to buy a product, he has to request it by creating a Request. That Request stores the product's id, the product owner's id as well as the requester's id, just to associate the three with each other.
All this happens through a form that is sent, of course, through a post request.
Here comes the tricky part: The user has to be logged in to place a request. They can log in through facebook. In my application controller, I currently have the following method to check if a user is logged in:
def user_signed_in?
unless current_user # from other method
flash[:error] = "Please log in first."
redirect_to root_path and return false
end
true
end
helper_method :user_signed_in?
I want to change root_path to the facebook auth dialog url. At the moment, I have the following:
def user_signed_in?
unless current_user
raise "https://www.facebook.com/dialog/oauth/?client_id=#{ENV['FACEBOOK_APP_ID']}&redirect_uri=#{request.url}&scope=#{User::BASIC_PERMISSIONS}"
redirect_to "https://www.facebook.com/dialog/oauth/?client_id=#{ENV['FACEBOOK_APP_ID']}&redirect_uri=#{request.url}&scope=#{User::BASIC_PERMISSIONS}" and return false
end
true
end
So far, all this works fine - after logging in, facebook redirects me to the right url. However, the redirect would have to happen through a post request, because otherwise the Request record won't be created. Does facebook support that? Ideally, in a way that my post parameters don't get lost along the way? I have checked facebook's documentation on the matter and searched the web, but couldn't find anything.
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?
I'm building a multi-tenant app where accounts are scoped under subdomains. Assuming acme.com is my app and Elmer is my user, when Elmer registers at acme.com he is transferred to elmer.acme.com. I want to sign Elmer in after he registers, but I'm having a hard time. I'm using cookies. Here's my sign in method:
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
current_user = user
end
Here's part of my Users#create method where users get signed in.
if #user.save
sign_in(#user)
redirect_to root_url(subdomain: #user.subdomain)
end
The cookie is getting set when Elmer is still at acme.com. When Elmer is redirected to elmer.acme.com the cookie is not valid.
I can set domain: :all in my session_store, but this breaks a requirement. It would mean Elmer will be signed into elmer.acme.com, buggs.acme.com, and essentially *.acme.com. Elmer's session cookie should only be valid for elmer.acme.com and/or acme.com.
Any idea how to achieve this? I'm running Rails 3.2 with Ruby 1.9.3.
If you were to create/allow a token login for your user, then you could:
Have a token on the user model
Login with that token (either redirect to a specific URL, or add to your authentication system to login when :token is present)
Sample redirect code:
if #user.save
sign_in(#user)
redirect_to root_url(user_id: #user.id, subdomain: #user.subdomain, token: #user.token)
end