Implementing Magic Links in Rails
What is a Magic Link?
Magic Links are links that provide instant sign-in without entering a password.
You may have encountered a website that only asks for your email. They will send you an email with a link that you will use to authenticate and access the site.
What solutions are out there?
If this is something that you'd like to implement, naturally you'd see what tools and libraries are available for this service.
There are tools out there like:
and gems like:
They provide capabilities to do magic links, however executing magic links is really not a complicated feature and something you can pull off without dependency on any external tools.
GlobalID
GlobalID is a tool that's included in ActiveRecord that easily allows you to identify objects using an identifier.
Here's an example of its usage:
These signed global IDs are set to expire in 1 month by default, however you can set the expiration to your liking.
Furthermore, you can scope the usage of the SGID by setting the :for
option.
How to implement
To implement this feature on your app, you need to do 2 things:
- Add a controller action that will handle the magic link.
- Create an email that will send out the magic link.
1. Magic link handler
In one of your controllers (ideally sessions_controller.rb), you will create an action that will look similar to below that will retrieve the sgid
from params.
def magic_link
sgid = params.require(:sgid)
user = GlobalID::Locator.locate_signed(sgid, for: 'login')
if user.nil? || !user.is_a?(User)
redirect_to root_path
else
sign_in(user)
redirect_to root_path
end
end
Also remember to add a route for this action!
2. Create the magic link for the email
Create an SGID for the user. You can optionally set the :expires_in
and :for
arguments.
user.to_sgid(expires_in: 30.days, for: 'login').to_s
In your email, you set the button's href to your controller action with the sgid as a param.
magic_link_sessions_url(sgid: sgid)
And that's it!
With minimal lines of code, you have implemented magic links for your application without any reliance on external libraries.