Blog | G5 Cyber Security

Magic Link Authentication

TL;DR

Let users log in without passwords by clicking a unique link sent to their email address after they initiate the process on an external website. This guide explains how to set it up.

How It Works

The basic flow is:

  1. User starts login on your external site (e.g., a marketing page).
  2. Your site asks for the user’s email address.
  3. Your site generates a unique, time-limited token and creates a link containing it.
  4. Your site sends an email to the provided address with this magic link.
  5. The user clicks the link in their email.
  6. Your server validates the token. If valid, log the user in.

Step-by-Step Guide

This guide assumes you have a basic web application with an email sending capability.

1. Choose a Token Generation Method

You need a secure way to create unique tokens. Here are some options:

Example using Python:

import secrets
import string

def generate_token(length=32):
    alphabet = string.ascii_letters + string.digits
    return ''.join(secrets.choice(alphabet) for i in range(length))
token = generate_token()
print(token)

2. Store Tokens Securely

You need a place to store the tokens and associate them with users.

Important considerations:

3. Create the Magic Link

When the user submits their email address, generate a token and create a link that includes it.

base_url = "https://yourwebsite.com/login" # Replace with your actual URL
token = generate_token()
expiry_time = datetime.now() + timedelta(minutes=15)
db.insert_token(user_id, token, expiry_time)  # Store in database
magic_link = f"{base_url}?token={token}"
send_email(email_address, "Login Link", f"Click here to log in: {magic_link}")

4. Handle the Magic Link Click

When a user clicks the link, your server needs to validate it.

  1. Extract Token: Get the token from the URL query parameters (e.g., request.args.get('token')).
  2. Validate Token: Check if the token exists in your database/Redis and hasn’t expired.
  3. Log In User: If valid, retrieve the associated user ID and log them in (e.g., create a session or issue a JWT).
  4. Mark Token as Used: Update the token record to prevent reuse.

Example (simplified):

token = request.args.get('token')
token_record = db.get_token(token)
if token_record and token_record['expiry_time'] > datetime.now():
    user_id = token_record['user_id']
    db.mark_token_as_used(token)
    # Log user in (e.g., create session)
    session['user_id'] = user_id
    return redirect('/dashboard')
else:
    return "Invalid or expired link"

5. Security Considerations

Exit mobile version