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.
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
- The browser redirects him to
https://login.example.com/users/sign_inwhere he can enter his credentials and finally
- gets redirected to
- After doing nasty stuff on the page he clicks on the link labeled “Logout”,
which basically calls
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
- …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_outbecause 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.
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.
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.