Authsome
1.x
Docs/Authsome/Magic Link Plugin
Open

Reading3 min
Updated31 Jul 2026
Sourcev1/plugins/magiclink.mdx

The magiclink plugin provides passwordless authentication. Users enter their email address, receive a one-time link, and clicking it authenticates them instantly -- no password required.

Setup01

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/magiclink"
)

eng, err := authsome.NewEngine(
    authsome.WithStore(store),
    authsome.WithPlugin(magiclink.New(magiclink.Config{
        Mailer: magiclink.MailerFunc(func(ctx context.Context, email, token string) error {
            link := fmt.Sprintf("https://example.com/auth/magic?token=%s", token)
            return mailer.Send(ctx, email, "Sign in to My App", link)
        }),
        TokenTTL:          10 * time.Minute,
        SessionTokenTTL:   1 * time.Hour,
        SessionRefreshTTL: 30 * 24 * time.Hour,
    })),
)

Configuration02

OptionTypeDefaultDescription
Mailermagiclink.MailerrequiredSends the magic link email
TokenTTLtime.Duration10mHow long the magic link token is valid
SessionTokenTTLtime.Duration1hLifetime of sessions created via magic link
SessionRefreshTTLtime.Duration30dLifetime of refresh tokens for magic link sessions

Implemented interfaces03

InterfacePurpose
PluginBase plugin identity ("magiclink")
OnInitCaptures the store reference from the engine
RouteProviderRegisters /v1/auth/magic-link/send and /verify endpoints

Authentication flow04

Request magic link: The user submits their email address.

POST /v1/auth/magic-link/send

{"email": "[email protected]", "app_id": "myapp"}

The plugin creates a verification record with a random token, stores it in the database with the configured TTL, and calls the Mailer to deliver the link.

Response:

{"status": "magic link sent"}

The response is always successful regardless of whether the email exists. This prevents email enumeration.

Verify magic link: The user clicks the link, which sends the token to the verify endpoint.

POST /v1/auth/magic-link/verify

{"token": "the-token-from-email", "app_id": "myapp"}

The plugin validates the token, checks expiration, ensures it has not been consumed, looks up the user, creates a session, and returns the authentication result.

Response:

{
  "user": { "id": "ausr_01j9...", "email": "[email protected]" },
  "session_token": "a3f8c9d4...",
  "refresh_token": "d72b1ef8...",
  "expires_at": "2024-11-01T11:00:00Z"
}

Token security05

Magic link tokens are:

  • Cryptographically random -- generated using crypto/rand

  • One-time use -- consumed immediately on verification

  • Time-limited -- expire after TokenTTL (default 10 minutes)

  • Stored server-side -- tokens are verification records in the database, not JWTs

If a token is expired or already consumed, the verify endpoint returns 401 Unauthorized.

Custom Mailer implementation06

The Mailer interface requires a single method:

type Mailer interface {
    SendMagicLink(ctx context.Context, email, token string) error
}

Use MailerFunc to adapt a plain function:

magiclink.Config{
    Mailer: magiclink.MailerFunc(func(ctx context.Context, email, token string) error {
        link := fmt.Sprintf("https://example.com/auth/magic?token=%s", token)
        return sendEmail(ctx, email, "Sign in", link)
    }),
}

API routes07

MethodPathDescription
POST/v1/auth/magic-link/sendSend a magic link to the given email
POST/v1/auth/magic-link/verifyVerify a magic link token and create a session

Per-app session configuration08

When the engine has per-app session configuration (via AppSessionConfig), the magic link plugin uses it to determine token and refresh token TTLs. The plugin-level SessionTokenTTL and SessionRefreshTTL are used as fallbacks.