Rails 4: Single-Sign-Out of all applications with Doorkeeper


This is a quick solution to add single-sign-out of all applications for a doorkeeper based oauth2 application.

For my latest project I created a separate login-app (server app running under a subdomain login.example.com) and client app (running under another subdomain client.example.com) using it for authentication. The goal is to use one login service for several apps, keeping user registration and related stuff in one single place.

I’ve chosen the doorkeeper gem for the server app and devise using oauth2 for the client app. How to set things up can be read from the example apps doorkeeper-gem provides.

The login process runs very smooth, but as soon as it comes to logout, it’s not nice anymore. Imagine the following behaviour:

  • A user requests client.example.com and clicks on a link labeled “Login” which calls https://client.example.com/users/auth/mystrategy
  • The browser redirects him to https://login.example.com/users/sign_in where he can enter his credentials and finally
  • gets redirected to https://client.example.com again
  • After doing nasty stuff on the page he clicks on the link labeled “Logout”, which basically calls DELETE https://client.example.com/sign_out.

What this does is simply removing the Cookie from the subdomain client app, logging out the user, so that someone else might login, right? Well, partially yes, but… no – let’s see what happens:

  • The second user clicks on the link labeled “Login” and gets redirected to https://login.example.com/users/sign_in
  • …and immediately redirected back to the client app, logged in as the first user. WTF?

Of course, because only the client app killed the session cookie. The login app, when redirected to, finds the login session cookie, finds a valid auth_token and signs in the user.

But I want to sign in as another user!

Unfortunately there’s no easy way (I could find) to sign out the user from the login app as well, because

  • you can’t simply call DELETE https://login.example.cm/users/sign_out because you don’t have the authenticity_token
  • you could try adding a special controller to login app, authorize yourself with the token stored in the client app and…

but there’s a simpler solution to this which is basically not logging out the user when he wants to, but always immediately after he signed in.

The first solution found in the net was to set resource_owner_from_credentials inside doorkeepers initializer, logging out the user at the end. However, this didn’t work for me for whatever reasons – the block was never called.

So I simply added a doorkeeper authorizations controller to the app doing the logout.

×
config/routes.rb
use_doorkeeper do
  controllers applications: 'doorkeeper', authorizations: 'authorizations'
end

The applications controller in here is part of my implementation of the app itself (so not needed for this tweak), but the new stuff is the authorizations controller.

×
app/controllers/authorizations_controller.rb
class AuthorizationsController < Doorkeeper::AuthorizationsController
  def new
    super
    env['warden'].logout
  end
end

Et voilà – small but effective. Now you can log in, get redirected to the client app with a valid token and logging out of the client app will bring up the login page again.


Ein Kommentar

  • Joshua_Lippiner  – 
    Hi - thank you for this. Im amazed that no one else has posted about this. Only problem is that after implementing this solution when the user LOGS IN as part of the OAuth handshake it is immediately logging them out before the callback, which then asks them to log in again. How do you handle this?