OOZOU
Get in Touch
Back to Blog

How to Implement Passwordless Authentication in Ruby on Rails

We recently discussed the benefits of passwordless authentication. Now let's take a look at how to implement passwordless authentication in Ruby on Rails

December 31, 2020
4 min read
How to Implement Passwordless Authentication in Ruby on Rails

In the previous article I discussed the benefits of passwordless authentication. In this article I'm going to demonstrate how to implement magic sign in link emails in Ruby on Rails. For those unfamiliar, magic login links allow a user to log into their account without entering a password. Instead of the traditional email and password form, the user only needs to enter their email address. The system will then send a link to the user which contains a token linked to their account. When the user clicks the link they will be taken to the application and seamlessly logged into their account. With this technique we can even log them into native applications through the usage of deeplinks.

Let's Write Some Code

The first thing we need to do is add a new column to our Users to store the login tokens. We'll use UUIDs to make generation simpler.

rails g migration add_login_token_to_users login_token:uuid

Now let's create a controller to handle the log ins. This controller won't be strictly RESTful as we can't use a post request from the users email client. I normally use magic_logins_controller so we can also reserve sessions controller for password logins should we ever want to have both.

class MagicLoginsController < ApplicationController
  def new; end

  def create
    if (user = User.find_by(login_token_params))
      user.generate_login_token!
      LoginMailer.with(user: user).magic_login_email.deliver_later
      redirect_to(new_magic_login_path, notice: 'Please check your inbox')
    else
      redirect_to(new_magic_login_path, alert: 'It looks like that email is not registered')
    end
  end

  private def login_token_params
    params.require(:login_token).permit(:email)
  end
end
``` ```ruby
Rails.application.routes.draw do
  resources :magic_logins, only: %i[new create]
end

Let's add a view for the new action. I'm not going to style this, you can style however you like, we'll simply add a form for an example.

<%= form_for(User.new, url: magic_logins_path, method: :post do %>
  <%= f.label :email %>
  <%= f.email_field :email %>
  <%= f.submit 'Send me a magic login link' %>
<% end %>

Next we need to add a method to generate a new token to our User model.

class User < ApplicationRecord
  def generate_login_token!
    update_column(:login_token, SecureRandom.uuid)
  end
end

We don't need to validate anything here as we're using UUIDs so we should be safe. Ok, so next, let's create our _magic_login_email. _

class LoginMailer < ApplicationMailer
  def magic_login_email
    user = params[:user]
    @magic_login_url = magic_logins_url(token: user.login_token)
    mail(to: user.email, subject: "Here's your login link")
  end
end
``` ```erb
<h1>Here's your login link</h1>
<%= link_to 'Log in now', @magic_login_url %>

You might have noticed we're using the index url and passing the token as a query string. You can do this other ways but this approach is simple and fits in with what Rails already offers. It does of course violate RESTful principles so you might prefer to use another approach. Now we just need to add the logic to sign in the users. I'm going to assume you're using Devise. If you're using another gem or are managing sessions manually you'll need to adjust this logic.

class MagicLoginsController < ApplicationController
  def index
    redirect_to root_path unless params[:token].present?

    user = User.find_by(login_token: params[:token])
    if user
      sign_in(user)
      user.update_column(:login_token, nil)
      redirect_to after_sign_in_path, notice: 'Logged in successfully!'
    else
      redirect_to new_magic_login_path, alert: 'The link you used was invalid. Please request a new login link'
    end
  end
end

As you can see we are signing in the user and then removing the login token from the database. This prevents the token from being used more than once. Everything is all hooked up and users can now login using magic links. You may also like to restrict how long the tokens are valid for. To do this we can simply add another column to track when the token was created and verify it hasn't expired

rails g migration add_login_token_generated_at_to_users login_token_generated_at:datetime
``````ruby
class MagicLoginsController < ApplicationController
  def index
    redirect_to root_path unless params[:token].present?

    user = User.find_by(login_token: params[:token])
    if user
      if user.login_token_generated_at < 15.minutes.ago
        redirect_to new_magic_login_path, alert: 'The link you used has expired. Please request a new login link'
      end
      sign_in(user)
      user.update_column(:login_token, nil)
      redirect_to after_sign_in_path, notice: 'Logged in successfully!'
    else
      redirect_to new_magic_login_path, alert: 'The link you used was invalid. Please request a new login link'
    end
  end
end
``` ```ruby
Rails.application.routes.draw do
  resources :magic_logins, only: %i[index new create]
end

That's all there is to it. It's really quite simple to implement.

Related Articles

How Can I Design a Software: A Beginners Guide for Business Owners

How Can I Design a Software: A Beginners Guide for Business Owners

Designing software is an exciting yet complex process that involves creativity, logical thinking, and problem-solving skills.

Read More →
The Future of Edge Computing: What Businesses Need to Know

The Future of Edge Computing: What Businesses Need to Know

The digital landscape is evolving rapidly, and businesses must adapt to keep up with rising demands for speed, efficiency, and real-time processing.

Read More →
The Future of Retail: AI, AR, and Digital Transformation Trends

The Future of Retail: AI, AR, and Digital Transformation Trends

Retail is evolving at an unprecedented pace, driven by AI (Artificial Intelligence), AR (Augmented Reality), and digital transformation technologies, revolutionizing the retail industry. Traditional brick-and-mortar stores are no longer just about selling products—they are becoming smart, interactiv

Read More →

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

Start a Conversationhello@oozou.com
OOZOU Logo

Bangkok · Singapore · Hong Kong

X
Facebook
Instagram
LinkedIn

Services

  • Web Development
  • AI Agents & Generative AI
  • Mobile App Development
  • Data Analytics & Engineering
  • UI/UX & Product Design
  • Digital Transformation

Company

  • About Us
  • Careers
  • Blog
  • Case Studies
  • Today I Learned
  • Contact

More

  • Industries
  • Partner Network
© 2026 OOZOU. All rights reserved.
Privacy PolicyCode of ConductABAC Policy