Last Updated: February 25, 2016
·
9.107K
· erikwco

Sinatra Authentication with Warden

For those projects that not need a huge power behind them using Rails, is a wonderful idea use Sinatra because is light and cool.

I'm new, working with Rails / Ruby / Sinatra ( ~ 1 year ago ) and I don't really know if exists something that help me to start a new project with some stuffs or abilities included and not to start from scratch, anyways, I decide to create some repos to use as project start, I will explain you now what this contain and if you found it useful then feel free to use.

Warden Configuration Steps

I will assume that you already know how to install and use Sinatra and also have knowledge about Ruby.

Add Warden gem referente to your GemFile

gem "warden", "1.2.1" 

Require warden in your app file

require "warden"

Warden uses Rack::Flash and Rack:Session we must to register

use Rack::Session::Cookie, secret: "IdoNotHaveAnySecret"
use Rack::Flash, accessorize: [:error, :success]

Add Warden Configuration in your app file

use Warden::Manager do |config|
      # serialize user to session ->
      config.serialize_into_session{|user| user.id}
      # serialize user from session <-
      config.serialize_from_session{|id| User.get(id) }
      # configuring strategies
      config.scope_defaults :default, 
                    strategies: [:password], 
                    action: 'auth/unauthenticated'
      config.failure_app = self
end

Add Warden Strategies for :password

 Warden::Strategies.add(:password) do
  def flash
    env['x-rack.flash']
  end

  # valid params for authentication
  def valid?
    params['user'] && params['user']['username'] && params['user']['password']
  end

  # authenticating user
  def authenticate!
    # find for user
    user = User.first(username: params['user']['username'])
    if user.nil?
      fail!("Invalid username, doesn't exists!")
      flash.error = ""
    elsif user.authenticate(params['user']['password'])
      flash.success = "Logged in"
      success!(user)
    else
      fail!("There are errors, please try again")
    end
  end
end

Route Configuration Steps

Route configuration are the easy part but important.

Warden "must" routes

# when user reach a protected route watched by Warden calls
post '/auth/unauthenticated' do
  session[:return_to] = env['warden.options'][:attempted_path]
  puts env['warden.options'][:attempted_path]
  flash[:error] = env['warden'].message  || 'You must to login to continue'
  redirect '/auth/login'
end

# to ensure user logout a session data removal
get '/auth/logout' do
  env['warden'].raw_session.inspect
  env['warden'].logout
  flash[:success] = "Successfully logged out"
  redirect '/'
end

Application routes

To protect a resource is only need to call the Warden method authenticate!

get '/protected' do
  env['warden'].authenticate!
  slim :protected
end

Now every time the user hit /protected route without authentication Warden will send him to the login form.

Startup Project

If you want all of these step preconfigured to use as a start point in your new project feel free to fork the repo and use it

This repo use all this components

  1. Sinatra Link for Repo
  2. Warden Link for Repo
  3. Thin Link for Repo
  4. Foundation 5 Link for Repo
  5. Slim Link for Repo
  6. Rack-Flash Link for Repo
  7. Sqlite3 Link for Repo

Source in GitHub

Any comments, suggestion or correction is welcome