Many apps that you will write in your programming career may allow for multiple sessions and while your use case may vary it's fine for most cases especially when it's an application with a mix of components (web/mobile/desktop). From a user experience you'd obviously not want to invalidate user sessions as that would be annoying.
But let's just say for arguments sake you have an application that has a more strict security requirement and you want to ensure that a single user cannot be logged in and using your system from multiple computers/devices. There are a few Rubygems out there that do this, however I found that by leveraging a few simple techniques this can be done in a few lines of code and it works well.
This simple tutorial assumes that you are using Devise for authentication, however this technique could be applied to other plugins or your own authentication. Our goal here is to evaluate the
current_user's (handy method Devise gives us to get the current user in the request cycle) session token and kick them out if there's a difference in tokens.
Since this is an application-wide technique, the most likely place to put this code is in
app/controllers/application_controller.rb. Let's go ahead and write a method called
duplicate_session? to eval the session token:
def duplicate_session? user_signed_in? && (current_user.login_token != session[:token]) end
Let's break this down:
user_signed_in?is a method Devise gives us to eval if the user is currently signed into the application.
current_user.login_tokenis the token assigned when you login that is stored in your
User(this name may vary by your choice) model.
- The next part we eval using the Ruby operator
!=or (not equal to) to look for equality between the
Now we've got a simple setup which will let us write our next method,
check_concurrent_session. This will also live in the
app/controllers/application_controller.rb file. Let's go ahead and write it:
def check_concurrent_session if duplicate_session? sign_out_and_redirect(current_user) flash[:notice] = "Duplicate Login Detected" end end
Again, let's break this down.
We are using a simple conditional
if to evaluate our previous method
duplicate_session?. If this condition is met, then we use the devise method of
sign_out_and_redirect passing the
current_user object to tear down the session, then finally displaying a flash notice with
Duplicate Login Detected. Obviously, you can make this message whatever you want it to be, but this is what I chose.
We're almost done... hang in there. One more simple thing to do.
We're going to need a way to execute the
check_concurrent_session method in each request cycle. So we'll use a callback, in this case a
before_action which will execute our code before any request is allowed to process. This is as simple as putting the following line at the top of your
And literally, that's all there is to it. Go ahead and try logging in with your browser of choice (i.e. Chrome). Ok, logged in? Now open an incognito window and try to login to your app again. Ok logged in? Now go back to your original browser window and refresh the page. You're now signed out with a nice, (hopefully friendly) notice message.
Voila... we are done!
Dead simple and it works every time!