Magic Link Expired
magic_link_expired401
This magic link timed out. Magic links are valid for a short window — request a fresh one.
What this means
The magic link token in the request was valid and unused, but it's past its expiration window. Magic links don't last indefinitely — they're issued with a short TTL (typically 15-30 minutes) so a leaked or intercepted link has a bounded lifetime. The token's record still exists but its expiration timestamp has passed.
When you'll see this
- The user requested a magic link, got distracted, and clicked it an hour later.
- A delayed email delivery (corporate filters, mailing-list relays) arrived after the link had already expired.
- A user requested a link, switched devices, found the email on the new device much later, and tried to use it.
- A test or staging environment was paused mid-flow and resumed after the link's TTL.
Learn more about how this works
Every magic link carries an expiration timestamp set at creation. When you submit a token, we check three things: does it exist, has it been used, and is it within its TTL. Failing any of those returns a distinct error code (magic_link_not_found, magic_link_already_used, magic_link_expired). The TTL exists to bound the credential lifetime — a long-lived link is a long-lived security risk.
The most common gotcha: users sometimes assume "I just got this email, it must be fresh." But the email might have sat in a relay or filter queue for hours. The link's freshness is dated from when we issued it, not when they received it.
Example response
{
"success": false,
"error": "magic_link_expired",
"message": "This magic link has expired. Request a new one.",
"details": [],
"retry_after": null,
"doc_url": "https://docs.asterwise.com/reference/errors/magic_link_expired",
"request_id": "req_01HXYZABCDEFGH",
"timestamp": "2026-05-25T12:34:56Z"
}
- Go to asterwise.com/signin and request a fresh magic link.
- Open the email promptly and click the link within the displayed window.
- If you keep hitting this error and you're clicking promptly, check your email infrastructure — there may be a delivery delay between Asterwise sending and your inbox receiving.
Same UI-layer shape as the other magic-link errors. Show a clear message and a request-new-link button.
Python:
Production handler
- Python
- TypeScript
import httpx
def verify_magic_link(token, base_url, headers):
response = httpx.post(
f"{base_url}/v1/auth/verify",
headers=headers,
json={"token": token},
timeout=10,
)
if response.status_code == 401:
body = response.json()
if body.get("error") == "magic_link_expired":
return {
"ok": False,
"user_message": (
"This sign-in link has expired. "
"Magic links are valid for a short window — "
"request a fresh one to continue."
),
}
response.raise_for_status()
return {"ok": True, "data": response.json()}
async function verifyMagicLink(
token: string,
baseUrl: string,
headers: HeadersInit,
) {
const response = await fetch(`${baseUrl}/v1/auth/verify`, {
method: "POST",
headers,
body: JSON.stringify({ token }),
});
if (response.status === 401) {
const body = await response.json();
if (body.error === "magic_link_expired") {
return {
ok: false,
userMessage:
"This sign-in link has expired. " +
"Magic links are valid for a short window — " +
"request a fresh one to continue.",
};
}
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return { ok: true, data: await response.json() };
}
Avoid this error by
- Tell users to check their email promptly after requesting a link. A line like "Check your email — link expires in 15 minutes" sets expectations.
- For environments with known email-delivery latency (large enterprises, government), consider session-token flows or SSO instead of magic links.
- If you control the email template, include the expiration timestamp visibly so users know if they're cutting it close.
- Don't queue or schedule emails containing magic links — they should be sent immediately on link generation.