• This repository has been archived on 24/Jul/2023
  • Stars
    star
    372
  • Rank 111,241 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 11 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Oath is rails authentication made simple. Previously known as Monban

NOTICE

Monban is currently in the process of being renamed Oath: https://github.com/halogenandtoast/oath

Oath

Build Status Code Climate

Oath is designed to be a very simple and extensible user authentication library for rails. Its goal is to give all the power to the developer instead of forcing them to make Oath work with their system.

Why use Oath?

Oath makes authentication simple:

  • Easy to use in tests with dependency injection
  • Provides convenient controller helpers
  • Very customizable

Oath doesn't do the following:

  • Doesn't automatically add routes to your application
  • Doesn't force you to use engine based controllers or views
  • Doesn't require you to make changes to your user model

Documentation

You can read the full documentation at rubydoc

Installation

Oath was designed to work with Rails > 4.0. Add this line to your Gemfile:

gem 'oath'

Then inside of your ApplicationController add the following:

include Oath::ControllerHelpers

And you're ready to start designing your authentication system.

Generators

If you'd like a good starting point for building an app using Oath, it is suggested to use the oath generators

Usage

Oath does currently have some out-of-the-box expectations, but you can configure and change any of these:

  • By default the model should be called User
  • Oath expects your user model to respond to create, id, and find_by
  • You should have an email and password_digest column on your User
  • Passwords will be handled with BCrypt

Suggestions

Console Usage

If you're trying to sign up a User in a console you won't be able to call User#new or User#create because the User model does not know how to encrypt passwords. You should instead use the sign up service in order to create the user:

Oath.config.sign_up_service.new(email: "[email protected]", password: "password").perform

Validations

Oath doesn't add validations to your user model unless you're using oath generators so it's suggested to add the following validations:

validates :email, presence: true, uniqueness: true
validates :password_digest, presence: true

In addition to that you'll want to add the following to your config/locale/en.yml:

en:
  activerecord:
    attributes:
      user:
        password_digest: "Password"

Which will generate the error message Password can't be blank instead of Password digest can't be blank.

Layout changes

It is suggested you add something like this to your application layout:

<% if signed_in? %>
  <%= link_to "Sign out", session_path, method: :delete %>
<% else %>
  <%= link_to "Sign in", new_session_path %>
  <%= link_to "Sign up", new_user_path %>
<% end %>

Guest user

If you want to introduce a Guest object when a user is not signed in, you can override Oath's current_user method in your ApplicationController:

def current_user
  super || Guest.new
end

In app/models/, define a Guest class:

class Guest
  def name
    "Guest"
  end
end

This article on the Null Object Pattern provides a good explanation of why you might want to do this.

Using I18n for sign in notice

If you want to use I18n for the notice instructing users to sign in when they try to access an unauthorized page you can do so with the following configuration:

Oath.configure do |config|
  config.sign_in_notice = -> { I18n.t("sign_in_notice") }
end

It is suggested to store this file at config/initializers/oath.rb

Controller Additions

Oath provides the following controller methods:

  • sign_in(user)
  • sign_out
  • sign_up(user_params)
  • authenticate(user, password)
  • authenticate_session(session_params)
  • reset_password(user, password)

These helpers:

  • current_user
  • signed_in?

And this filter:

  • require_login

Routing Constraints

To authorize users in config/routes.rb:

require "oath/constraints/signed_in"
require "oath/constraints/signed_out"

Blog::Application.routes.draw do
  constraints Oath::Constraints::SignedIn.new do
    root "dashboards#show", as: :dashboard
  end

  constraints Oath::Constraints::SignedOut.new do
    root "landings#show"
  end
end

Usage in Tests

Test mode

Oath provides the following:

Oath.test_mode!

Which will change password hashing method to provide plaintext responses instead of using BCrypt. This will allow you to write factories using the password_digest field:

FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@example.com" }
    password_digest 'password'
  end
end

Spec helpers

A couple of convenience methods are available in your tests. In order to set this up you'll want to add the following to rails_helper.rb or if that doesn't exist spec_helper.rb

Oath.test_mode!

RSpec.configure do |config|
  config.include Oath::Test::Helpers, type: :feature
  config.after :each do
    Oath.test_reset!
  end
end

Then you can use any of the test helpers in your scenarios

feature "A feature spec" do
  scenario "that requires login" do
    user = create(:user)
    sign_in(user)
    # do something
    sign_out
    # do something else
  end
end

Oath Backdoor

Similar to clearance's backdoor you can visit a path and sign in quickly via

user = create(:user)
visit dashboard_path(as: user)

To enable this functionality you'll want to add the following to config/environments/test.rb:

config.middleware.insert_after Warden::Manager, Oath::BackDoor

If you'd like to find your User model by a field other than id, insert the middleware with a block that accepts the as query parameter and returns an instance of your User model:

config.middleware.insert_after Warden::Manager, Oath::BackDoor do |user_param|
  User.find_by(username: user_param)
end

Controller Specs

If you are going to write controller tests, helpers are provided for those as well:

Oath.test_mode!

RSpec.configure do |config|
  config.include Oath::Test::ControllerHelpers, type: :controller
  config.after :each do
    Oath.test_reset!
  end
end
require 'spec_helper'

describe ProtectedController do

  describe "GET 'index'" do
    it "returns http success when signed in" do
      user = create(:user)
      sign_in(user)
      get 'index'
      response.should be_success
    end

    it "redirects when not signed in" do
      get 'index'
      response.should be_redirect
    end
  end
end

Advanced Functionality

Authentication with username instead of email

If you want to sign in with username instead of email just change the configuration option

# config/initializers/oath.rb
Oath.configure do |config|
  config.user_lookup_field = :username
end

If you used the oath:scaffold generator from oath generators you'll have to change the following four references to email.

  • In SessionsController#session_params
  • In UsersController#user_params
  • The email form field on sessions#new
  • The email form field on users#new

Using multiple lookup fields

You may perform a look up on a user using multiple fields by doing something like the following:

class SessionsController < ApplicationController
  def create
    user = authenticate_session(session_params, email_or_username: [:email, :username])

    if sign_in(user)
      redirect_to(root_path)
    else
      render :new
    end
  end

  private

  def session_params
    params.require(:session).permit(:email_or_username, :password)
  end

end

This will allow the user to enter either their username or email to login

Configuration

Oath::Configuration has lots of options for changing how oath works. Currently the options you can change are as follows:

User values

  • user_lookup_field: (default :email) Field in the database to lookup a user by.
  • user_token_field: (default :password) Field the form submits containing the undigested password.
  • user_token_store_field: (default: :password_digest) Field in the database that stores the user's digested password.
  • user_class: (default: 'User') The user class.

Services

  • sign_in_notice: (default: You must be signed in) Rails flash message to set when user signs in.
  • sign_in_service: (default: Oath::Services::SignIn) Service for signing a user in.
  • sign_up_service: (default: Oath::Services::SignUp) Service for signing a user up.
  • sign_out_service: (default: Oath::Services::SignOut) Service for signing a user out.
  • authentication_service: (default: Oath::Services::Authentication) Service for authenticated a user.
  • password_reset_service: (default: Oath::Services::PasswordReset) Service for resetting a user's password.

Rails values

  • no_login_handler: A before_action for rails that handles when a user is not signed in.
  • no_login_redirect: Used by the no_login_handler to redirect the user

Methods

  • hashing_method: Method to hash an undigested password.
  • token_comparison: Method to compare a digested and undigested password.
  • creation_method: Method for creating a user.
  • find_method: Method for finding a user.

Warden Settings

  • failure_app: Necessary for warden to work. A rack app that handles failures in authentication.

Limitations

Here are a few of the current limitations of oath:

  • Oath assumes you only have one user model.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

More Repositories

1

alchemist

A scientific conversion library.
Ruby
155
star
2

ArkhamHorror

A rules-compliant browser based version of Arkham Horror: The Card Game.
Haskell
55
star
3

excelsior

Makefile
37
star
4

dagon

The programming language of the elder gods.
Ruby
29
star
5

reconstructing-ruby

Ruby implementation for the blog post series http://www.halogenandtoast.com/reconstructing-ruby-an-introduction/
Bison
19
star
6

oath-generators

Rails generators for the oath authentication library
Ruby
16
star
7

vim

vim
Vim Script
8
star
8

intermediate_workshop

Ruby
7
star
9

nhk-reader-haskell

Haskell implementation of my NHK Reader
Haskell
7
star
10

griddle

GridFS made simple.
Ruby
7
star
11

MarvelChampions

A rules-compliant browser based version of Marvel Champions.
Haskell
5
star
12

terminal_minesweeper

Minesweeper in the terminal
Ruby
4
star
13

intro_workshop

Ruby
4
star
14

kitsune

Ruby
3
star
15

mirin

A tiny redirection server in Spock backed by MySQL.
Haskell
3
star
16

game

A Game
C++
3
star
17

presentable

Simple presenters for rails.
Ruby
3
star
18

timelord

Parse dates out of strings
Ruby
3
star
19

AdventOfCode2020

Haskell
3
star
20

holdem

Texas Hold'em API Competition
Ruby
2
star
21

tengu

A RSpec-like testing framework.
Ruby
2
star
22

intermediate

intermediate
Ruby
2
star
23

Robots-Tower-Defense

Node.js game for 2011 Node Knockout competition
JavaScript
2
star
24

dotfiles

Delectable dotfiles!
Vim Script
2
star
25

codenames

A rails version of the codenames board game
Ruby
2
star
26

LightsOut

Lights out implementation in Haskell
Haskell
2
star
27

Pinchlist

A project
Ruby
2
star
28

halogenandtoast.github.io

resume
HTML
1
star
29

haskell-cabal-new-buildpack

Shell
1
star
30

count_von_count

Ruby
1
star
31

irxml

Gem for dealing with irxml's api
Ruby
1
star
32

babushka-deps

Personal Deps for Babushka
1
star
33

scrub

Ruby
1
star
34

squawkr

Haskell
1
star
35

intermediate_workshop_2_11_13

intermediate_workshop_2_11_13
Ruby
1
star
36

bonsai

The bonsai programming language
C
1
star
37

boardgamenight

The board game night app.
Ruby
1
star
38

memori

memoriapp.com
Ruby
1
star
39

AdventOfCode2021

Haskell
1
star
40

dagon-c

A C implementation of the dagon language
C
1
star
41

tagged

Ruby
1
star
42

boardy

A slack bot for finding boardgamegeek games
Haskell
1
star
43

intermediate_rails

intermediate_rails
Ruby
1
star
44

terminal

terminal settings
Shell
1
star
45

opengl_experiments

opengl_expriments
C++
1
star
46

opengl_project

C++
1
star