Posts tagged "authentication"

Last week I spoke at Silicon Valley Ruby Group about PlataformaTec’s open source tools, mainly Devise, Simple Form and Responders.

When talking about Devise, I’ve mentioned that, before creating Devise, we were alternating between using Authlogic or Clearance in our projects. However, we soon realized that we needed a solution that was as customizable as Authlogic (allowing us to choose behaviors and several configuration options) and as complete as Clearance (whole MVC stack). It is fun to remember this happened more than 2 years ago.

After the presentation, someone came to talk to me about Sorcery and said it would be nice if Devise provided the same kind of tooling, allowing someone to build their own controllers and views around Devise instead of using Devise built-in controllers and views. His proposal surprised me, because this approach is totally possible with Devise and it was one of our design goals since day one.

That said, we realized that we were probably not “advertising” the bare-bone, stripped-down aspect of Devise well enough. That’s why I am writing this blog post. Devise already makes it easy for you to customize your own views, using the generator rails g devise:views which copies the views to your application. But what if you want to roll out your own views AND controllers?

To show you how we can achieve that, let’s write some code! The first step is to create a Rails application:

rails new devise-only-model

Next, we will add Devise to the Gemfile:

gem "devise", "~> 1.4.6"

And run the installation generator:

bundle install && rails g devise:install

The installation generator is going to give you some extra instructions, so don’t forget to do that as well. Next, let’s generate our basic User model, but we will pass an extra parameter called --skip-routes:

rails g devise User --skip-routes

By passing this extra parameter, Devise is going to generate everything as usual, with a small difference on config/routes.rb:

devise_for :users, :skip => :all

This parameter tells Devise to not generate any route at all. You can check that by executing bundle exec rake routes. However, you may be wondering: why can’t we simply remove the devise_for call? If we remove the route, Devise wouldn’t actually know that you have added Devise configuration to the User model, as all models are lazy loaded. So we need the route to tell Devise it needs to setup the appropriate helpers for the user, like authenticate_user!.

With Devise configured, we are ready to create the controllers and views on our own. In this blog post, we are going to create the SessionsController as an example allowing us to sign in and sign out. First, let’s add our routes:

root :to => "sessions#new"
post "/users/sign_in"    => "sessions#create"
delete "/users/sign_out" => "sessions#destroy"

Our SessionsController at app/controllers/sessions_controller looks like:

class SessionsController < ApplicationController
  # For security purposes, Devise just authenticates an user
  # from the params hash if we explicitly allow it to. That's
  # why we need to call the before filter below.
  before_filter :allow_params_authentication!, :only => :create
 
  def new
    @user = User.new(params[:user])
  end
 
  def create
    # Since the authentication happens in the rack layer,
    # we need to tell Devise to call the action "sessions#new"
    # in case something goes bad. Feel free to change it.
    user = authenticate_user!(:recall => "sessions#new")
    flash[:notice] = "You are now signed in!"
    sign_in user
    redirect_to root_path
  end
 
  def destroy
    sign_out
    flash[:notice] = "You are now signed out!"
    redirect_to root_path
  end
end

The controller implementation is quite straightforward. With the controller in hands, we just need to generate the view for the new action at app/views/sessions/new.html.erb:

<% if user_signed_in? %>
  You are signed in as <%= current_user.email %>. <%= link_to "Sign out", users_sign_out_path, :method => :delete %>.
<% else %>
  <%= form_for @user, :url => users_sign_in_path do |f| %>
  <div><%= f.label :email %><br />
  <%= f.email_field :email %></div>
  <div><%= f.label :password %><br />
  <%= f.password_field :password %></div>
  <div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
  <div><%= f.submit "Sign in" %></div>
  <% end %>
<% end %>

The view shows a message if the user is signed in, otherwise it shows a sign in form. Now we are almost ready to check if it works. First, we need to run the migrations:

bundle exec rake db:migrate

Remove the index page:

rm public/index.html

And create a user in the database so we can sign in. We can do that in rails console:

User.create!(:email => "jose@example.com", :password => "123456")

Now, start the server and you are ready to sign in and sign out. You can also block user access in any controller by calling authenticate_user! in a before filter. Just remember that, if you add the filter to your application controller, remember to skip the filter on the sessions controller, otherwise you won’t be able to sign in in the first place.

You can now freely proceed to implement the other controllers and views in your application. Keep in mind that if you have devise :recoverable in your model, all the related methods like User.send_reset_password_instructions will already be available in your model, so you can use them straight away to implement your own reset password feature. Since Devise use all those methods internally, if you have any questions about implementing your own reset password feature, you can always take a look at Devise own controllers for some help.

I hope this post can help you to roll out your own controllers if this is the kind of feature you expect from Devise. Also, if you are worried about the overhead of using Devise even if you are not using its controllers, there is no need to worry at all. Devise does the smart thing and only loads the controllers you are actually using. Also, it lazily loads all behaviors, so if you are not using recoverable, no code related to recoverable will be loaded at all.

It is important to keep in mind that Devise was built by us to be flexible and capable of handling different requirements from different clients, so it is PlataformaTec’s priority to have it as flexible as possible! So, what would you like to see in “bare-bone, stripped-down Devise” in order to better use it in your applications?

A couple weeks ago we finally released Devise 1.1 which is fully-compatible with Rails 3! Not only that, we’ve been working with Rails 3 since the first betas and several features were added along the way! Let’s take a look at those, some architectural changes and see how Devise 1.1 and Rails 3 will change how you handle authentication.

Pretty URLs with Metal

A common complaint in Devise 1.0 (for Rails 2.3) was, in order to know which message to show to the user when sign in failed, we had to pass a parameter in the URL as in /users/sign_in?unauthenticated=true while one would expect us to simply use flash messages. This happened because the redirection was done not from inside a controller, but a Rack application set up in Warden (a Rack authentication framework Devise relies on) and we could not access flash messages from it.

However, since Rails 3 moved several responsibilities to the Rack layer, including flash messages, we can easily access flash messages from any Rack application, allowing us to remove the parameter from the URL! Even more, Rails 3 provides small, fast, bare bone controllers through ActionController::Metal, which we used in Devise to clean and speed up the code considerably.

Locking goodness

The lockable module in Devise also went through a major overhaul. Previously, it already supported :unlock_strategy as option, allowing you to specify if the user could be automatically unlocked after a time period, through an e-mail token or both. Now, it also supports :none as option, meaning that all unlocking should be done manually.

Even more, there is a new option called :lock_strategy, that allows you to specify whether the lock happens only manually or after an amount of invalid sign in attempts.

HTTP Authentication on by default

In Devise 2.3, you may remember that we had a module called :http_authenticable along with :database_authenticatable and :token_authenticatable. While all three worked great, it was confusing that all HTTP authentication features were built on top of the database authentication and it was not possible to do HTTP authentication using a token unless we created a forth module called :http_token_authenticatable. We quickly noticed this could be improved by providing a better design and better abstract Devise authentication strategies.

And that is what happened in Devise 1.1. Now both database and token authentication work through HTTP with no extra work and the http authenticatable module was deprecated. Besides, if you are creating a new strategy on your own, you get both authentication through parameters (form) and HTTP with no extra work!

Routing customizations

We built Devise to be a full stack solution with customization in mind. In Devise 1.1, the customization abilities from Devise were taken to the next level. Now the devise_for method in routes accepts to extra options: :skip and :controllers. The first one allows you to skip the routes generation for a given controller/module in case you want to define them on your own, while the second allows you to change the router to point to a given controller in your application, like Users::ConfirmationsController instead of Devise’s internal controller.

Talking about Devise’s internal controller, Devise 1.1 namespaced all controllers classes, so now we have Devise::ConfirmationsController instead of ConfirmationsController.

Another limitation removed from Devise in this new version is related to URLs customizations. In prior versions, Devise used the URL to retrieve which scope is being accessed. That said, if you were accessing “/users/sign_in”, Devise had to inspect this URL and find the “/users” bit to specify the current scope is “users”. The same happened to “/admin/sign_in”.

This had a huge impact in URL customization, because if you wanted to have an URL like “/some_prefix/users/sign_in”, you had to tell Devise you were appending a prefix. Things could get even uglier if you wanted to prepend dynamic prefixes like “/:locale”.

In Devise 1.1, we use the new contraints API and Rack capabilities from the new router to specify which scope to use. So, instead of inspecting the URL, Devise retrieves the user from the request’s env hash as request.env["devise.mapping"].

For all the routes generated by devise_for, Devise automatically sets this value in the env hash. However, if you are creating your own routes, you need to set it manually using the constraints API:

constraints lambda { |r| r.env["devise.mapping"] = Devise.mappings[:user] } do
  # Add a custom sign in route for user sign in
  get "/sign_in", :to => "devise/sessions"
end

Of course, since this is rather a common pattern, we encapsulated it in a nice API:

devise_scope :user do
  # Add a custom sign in route for user sign in
  get "/sign_in", :to => "devise/sessions"
end

You can simply give a block to devise_for as well and get the same result:

devise_for :users do
  # Add a custom sign in route for user sign in
  get "/sign_in", :to => "devise/sessions"
end

All the routes specified in the block have higher priority than the ones generated by devise_for.

Awesomeness pack

The last feature we want to discuss is also a routing customization, but we decided to leave it up for last because it shows all the potential coming with Rails 3 and Devise 1.1.

In Devise 1.1, we added the ability to require authentication for a given url in the router, besides the existing before filters in controllers. This allow us to easily require authentication for third party rack application without a need to hack into them. Kisko Labs posted an interesting case where you can use Devise to require authentication to a Resque application in very few lines of code:

authenticate :admin do
  mount Resque::Server.new, :at => "/resque"
end

Devise simply uses the constraints API discussed above, allowing the request to continue only if the user is already authenticated. Otherwise, it redirects the admin to the sign page managed by Devise inside your Rails application. Indeed, when you have Rack, Rails 3 and Devise 1.1 playing along, great things can be accomplished quite easily!

There are several other features, bug fixes and deprecations included in this release, we invite you to check the CHANGELOG and take a look at them!

And we are happy to say this is not all, there is much more to come in Devise 1.2, including OAuth2 support which is already added in the master branch. Enjoy!

Two months ago we were celebrating Devise’s birthday. We were not talking about its age, Devise had just 4 months of life, but we were happy to reach the 1.0 release.

Today we are celebrating again! We are very proud and glad to have Devise in its first Railscast! Ryan Bates has done a great job explaining how to get Devise up and running in a Rails 3 application, showing how to install Devise and choose the basic modules you want to use in your application.

We also made a promise to you: get Devise up and running for Rails 3. We keep walking this road, each Rails beta version released we are releasing a new compatible Devise version. For the time being, we have Devise 1.1.rc0, a release candidate version, compatible with Rails 3 beta 2.

We are looking forward to see the second part of Devise’s Railscast, about how to configure Devise to fit the needs of your application.

Give Devise a try. You can post your questions to the mailing list and, if you find any issue, please use the Github Issue Tracker. Don’t forget to post information about your environment (like Devise, Warden and Rails versions) including the stack trace if you are facing an error, to help us help you =). Enjoy!

Update: Railscasts just released the second part of Devise screencast, Customizing Devise, going through Devise configuration options. Check it out!

Today we are celebrating Devise‘s birthday. But wait, if you have started watching Devise since the beginning you may be asking: has Devise already completed one year of life? Nope. Today we are completing exactly 4 months since Devise was released at Rails Summit Latin America 2009. And we are very proud and glad to say that we have just reached version 1.0! Yeah! Let’s celebrate and talk a bit about history.

The beginning

We decided to build Devise based on some requirements we had in a project last year. The majority of our projects usually require an admin interface to configure the application with some CRUD information. And in this specific project, we were needing two different roles in the same application, the admin itself with all its powers to manage the application, and the end users that should be signed in to do some stuff inside the application. Usually only one model would be required in this situation, with some “type” column or flag to determine if the user is an admin or not, right? Okay, but we didn’t like this approach that much. So we started looking at some of the possibilities:

  • Authlogic: a really great piece of code and functionality, but a bit messy by handling the session in a model. It also only handles the model part.
  • Clearance: full stack, Rails Engine, extra modules, everything we needed. However, packaged with a User model and without the ability to customize it.

Okay, we could pick one of these and with a bit of extra work we would achieve our requirements. But would we need to do it every time this situation happens? We said no. It’s not DRY enough. And we like DRY. So Devise was born.

The main objective of the first Devise version was to get up and running the entire sign in process, including password recovery and confirmation stuff. And everything should work with different roles, which mean you could easily plug and play an Admin, User, Account, or whichever role you needed, in your application, without much effort. And we had a deadline: Rails Summit. It took almost 1 month of work before Rails Summit. I still remember the days before the event, we putting a lot of effort to have Devise up and running, and the README being written during the event. So, we were ready there and presenting Devise to the world.

How it works

Devise was born with the intuit of handling different roles without effort, automatically, and it is achieved with Rails Engines. In addition, Devise is build in top of Warden, a great rack authentication framework. It allowed us to be flexible enough and add different strategies, hooks, and modules easily. In short, Devise:

  • Is Rack based;
  • Is a complete MVC solution based on Rails Engines;
  • Allows you to have multiple roles (or models/scopes) signed in at the same time;
  • Is based on a modularity concept: use just what you really need.

The road so far

Devise has started with the basic modules needed for that specific application:

  • Authenticatable: responsible for signing users in through a basic login form, handling password validation and authentication.
  • Confirmable: manages confirming users account.
  • Recoverable: handles password recovery.
  • Validatable: basic email and password validation.

Okay, everything we needed were there. Everything else was in a wish list, nicely called TODO. And we decided from the beginning to not add features to Devise until us or somebody else really needed them. But people asked, people needed new features. And they were always there to help, to fork and fix a bug, to comment. We started soon to add new features, the first was:

  • Rememberable: handles signing users in automatically from cookies.

After people were asking for easier ways to create their migrations, so we introduced a new module with Devise 0.2:

  • Migratable: hooks into ActiveRecord migrations to add helper methods for creating Devise colums. So you can do stuff like t.authenticatable, t.confirmable and so on.

To help people getting up and running faster, we created some generators. Now they are:

  • script/generate devise_install: create devise initializer file to enable some configs and copy default locale file.
  • script/generate devise MyModel: create a model with setup for Devise, routes and migration.
  • script/generate devise_views: copy all Devise views to your app/views folder, so you can change it as needed.

Devise 0.3 and 0.4 came soon after, with a lot of bug fixes in generators, I18n, initialization, some deprecations and a bunch of code refactored.

Contributions from community were coming more and more. The first big contribution came with the addition of encryptors. Nowadays Devise supports encrypting passwords with SHA1, SHA512, and BCrypt. It has also support for using the same encryptors as Authlogic, Clearance and Restful Authentication, to help you migrating from these solutions.

At this point we thought: okay, that should be enough. It wasn’t. People needed different ORMs, other than ActiveRecord. So we introduced support to MongoMapper and then we were reaching Devise 0.5.

We were receiving a lot of issues with functional tests, so we introduced some test helpers to help people with the sign in/out process in this kind of tests called Devise::TestHelper.

As applications grow, more roles may be needed. So we created the possibility to scope your views for each role/scope in your application. This way your user can have a different sign in view than the admin, for example. Reaching Devise 0.6, a lot of improvements on routes and DataMapper support were added.

We were full of nice ideas to add new features, and our TODO was bigger than we like. So we came up with:

  • Timeoutable: verify each request to timeout the user session after a certain period of inactivity, asking for credentials again.
  • Trackable: records how many times each user has signed in, last timestamps and ips.

Also the loading process and ORM support received a lot of work before launching Devise 0.7.

For Devise 0.8 we looked at tests for MongoMapper and the code got a great review. Also some work was done to get Devise up and running with latest version of Warden and its new features, such as serializers. We also extracted a new base module from Confirmable:

  • Activatable: allow setting up extra activation methods for your models.

We were receiving a lot of feedback from the community, and then we merged a cool new feature:

  • Lockable: lock accounts based on a number of invalid sign in attempts.

Following the same pattern from Rails in this commit we moved flash messages to :notice and :alert, and released Devise 0.9. Step by step the 1.0 version was coming.

What is new

Devise 1.0 introduces a lot of cool features. The community seems to be really appreciating Devise, and we’ve received another great contribution:

  • Token Authenticatable: validates authenticity of a user while signing in using an authentication token (also known as “single access token”).

In addition, we created the two most requested features for Devise:

  • Registerable: handles sign up users through a registration process, and also editing/updating user info and deleting user account.
  • HTTP Authenticatable: http basic authentication.

We also added the possibility to use Migratable while editing a table using change_table, among other fixes.

What comes next

We are preparing a new release of Devise fully compatible with Rails 3. It means Devise has now closed its development for new features in Rails 2.x. We are still going to maintain a 1.0 branch in github for bug fixes to keep everything up and running.

In the end

We would like to say thank you to everyone who has helped us achieve 1.0 version and who is using Devise, testing, creating issues, and giving all this feedback.

Also, for those who were at Rails Summit last year, we proposed something: get the biggest number of watchers on github as fast as possible! When we presented Devise, there were 7 watchers, and if I am right we were 4 of them. At the time of this writing we have 762 watchers. Yeah! I think I can take the risk and say we accomplished it. Thanks!

Let’s celebrate Devise 1.0, and look forward to see Devise and Rails 3. Enjoy!

Happy birthday Devise!

After Devise was released, there were some misunderstandings about Devise roles and how to use it. And the best way to understand it is explaining which problem we wanted to solve when we designing Devise.

In most applications developed at Plataforma, we usually have two actors: one which represents the client who hired us and another which is the end-user, the audience of the developed app.

Before Devise, we used Authlogic or Clearance as authentication solutions. Authlogic does not say anything about controllers, so we usually had two models (Admin and User) and some controllers to handle sign in, password reset and so forth for each model, which required expressive effort to handle and maintain.

On the other hand, we had Clearance. Clearance deals completely with the User model, but we needed to work on the Admin model almost from scratch.

With Devise, we can have a full stack solution for both User and Admin. But that only works if User and Admin does not need to share a lot of responsibilities.

For instance, if you are working on a blogging system with different roles as “editor”, “author” and “contributor”, but they all share a lot of activities in common, as writing a post, handling such roles with Devise can add a great of complexity to your code, mainly because you will need to use Single Table Inheritance (STI) and/or polymorphic relationships very frequently.

To handle such cases, you can use any of the authorization libraries out there for Rails (remember that Devise is mainly an authentication tool).

Scoped authentication

On the same line, there were some requests to provide authentication by username, instead of e-mail, or providing a subdomain as scope for the authentication. You can now do that using Devise 0.5.1 or higher by just setting the authentication keys in your model:

class User < ActiveRecord::Base
 devise :all, :authentication_keys => [ :username, :subdomain ]
end

Now you user needs an username and subdomain to authenticate and their respective value should be sent as parameters when signing in. Such values are converted to conditions when retrieving the user from the database for authentication. For example, the following path with query string:

/users/sign_in?user[username]=josevalim&user[subdomain]=plataformatec

Is converted to the following query with ActiveRecord:

User.first(:conditions => { :username => "josevalim", :subdomain => "plataformatec" })

And only after retrieving the user we check for password validity. However, keep in mind that those conditions are used only when signing in. If an user is already authenticated, it will be retrieved from session, where such conditions are not used. In other words, you still need a filter in your controllers to verify that the user accessing a given subdomain, is really allowed to access that subdomain.

Such configuration should handle most of the cases, but if you still need more customization, you can overwrite three class methods exposed for exactly this purpose: User.authenticate, User.serialize_into_session and User.serialize_from_session.

Enjoy!

It has been a couple weeks since we first bloged about Devise. At that time, we released version 0.1 and now, after some great feedback, some enhancements and a few bugs fixes, we reached Devise 0.4. So, what changed since then?

I’m lazy, you’re lazy

Devise now comes with generators, so adding up authentication to your app is even easier and quicker to do. First, let’s install Devise if you haven’t yet:

gem sources -a http://gemcutter.org/
gem install devise

And let’s add it to your environment, all together with warden:

config.gem "warden", :version => "0.5.1"
config.gem "devise", :version => "0.4.1"

After setting the gem up, the first generator can be invoked:

script/generate devise_install

And it simply places an initializer at config/initializers/devise.rb. You can check there all devise configuration options, so the initializer fits well as documentation tool too. Some of the new things you can configure since 0.1 release is the :confirm_within period (the time the user can access the site even without confirming his account) and :remember_for period (the time the remember token is valid).

After we configured Devise, we are able create our models. And how hard can that be if we have a generator? So just do:

script/generate devise User

It’s going to create a model User, add map.devise_for :users in routes.rb and a migration file. And before we proceed, we just need to configure default_url_options for ActionMailer in config/environments/development.rb (the config below is for development, be sure to properly set them for test and production too):

config.action_mailer.default_url_options = { :host => 'localhost:3000' }

And have at least a route named root in our config/routes.rb (by default, devise will look for user_root_path, if none is defined, is uses root_path):

map.root :controller => "your_controller"

Now we just need to run migrations and we will be able to create our first user in the console:

User.create!(:email => "your@email.com", :password => "secret")

Now just start your web server and you will be able to sign your user in at /users/sign_in, request for another confirmation code to be sent, request a code to reset your password and so forth.

Just remember that Devise does not say anything about the sign up process, that’s why you have to create your users in console.

Customization

We also know that you want to customize your views, to use something like Formtastic instead of the default markup. Well, guess who is here to help you?

Generators! The command below will make a copy of all devise views to your application, including locale files, for flash messages configuration:

script/generate devise_views

Laziness for all!

We know that you are lazy and not just with ActiveRecord. You want to be lazy with Datamapper, Mongomapper, Couchrest… This is why we worked on making Devise a little bit more agnostic, all your ORM has to do is have an API similar to ActiveRecord (finder and callbacks mainly).

Besides, if you already travelled a bit on Warden world, you will see that there is a lot more than Devise, including some strategies for OAuth. So we are also working on making Devise compatible with such new strategies as well, that’s why you can already see a config.warden hook on the initializer.

Deprecations

Since things are getting really easy, we need to ask something back from you. Just watch out for to deprecations in Devise 0.4.0:

1) :authenticable is a typo, so we fixed that renaming it to :authenticatable. If you used Devise 0.3.x, you could see some deprecation warnings. However, in Devise 0.4.0 such warnings were removed. Tip: be sure to check your migration!

2) We had a notifier inside Devise called Notifier. We decided to follow Clearance convention and rename it to DeviseMailer. You will need to change your views from notifier to devise_mailer and your locale yml from notifier to mailer.

We hope you enjoy Devise as much as we do! And, as previously, we also have an example app in Github to help you get started too.