http://www.developer.com/lang/rubyrails/implement-user-authentication-in-ruby-with-sinatra.html

Back to article

Implement User Authentication in Ruby with Sinatra


October 26, 2011

Content and profile customization is a central part of any website's success, yet implementing even basic authentication- and profile-related features can be incredibly tedious and time consuming. In recent years the various development communities have responded by implementing pluggable authentication extensions which in many cases provide all of the necessary functionality right out of the box. The Ruby community has been particularly strong in this regards, producing numerous fantastic solutions capable of not only managing users within a local database but also interacting with popular third-party user repositories such as Facebook and GitHub.

In the latest installment of this occasional series introducing the popular Ruby-based framework Sinatra, I'll show you how to easily add user authentication capabilities to your Sinatra application (be sure to also check out previous articles which show you how to create a Sinatra-based REST API and interact with a MySQL database by way of the DataMapper ORM). To accomplish this goal, we'll use the aptly-named sinatra-authentication Sinatra extension.

Installing and Configuring sinatra-authentication

The sinatra-authentication Sinatra extension is installable as a Ruby gem, meaning you can install it using the following command:

$ gem install sinatra-authentication

We'll store the user profiles in a MySQL database, and interact with them using the DataMapper ORM. (If you're not familiar with DataMapper, be sure to check out my recent article on the topic.) Additionally, we'll use convenient flash messaging to notify the user of various events such as a successful login, so be sure to install rack-flash if you haven't already done so.

Integrating User Authentication Features

Integrating user authentication features into your Sinatra application is incredibly easy.

require 'rubygems'
require 'sinatra'
require 'haml'
require "dm-core"
require "dm-migrations"
require "digest/sha1"
require 'rack-flash'
require "sinatra-authentication"
DataMapper.setup(:default, "mysql://webuser:secret@localhost/stampclub")
DataMapper.auto_upgrade!
use Rack::Session::Cookie, :secret => 'superdupersecret'
use Rack::Flash

Save this file as app.rb. For the purposes of this example I'm using a database named stampclub. In order to follow along with the examples you'll need to create a database and pass along the credentials to the DataMapper.setup method as demonstrated above.

Next, create a file named layout.haml, saving it to a directory named views and adding the following content to it:

!!!
%html
  %head
    %title Stamp Club     
  %body
    = yield

With app.rb and views/layout.haml in place, open a terminal window and execute the following command from within your application directory to start the Sinatra server:

$ ruby -rubygems app.rb
== Sinatra/1.2.6 has taken the stage on 4567 for development with
backup from Mongrel

Thanks to DataMapper's convenient schema migration capabilities, merely starting the application for the first time will result in a table named dm_users being created within the database you specified in app.rb:

mysql> describe dm_users;
+------------------+------------------+------+-----+---------+----------------+
| Field            | Type             | Null | Key | Default | Extra          |
+------------------+------------------+------+-----+---------+----------------+
| id               | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| email            | varchar(40)      | YES  | UNI | NULL    |                |
| hashed_password  | varchar(50)      | YES  |     | NULL    |                |
| salt             | varchar(50)      | YES  |     | NULL    |                |
| created_at       | datetime         | YES  |     | NULL    |                |
| permission_level | int(11)          | YES  |     | 1       |                |
+------------------+------------------+------+-----+---------+----------------+

In addition to creating the dm_users table, sinatra-authentication creates a number of routes which implement the various user registration, login, logout, profile viewing, and profile editing features. If you're familiar with REST, then these routes should make perfect sense. If you haven't yet been acquainted with REST, check out my recent article on the topic, which shows you how to implement a REST-based API using Sinatra. In any case, sinatra-authentication generates the following routes out of the box:

GET '/login'
GET '/logout'
GET '/signup'
GET/POST '/users'
GET '/users/:id'
GET/POST '/users/:id/edit'
GET '/users/:id/delete'

Creating an Account

Be sure to test out the routes by navigating to /signup and creating a new account. You'll see sinatra-authentication's default registration view (presented in Figure 1).

Default Sinatra Authentication Registration Form
Figure 1. The Default Registration Form

After creating an account, be sure to check out the dm_users table, where you'll see that a new row has been created such as the following:

mysql> select * from dm_users\G
*************************** 1. row ***************************
              id: 1
           email: wj@wjgilmore.com
 hashed_password: c709816a0d6ebc500206d5d4a3495e9743cfd030
            salt: 1gf8Md1Q7l
      created_at: 2011-10-18 16:22:03
permission_level: 1
1 row in set (0.00 sec)

Adding a Flash Message

If you started the Sinatra application from scratch, then you received an error message after pressing the registration button, despite having confirmed that the new user information was added to the dm_user table. This is because sinatra-authentication will redirect the user to the application's home page, which doesn't yet exist. Open app.rb and add the following route:

get '/' do
  haml :home
end

Next, create a file named home.haml, placing it in the views directory and adding the following contents:

%h1 Welcome to the Stamp Club website
= flash[:notice]

Once added, try logging out of your new account (navigate to /logout). After being successfully logged out of your account, sinatra-authentication will redirect to you the home page where you'll be greeted with a flash message stating Logout successful.

Accessing User Data

Chances are you'll want to know whether a user is logged in so as to provide custom content. sinatra-authentication makes several global variables available which you can use for this purpose. For instance, add the following snippet to your layout.haml file will produce a tailored message based upon whether the user is currently logged in:

- if logged_in?
  = "Welcome back, " + current_user.email
- else
  <a href="/login">Login</a> | <a href="/register">Register</a>

Where to From Here?

The sinatra-authentication extension packs a pretty powerful punch while requiring minimal effort on the part of the developer. In fact, for rudimentary purposes you could conceivably use the extension without even needing to tweak its default behavior. However, chances are you'll want to modify the default views, as well as extend the default users table. For more information about such possibilities, check out the sinatra-authentication home page.

About the Author

Jason Gilmore is founder of the publishing, training, and consulting firm WJGilmore.com. He is the author of several popular books, including "Easy PHP Websites with the Zend Framework", "Easy PayPal with PHP", and "Beginning PHP and MySQL, Fourth Edition". Follow him on Twitter at @wjgilmore.

Sitemap | Contact Us