I have started building a small app and using Omniauth and the omniauth-twitter gems.
Everyhting is going fine until twitters hits the callback url and i get sent to the failure response with the error auth/failure?message=session_expired&strategy=twitter.
Here is my code so far:
class Admin < Sinatra::Base
register Sinatra::Namespace
enable :sessions
use OmniAuth::Builder do
provider :twitter, 'Cient_ID', 'Client_secret'
end
namespace '/admin' do
get do
erb :index
end
get '/login/?' do
redirect '/auth/twitter'
end
end
get '/auth/twitter/callback' do
"You are now logged in"
end
end
When i go to /admin/login I get redirect to twitter asking me to authorize the app and when I click "Allow" it redirects me back but I just get sent to the same failure screen over and over.
I have figured this out in my case. I was using Pow as my web server and in my project folder had a folder called 'tmp'. You can tell POW to restart the server on every request by adding in a file called 'always_restart'. The fact that the server restarted on every request meant the the session token became invalid. By removing this file I got it to work.
Related
Ok - after 48 hours I give up. I have my Rails 3.2 app setup with Doorkeeper and Devise. The doorkeeper.rb initializer is pretty straight forward:
resource_owner_authenticator do
current_account || warden.authenticate!(:scope => :account)
end
and I am using the awesome p2_oauth POD in an iOS Swift app for OAuth2 connecting. Here's the problem/oddity:
When I go to login and the OAuth2 dance begins, p2 uses iOS's embedded web view to hit my Rails API. Since there is no current_account, it redirects appropriately to login. Great.
HOWEVER - I CANNOT LOG OUT.
I've tried everything:
warden.logout
signout
session.delete("warden.user.account.key")
clearing cookies in the Rails App when the logout route is called
clearing the sessions in the Rails App when the logout route is called
etc
Regardless of what I do, when I go to login again the Rails app is RETAINING the current_account!? I inspected the session and, sure enough, there is a warden.user.account.key still in the session! It's infuriating.
If I stop and restart the iOS app in the simulator, all is well again until I login/logout. So clearly it's like there is some session that iOS is maintaining and not clearing that the Rails app is reading. Im also making sure that my request has a no cache policy:
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPMethod = "DELETE"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
config.URLCache = nil
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler:
I honestly cant believe that no one else has come across this. How am I suppose to log out with this setup?
just wanted to follow up on your comment.
Just to recap what problem I had that brought me to your question:
User can log in fine but couldn't properly log out. Once they clicked log in again, it would automatically log in without asking for password again.
As you said, using the password grant flow would indeed avoid the cookie session. For me, I had to use a webview of some sorts in my iOS app. So I had to stick with the authorization_code grant.
I spent an entire week trying to figure out what was going on with doorkeeper+devise (all my links are purple...), and I finally found a solution that works for me. I'm not sure it's the proper way to do it though because I'm not familiar with ruby on rails at all. I'll have to go through the code again later.
Basically, what to do is add this to config/routes.rb where you say user_doorkeeper
use_doorkeeper do
controllers applications: 'doorkeeper', authorizations: 'authorizations'
end
Then add an authorizations controller here app/controllers/authorizations_controller.rb
class AuthorizationsController < Doorkeeper::AuthorizationsController
def new
super
env['warden'].logout
end
end
This forces the user to logout on log in. For the code, I think what it's doing is overriding/adding code to the original AuthorizationsController in Doorkeeper.
I found this solution on what looks like someone's blog, thank you good sir! This will do for now.
http://www.kluks.de/blog/posts/14-rails-4-single-sign-out-of-all-applications-with-doorkeeper.
------------ Edit ------------
For reference, for the provider side, I had been following this guide, while adding stuff I needed. I wouldn't recommend following her clientside tutorial though. That didn't work out for me at all.
doorkeeper.rb
Doorkeeper.configure do
use_refresh_token
force_ssl_in_redirect_uri false
#for authorization_code grant
resource_owner_authenticator do
current_user || begin
session[:user_return_to] = request.fullpath
redirect_to new_user_session_url
end
end
end
We had a similar issue, same setup on the backend, but we were able to resolve by clearing the cookies on the iOS app.
[[NSHTTPCookieStorage sharedHTTPCookieStorage] removeCookiesSinceDate:[NSDate dateWithTimeIntervalSince1970:0]];
Gabriel's answer worked only partially for me. The problem with it was, that the user is signed out directly after calling AuthorizationsController#new, so the subsequent AuthorizationsController#create request, which is required when the user authorizes the app for the first time, does not work.
In order to get the Authorization flow to work correctly, I needed to only sign out the user after the create action, or after the authorize#new if there is no need to authorize the app.
class AuthorizationsController < Doorkeeper::AuthorizationsController
def create
redirect_or_render authorize_response
# Sign out the user user clicked "Authorize" in the Authorize application page
warden.logout
end
private
def render_success
if skip_authorization? || matching_token?
redirect_or_render authorize_response
# sign out directly if there is no need for authorizing the app
warden.logout
elsif Doorkeeper.configuration.api_only
render json: pre_auth
else
render :new
end
end
end
Be aware that this case was used with a Mobile App as client and will not work if the intention is to have SSO for multiple apps.
I use doorkeeper 5.1 and devise 4.7, so it may look a little different for other versions.
I'm running ngrok, pow, and using devise for authentication on my Rails 4.2.1 application. When I run it locally by going to http://myapp.dev, pow works fine all across the board. I can sign in, view pages, etc.
When I set up an ngrok proxy, I get the first login page correctly (by hitting http://123.ngrok.io), and can see that it's hitting my local app. However, after I sign in, I get redirected from http://123.ngrok.io to http://myapp.dev and prompted to sign in again. My 'after_sign_in_path` is set to return a path in my app, and it works when I do it locally.
Any ideas where that interaction is failing?
You can set your host name so the redirect doesn't happen in default_url_options
class ApplicationController < ActionController::Base
...
def default_url_options
{ host: 'hostname.com' }
end
...
end
I am using this code to Facebook from my Rails app using Koala:
def login #login on Facebook
session['oauth'] = Koala::Facebook::OAuth.new(SITE_URL+'/callback')
# redirect to facebook to get your code
redirect_to session['oauth'].url_for_oauth_code(:permissions=>PERMISSIONS)
end
When login is executed, I get the following error message:
Load denied by X-Frame-Options: https://www.facebook.com/dialog/oauth?
client_id=MYAPPID&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback
&scope=public_profile does not permit framing.
Seems to be trying to show the canvas for login, but my app is just a website that needs Facebook authentication. Is there anything that I have to change in my Facebook App settings or in the code?
Add the following into your config/application.rb
config.action_dispatch.default_headers = {
'X-Frame-Options' => 'ALLOW-FROM https://www.facebook.com'
}
PS: don't forget to restart your server after you add this.
Trying to write a facebook app and am attempting authentication. This is a rails 3.1 application
The First redirect where I give facebook my api and it returns a code seems to run well. But when I try to take that code and 'exchange it' from a access_token I run into problems.
The access token appears where the iframe aws.
Here is my code.
def index
#Load facebook.yml info
config = YAML::load(File.open("#{Rails.root}/config/facebook.yml"));
# setup client
redirect_to "https://graph.facebook.com/oauth/authorize?client_id=#{config['development']['app_id']}&redirect_uri=#{CALLBACK_URI}"
end
def callback
logger.debug("c")
config = YAML::load(File.open("#{Rails.root}/config/facebook.yml"));
if (!params.key?('access_token'))
logger.debug("A")
redirect_to "https://graph.facebook.com/oauth/access_token?client_id=# {config['development']['app_id']}&redirect_uri=#{CALLBACK_URI}&client_secret=#{config['development']['client_secret']}&code=#{params['code']}"
return
end
logger.debug("B")
access_token = params['access_token']
#me = FbGraph::User.me(ACCESS_TOKEN)
#name=#me.name
end
end
You are not supposed to redirect the user’s browser to the second endpoint (think for a moment, you are putting your app secret into that URL, so it would be easy for everyone to spot it there) – you are supposed to make a server-side call to that endpoint.
The docs clearly say so, https://developers.facebook.com/docs/authentication/server-side/:
“Once the user has authorized your app, you should make a server side request to exchange the code returned above for a user access token.”
I'm trying to use Omniauth to allow users to login to my Rails app using Facebook. Locally, omniauth automatically redirects the browser to Facebook for authentication using the following link:
<%= link_to "Sign in with Facebook", "/auth/facebook" %>
It redirects back as is expected (no callback error) and I am then able to log out.
The issue occurs when I try to upload my application to my server. For some reason Omniauth isn't kicking in and it doesn't do the redirect. Instead it just points the browser to a non-existant directory in my app (http://sharedchecklist.com/auth/facebook) and spits out this error:
Routing Error
No route matches "/auth/facebook"
I've done a lot of searching over the past few hours to try and figure out what the issue could be. I've made sure to changee the the site and canvas URLs to my app's address. It isn't an issue with callback.
It's almost like omniauth isn't there…
Has anyone encountered this issue before? I'm fairly new to rails but I've been able to figure through any issues before which makes this one all the most frustrating.
If the url would help, here it is: http://sharedchecklist.com/
Thanks for any assistance you can offer.
You need to tell Facebook where to redirect to. If it works in development you probably have your site url set to "http://localhost:3000". Change it to "http://sharedchecklist.com" and it will work. Of course it then will break in development. Therefore I created a new "Test" Facebook application just for my testing which always redirects to localhost.
This seems to happen if config/initializers/omniauth.rb is missing.
I have that file on the ignore list and a sample file as omniauth.rb.sample. I forgot to create the omniauth.rb file and I was getting the same error.
If you want to test on local host and keep your production environment working:
1- Create a new Facebook app only for development purposes
2- Set the Site URL field to: http://localhost:3000/
3- Then edit your /config/initializers/omniauth.rb file to match the following:
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env.development?
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
provider :facebook, 'DEV_APP_ID', 'DEV_APP_SEVRET'
else
provider :facebook, 'DEPLOY_APP_ID', 'DEPLOY_APP_SECRET'
end
end
Finally relaunch rails server and you should be able to login through your new app.