• Stars
    star
    195
  • Rank 198,225 (Top 4 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 4 years ago
  • Updated 2 months ago

Reviews

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

Repository Details

Devise passwordless logins using emailed magic links

Devise::Passwordless

A passwordless a.k.a. "magic link" login strategy for Devise

Features

  • No special database migrations needed - magic links are stateless encrypted tokens
  • Magic links are sent from your app - not a mounted Rails engine - so path and URL helpers work as expected
  • Supports multiple user (resource) types
  • All the goodness of Devise!

Installation

First, install and set up Devise.

Then add this gem to your application's Gemfile:

gem "devise-passwordless"

And then execute:

$ bundle install

Finally, run the install generator:

$ rails g devise:passwordless:install

See the customization section for details on what gets installed and how to configure and customize.

Usage

This gem adds a :magic_link_authenticatable strategy that can be used in your Devise models for passwordless authentication. This strategy plays well with most other Devise strategies (see notes on other Devise strategies).

For example, if your Devise model is User, enable the strategy like this:

# app/models/user.rb
class User < ApplicationRecord
  devise :magic_link_authenticatable #, :registerable, :rememberable, ...
end

Then, you'll need to set up your Devise routes like so to use the passwordless controllers to modify Devise's default session create logic and to handle processing magic links:

# config/routes.rb
Rails.application.routes.draw do
  devise_for :users,
    controllers: { sessions: "devise/passwordless/sessions" }
  devise_scope :user do
    get "/users/magic_link",
      to: "devise/passwordless/magic_links#show",
      as: "users_magic_link"
  end
end

Finally, you'll want to update Devise's generated views to remove references to passwords, since you don't need them any more!

These files/directories can be deleted entirely:

app/views/devise/passwords
app/views/devise/mailer/password_change.html.erb
app/views/devise/mailer/reset_password_instructions.html.erb

And these should be edited to remove password references:

  • app/views/devise/registrations/new.html.erb
    • Delete fields :password and :password_confirmation
  • app/views/devise/registrations/edit.html.erb
    • Delete fields :password, :password_confirmation, :current_password
  • app/views/devise/sessions/new.html.erb
    • Delete field :password

Manually sending magic links

You can very easily send a magic link at any point like so:

remember_me = true
User.last.send_magic_link(remember_me)

Customization

Configuration options are stored in Devise's initializer at config/initializers/devise.rb:

# ==> Configuration for :magic_link_authenticatable

# Need to use a custom Devise mailer in order to send magic links
require "devise/passwordless/mailer"
config.mailer = "Devise::Passwordless::Mailer"

# Time period after a magic login link is sent out that it will be valid for.
# config.passwordless_login_within = 20.minutes

# The secret key used to generate passwordless login tokens. The default value
# is nil, which means defer to Devise's `secret_key` config value. Changing this
# key will render invalid all existing passwordless login tokens. You can
# generate your own secret value with e.g. `rake secret`
# config.passwordless_secret_key = nil

# When using the :trackable module, set to true to consider magic link tokens
# generated before the user's current sign in time to be expired. In other words,
# each time you sign in, all existing magic links will be considered invalid.
# config.passwordless_expire_old_tokens_on_sign_in = false

To customize the magic link email subject line and other status and error messages, modify these values in config/locales/devise.en.yml:

en:
  devise:
    passwordless:
      not_found_in_database: "Could not find a user for that email address"
      magic_link_sent: "A login link has been sent to your email address. Please follow the link to log in to your account."
    failure:
      magic_link_invalid: "Invalid or expired login link."
    mailer:
      magic_link:
        subject: "Here's your magic login link ✨"

To customize the magic link email body, edit app/views/devise/mailer/magic_link.html.erb

To customise email headers (including the email subject as well as more unusual headers like X-Entity-Ref-ID) pass them in a hash to resource.send_magic_link in SessionsController, eg. resource.send_magic_link(create_params[:remember_me], subject: "Your login link has arrived!").

Multiple user (resource) types

Devise supports multiple resource types, so we do too.

For example, if you have a User and Admin model, enable the :magic_link_authenticatable strategy for each:

# app/models/user.rb
class User < ApplicationRecord
  devise :magic_link_authenticatable # , :registerable, :rememberable, ...
end

# app/models/admin.rb
class Admin < ApplicationRecord
  devise :magic_link_authenticatable # , :registerable, :rememberable, ...
end

Then just set up your routes like this:

# config/routes.rb
Rails.application.routes.draw do
  devise_for :users,
    controllers: { sessions: "devise/passwordless/sessions" }
  devise_scope :user do
    get "/users/magic_link",
      to: "devise/passwordless/magic_links#show",
      as: "users_magic_link"
  end
  devise_for :admins,
    controllers: { sessions: "devise/passwordless/sessions" }
  devise_scope :admin do
    get "/admins/magic_link",
      to: "devise/passwordless/magic_links#show",
      as: "admins_magic_link"
  end
end

And that's it!

Messaging can be customized per-resource using Devise's usual I18n support:

en:
  devise:
    passwordless:
      user:
        not_found_in_database: "Could not find a USER for that email address"
        magic_link_sent: "A USER login link has been sent to your email address. Please follow the link to log in to your account."
      admin:
        not_found_in_database: "Could not find an ADMIN for that email address"
        magic_link_sent: "An ADMIN login link has been sent to your email address. Please follow the link to log in to your account."
    failure:
      user:
        magic_link_invalid: "Invalid or expired USER login link."
      admin:
        magic_link_invalid: "Invalid or expired ADMIN login link."
    mailer:
      magic_link:
        user_subject: "Here's your USER magic login link ✨"
        admin_subject: "Here's your ADMIN magic login link ✨"

Scoped views

If you have multiple Devise models, some that are passwordless and some that aren't, you will probably want to enable Devise's scoped_views setting so that the models have different signup and login pages (since some models will need password fields and others won't).

If you need to generate fresh Devise views for your models, you can do so like so:

$ rails generate devise:views users
$ rails generate devise:views admins

Which will generate the whole set of Devise views under these paths:

app/views/users/
app/views/admins/

Notes on other Devise strategies

If using the :rememberable strategy for "remember me" functionality, you'll need to add a remember_token column to your resource, as by default that strategy assumes you're using a password auth strategy and relies on comparing the password's salt to validate cookies:

change_table :users do |t|
  t.string :remember_token, limit: 20
end

If using the :confirmable strategy, you may want to override the default Devise behavior of requiring a fresh login after email confirmation (e.g. this or this approach). Otherwise, users will have to get a fresh login link after confirming their email, which makes little sense if they just confirmed they own the email address.

Alternatives

Other Ruby libraries that offer passwordless authentication:

License

The gem is available as open source under the terms of the MIT License.

More Repositories

1

docker-ruby

Dockerfiles for lots of MRI Ruby and JRuby interpreters
Shell
34
star
2

simple_form_tailwind_css

Tailwind components for Simple Form
Ruby
30
star
3

how-long-since-google-said-a-google-drive-linux-client-is-coming

HTML
29
star
4

docker-postgres

Postgres 9.3 + WAL-E + PL/V8 and PL/Python languages Docker image
Shell
26
star
5

haskellbook-solutions

My crappy solutions to http://haskellbook.com/
Haskell
22
star
6

gke-demo

Ruby
16
star
7

pdf_ravager

JRuby-only DSL for filling out AcroForms PDF or XFA documents.
Ruby
13
star
8

Kubernetes-on-Rails-Starter-Files

Ruby
11
star
9

gfc64

Obscures database sequential primary keys (or any 64-bit int) using a Feistel cipher. Throw away your UUIDs!
Ruby
10
star
10

docker-nginx

nginx Docker image
Shell
9
star
11

example_rails_docker_ci

CI of Rails Docker images using fig, make, and CircleCI
Ruby
8
star
12

rails-elm-example

Example Rails + Elm application
Ruby
6
star
13

jdbc-openedge

OpenEdge JDBC driver loader
Ruby
6
star
14

ansible-rabbitmq

Ansible RabbitMQ playbook for provisioning an Ubuntu server. Includes IPTables and Vagrant
5
star
15

vss2git

Fork of Trevor Robinson's vss2git project (http://code.google.com/p/vss2git/)
C#
5
star
16

docker-openproject

Shell
4
star
17

abl-email-client

Email client for OpenEdge ABL
OpenEdge ABL
4
star
18

abl-core

Provides some core classes for OpenEdge ABL similar to what the Java JDK provides.
OpenEdge ABL
4
star
19

blog-nanoc

Abandoned blog migration to nanoc
Ruby
3
star
20

gnome-terminal-colorscheme-switcher

Simple Rake script to switch gnome-terminal color schemes
Ruby
3
star
21

dm-openedge-adapter

OpenEdge adapter for DataMapper
Ruby
3
star
22

docker-elasticsearch

Elasticsearch + nginx reverse proxy (basic auth) using Java 7
Shell
3
star
23

BigCharacter

Progress OpenEdge ABL datatype comparable to LONGCHAR
3
star
24

SyntaxHighlighter-Progress-OpenEdge-ABL-Brush

Adds code syntax highlighting for the Progress OpenEdge ABL language to Alex Gorbachev's (JavaScript) SyntaxHighlighter. Also included is a Wordpress plugin that adds support using the existing SyntaxHighlighter Evolved plugin by Viper007Bond.
JavaScript
3
star
25

menosgrande

A URL shortener utilizing IDN domains and Unicode to make very short URLs
Ruby
2
star
26

ansible-playbooks

Ansible playbooks and an example Vagrantfile in the pattern I typically use
2
star
27

dotfiles

Vim Script
2
star
28

abl-zmq

ØMQ (zeromq / 0mq) binding for OpenEdge ABL
OpenEdge ABL
2
star
29

amazon_barcode

Ruby
2
star
30

em-ruby-mmo

EventMachine version of Ruby MMO
Ruby
2
star
31

buds_gun_shop

Basic API for accessing http://www.budsgunshop.com
Ruby
2
star
32

jdbc-openedge-internal

Ruby
1
star
33

abevoelker

1
star
34

programming_in_prolog

My solutions to "Programming in Prolog" (5th ed)
Prolog
1
star
35

nomen

Simple human name formatter
Ruby
1
star
36

scrapinghub-client

Scrapinghub Ruby client
Ruby
1
star
37

uwec_phonebook

Dump and crawl user details from UW-Eau Claire public phonebook
Ruby
1
star
38

advent-of-code-2021

Haskell
1
star
39

erlang_programming_exercises

Exercise solutions to the "Erlang Programming" O'Reilly book
Erlang
1
star
40

rails_tutorial

My progress on Michael Hartl's (awesome!) Ruby on Rails Tutorial
Ruby
1
star