OmniauthPassword
The OmniAuth Password gem is designed to be a simple way to add local login/password authentication along side other strategies. It simply makes ActiveModel's has_secure_password
work directly with OmniAuth like any other provider without the need for a separate Authentication or Identity model.
This gem will work well for you if you want to create your authentication system from scratch. Authenticating to a local User model is treated just like authenticating to an external provider like Twitter. OmniAuth Password stays out of your way leaving local user registration up to you. It does not provide controllers or views.
Installation
Add the strategy to your Gemfile
gem 'omniauth-password'
Add the following to your config/initializers/omniauth.rb
:
Rails.application.config.middleware.use OmniAuth::Builder do
# provider :twitter ...
# provider :github ...
provider :password
end
Add some routes:
match "/auth/:provider/callback" => "sessions#create"
match "/auth/failure", to: "sessions#failure"
resource :session
OmniAuth Password expects a POST to /auth/password/callback
with login params in the session hash. You might create a form something like this:
<h1>Sign in</h1>
<%= form_for(:sessions, url: "/auth/password/callback") do |f| %>
<div class="field">
<%= label_tag :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= label_tag :password %><br />
<%= f.password_field :password %>
</div>
<div class="actions">
<%= submit_tag "Sign in" %>
</div>
<% end %>
Your Sessions controller's create
method takes the omniauth hash from this and any other strategy you are using; it might look something like this:
class SessionsController < ApplicationController
def new
end
def create
user = User.from_omniauth(request.env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url, notice: "Signed in"
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Signed out"
end
def failure
redirect_to new_session_path, notice: "Authentication failed"
end
end
The User model does not need a uid
field for OmniAuth because it reuses the password_digest field when not doing local login/password authentication. ActiveModel's has_secure_password
causes password_digest to be a required field.:
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255)
# provider :string(255)
# password_digest :string(255)
#
class User < ActiveRecord::Base
has_secure_password
def self.from_omniauth(auth)
find_by_provider_and_password_digest(auth["provider"], auth["uid"]) || create_with_omniauth(auth)
end
def self.create_with_omniauth(auth)
create! do |user|
user.provider = auth["provider"]
user.password_digest = auth["uid"]
user.name = auth["info"]["name"]
end
end
end
Customizing
By default, OmniAuth Password expects to authenticate to the email and password of the User model. You can override these in your config/initializers/omniauth.rb
:
Rails.application.config.middleware.use OmniAuth::Builder do
# provider :twitter ...
# provider :github ...
provider :password, :login_field => :username, :user_model => Admin
end