Skip to main content

Documentation Index

Fetch the complete documentation index at: https://usegately.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Magic links provide passwordless authentication by sending a secure login link to the user’s email.
await gately.sendMagicLink(email, options)

Parameters

ParameterTypeRequiredDescription
emailstringYesUser’s email address
options.redirectTostringNoURL to redirect after login

Example

import { GatelyClient } from '@gately/sdk'

const gately = new GatelyClient('YOUR_PROJECT_ID')

async function handleMagicLink(email) {
  try {
    await gately.sendMagicLink(email, {
      redirectTo: '/dashboard'
    })
    
    // Show success message
    showMessage('Check your email for a login link!')
  } catch (error) {
    console.error('Failed to send magic link:', error.message)
  }
}

React Component

import { useState } from 'react'
import { useGately } from '@gately/sdk'

function MagicLinkForm() {
  const { sendMagicLink } = useGately()
  const [email, setEmail] = useState('')
  const [sent, setSent] = useState(false)
  const [error, setError] = useState('')

  const handleSubmit = async (e) => {
    e.preventDefault()
    setError('')

    try {
      await sendMagicLink(email, { redirectTo: '/dashboard' })
      setSent(true)
    } catch (err) {
      setError(err.message)
    }
  }

  if (sent) {
    return (
      <div className="success">
        <h2>Check your email</h2>
        <p>We sent a login link to {email}</p>
        <button onClick={() => setSent(false)}>
          Use a different email
        </button>
      </div>
    )
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <p className="error">{error}</p>}
      
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Enter your email"
        required
      />
      
      <button type="submit">
        Send Magic Link
      </button>
    </form>
  )
}

How It Works

  1. User enters their email
  2. SDK sends request to Gately API
  3. Gately sends email with secure link
  4. User clicks link in email
  5. Link redirects to your app with auth token
  6. SDK automatically logs user in

Email Template

The magic link email includes:
  • Your project name/branding
  • Login button with secure link
  • Link expiry notice (default: 1 hour)
  • Security notice
Customize the email template in Settings > Email > Templates. Magic links expire after 1 hour by default. If a user clicks an expired link:
  • They see an error message
  • They’re prompted to request a new link

Security

Magic links are:
  • Single-use (invalidated after first use)
  • Time-limited (expire after 1 hour)
  • Cryptographically signed
  • Tied to specific email address

New vs Existing Users

ScenarioBehavior
Existing userLogs in to existing account
New userCreates account and logs in
// Works for both new and existing users
await gately.sendMagicLink('user@example.com')

Error Handling

try {
  await gately.sendMagicLink(email)
} catch (error) {
  switch (error.code) {
    case 'INVALID_EMAIL':
      showError('Please enter a valid email address')
      break
    case 'RATE_LIMITED':
      showError('Too many requests. Please wait a moment.')
      break
    default:
      showError('Failed to send login link. Please try again.')
  }
}

Rate Limiting

Magic link requests are rate limited to prevent abuse:
  • 3 requests per email per 10 minutes
  • 10 requests per IP per 10 minutes

Combining with Password Login

Offer both options for flexibility:
function LoginOptions() {
  const [mode, setMode] = useState('password') // or 'magic'

  return (
    <div>
      <div className="tabs">
        <button 
          className={mode === 'password' ? 'active' : ''}
          onClick={() => setMode('password')}
        >
          Password
        </button>
        <button 
          className={mode === 'magic' ? 'active' : ''}
          onClick={() => setMode('magic')}
        >
          Magic Link
        </button>
      </div>

      {mode === 'password' ? (
        <PasswordLoginForm />
      ) : (
        <MagicLinkForm />
      )}
    </div>
  )
}