{
    "archive_path": "archive/1774536262.601131",
    "base_url": "etodd.io/2026/03/22/magic-link-pitfalls",
    "basename": "",
    "bookmarked_date": "2026-03-26 14:44",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/etodd.io/2026/03/22/magic-link-pitfalls",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=etodd.io",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": null
    },
    "domain": "etodd.io",
    "downloaded_at": "2026-03-26T14:44:25.734833+00:00",
    "downloaded_datestr": "2026-03-26 14:44",
    "extension": "",
    "hash": "3MJM5FYYPJSED3Y5WV6D",
    "history": {
        "archive_org": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://web.archive.org/save/https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2026-03-26T14:46:23.518090+00:00",
                "index_texts": null,
                "output": "TimeoutExpired: Command '['/usr/bin/curl', '--silent', '--location', '--compressed', '--proxy', 'socks5://tor-socks-proxy:9150', '--head', '--max-time', '60', '--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)', 'https://web.archive.org/save/https://etodd.io/2026/03/22/magic-link-pitfalls/']' timed out after 60 seconds",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:45:23.445059+00:00",
                "status": "failed"
            }
        ],
        "dom": [
            {
                "cmd": [
                    "/usr/bin/chromium-browser",
                    "--proxy-server=socks5://tor-socks-proxy:9150",
                    "--disable-features=DarkMode",
                    "--run-all-compositor-stages-before-draw",
                    "--hide-scrollbars",
                    "--autoplay-policy=no-user-gesture-required",
                    "--no-first-run",
                    "--use-fake-ui-for-media-stream",
                    "--use-fake-device-for-media-stream",
                    "--simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT'",
                    "--headless=new",
                    "--no-sandbox",
                    "--no-zygote",
                    "--disable-dev-shm-usage",
                    "--disable-software-rasterizer",
                    "--disable-sync",
                    "--window-size=1440,2000",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "--user-data-dir=/data/personas/Default/chrome_profile",
                    "--profile-directory=Default",
                    "--dump-dom",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "131.0.6778",
                "end_ts": "2026-03-26T14:44:42.430239+00:00",
                "index_texts": null,
                "output": "output.html",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:44:36.372374+00:00",
                "status": "succeeded"
            }
        ],
        "favicon": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.google.com/s2/favicons?domain=etodd.io"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2026-03-26T14:44:28.917241+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:44:26.284248+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2026-03-26T14:44:29.116039+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:44:28.950912+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [
            {
                "cmd": [
                    "(internal) archivebox.extractors.htmltotext",
                    "./{singlefile,dom}.html"
                ],
                "cmd_version": "0.8.5rc51",
                "end_ts": "2026-03-26T14:45:13.101683+00:00",
                "index_texts": [
                    "Magic Link Pitfalls \u00b7 Evan Todd (/css/style.css) (/css/fonts.css) (/custom.css) () (Evan Todd)  (/) Evan Todd  (Email) (mailto:evan@etodd.io)     (Github) (https://github.com/etodd)     (LinkedIn) (https://linkedin.com/in/evantodd)     (YouTube) (https://www.youtube.com/@helvetica.scenario)      (/archive/) Archive   (/about/) About me      Magic Link Pitfalls Mar 22, 2026 Recently I was surprised to discover that there are several bad ways to do magic links. The basic idea is: a user hits \u201clogin\u201d, enters their email address, and receives an email that allows them to login without a password.\nWhat could possibly go wrong? I work in security, so I already knew a few best practices I would need to implement: The link should have a short expiration The link should only work once The link should include a secret code with a sufficient amount of entropy (I went with 64 bits; your paranoia may vary) The database should store a hash of the secret code, not the code itself  Here\u2019s two more that were not immediately obvious to me. Require a click My first attempt at a magic link logged the user in immediately as soon as they clicked it.\nThat is, as soon as their browser issued a GET request.\nSomewhat alarmingly, some of these links were already claimed before I could click on them.\nThen I realized, some programs issue GET requests to render link previews.\nBrowsers might even prefetch the page when you hover over the link with your mouse.\nSo the code might be unintentionally \u201cclaimed\u201d without me ever seeing it. To avoid this pitfall, the link should lead to a page which only claims the code once the user clicks a big button. Login the original tab, not the magic link tab The first time I clicked a magic link on my phone, the in-app browser inside my email app got logged in.\nThe default browser on my phone remained painfully unaware. To avoid this pitfall, the link should do nothing but mark the code as \u201cverified\u201d and instruct the user to return to their original browser tab, which should auto-refresh every few seconds to check whether the code is verified, and if so, log the user in. This also allows users to login on devices that don\u2019t have access to email, by clicking a link on a different device.\nYou can also achieve the same effect by sending a short (6-ish digit) code in the email and asking the user to type the code in the original browser tab.\nBut in my opinion, 6 digits only offers enough entropy for low-stakes use cases like logging into your TV, or for a second factor on top of some other verification method. So that\u2019s where I\u2019m at now.\nWhat do you think?\nAny other pitfalls I\u2019m missing? (/2025/10/02/should-i-switch-from-git-to-jujutsu/) \u2190 Should I Switch From Git to Jujutsu (/about/) About me \u2192   (Email) (mailto:evan@etodd.io)     (Github) (https://github.com/etodd)     (LinkedIn) (https://linkedin.com/in/evantodd)     (YouTube) (https://www.youtube.com/@helvetica.scenario)      \u00a9 2026 Evan Todd.    "
                ],
                "output": "htmltotext.txt",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:45:13.075695+00:00",
                "status": "succeeded"
            }
        ],
        "media": [
            {
                "cmd": [
                    "/usr/local/bin/yt-dlp",
                    "--restrict-filenames",
                    "--trim-filenames",
                    "128",
                    "--write-description",
                    "--write-info-json",
                    "--write-annotations",
                    "--write-thumbnail",
                    "--no-call-home",
                    "--write-sub",
                    "--write-auto-subs",
                    "--convert-subs=srt",
                    "--yes-playlist",
                    "--continue",
                    "--no-abort-on-error",
                    "--ignore-errors",
                    "--geo-bypass",
                    "--add-metadata",
                    "--format=(bv*+ba/b)[filesize<=750m][filesize_approx<=?750m]/(bv*+ba/b)",
                    "--skip-download",
                    "--cache-dir=/data/yt-dlp-cache/",
                    "--cookies=/data/yt-dlp-cache/cookies.txt",
                    "--proxy=socks5://tor-socks-proxy:9150",
                    "--no-playlist",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "2024.10.7",
                "end_ts": "2026-03-26T14:45:23.379839+00:00",
                "index_texts": [],
                "output": "media/",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:45:17.473556+00:00",
                "status": "succeeded"
            }
        ],
        "mercury": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/postlight-parser",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "2.2.3",
                "end_ts": "2026-03-26T14:45:13.032208+00:00",
                "index_texts": null,
                "output": "mercury/",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:45:08.531258+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/readability-extractor",
                    "/tmp/tmph_ras4r5",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2026-03-26T14:44:51.190496+00:00",
                "index_texts": [
                    "Magic Link PitfallsMar 22, 2026Recently I was surprised to discover that there are several bad ways to do magic links.The basic idea is: a user hits \u201clogin\u201d, enters their email address, and receives an email that allows them to login without a password.\nWhat could possibly go wrong?I work in security, so I already knew a few best practices I would need to implement:The link should have a short expirationThe link should only work onceThe link should include a secret code with a sufficient amount of entropy (I went with 64 bits; your paranoia may vary)The database should store a hash of the secret code, not the code itselfHere\u2019s two more that were not immediately obvious to me.Require a clickMy first attempt at a magic link logged the user in immediately as soon as they clicked it.\nThat is, as soon as their browser issued a GET request.\nSomewhat alarmingly, some of these links were already claimed before I could click on them.\nThen I realized, some programs issue GET requests to render link previews.\nBrowsers might even prefetch the page when you hover over the link with your mouse.\nSo the code might be unintentionally \u201cclaimed\u201d without me ever seeing it.To avoid this pitfall, the link should lead to a page which only claims the code once the user clicks a big button.Login the original tab, not the magic link tabThe first time I clicked a magic link on my phone, the in-app browser inside my email app got logged in.\nThe default browser on my phone remained painfully unaware.To avoid this pitfall, the link should do nothing but mark the code as \u201cverified\u201d and instruct the user to return to their original browser tab, which should auto-refresh every few seconds to check whether the code is verified, and if so, log the user in.This also allows users to login on devices that don\u2019t have access to email, by clicking a link on a different device.\nYou can also achieve the same effect by sending a short (6-ish digit) code in the email and asking the user to type the code in the original browser tab.\nBut in my opinion, 6 digits only offers enough entropy for low-stakes use cases like logging into your TV, or for a second factor on top of some other verification method.So that\u2019s where I\u2019m at now.\nWhat do you think?\nAny other pitfalls I\u2019m missing?"
                ],
                "output": "readability/",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:44:47.831475+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://etodd.io/2026/03/22/magic-link-pitfalls/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2026-03-26T14:44:46.778675+00:00",
                "index_texts": null,
                "output": "Magic Link Pitfalls \u00b7 Evan Todd",
                "pwd": "/data/archive/1774536262.601131",
                "schema": "ArchiveResult",
                "start_ts": "2026-03-26T14:44:46.760213+00:00",
                "status": "succeeded"
            }
        ],
        "wget": []
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": "TimeoutExpired: Command '['/usr/bin/curl', '--silent', '--location', '--compressed', '--proxy', 'socks5://tor-socks-proxy:9150', '--head', '--max-time', '60', '--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)', 'https://web.archive.org/save/https://etodd.io/2026/03/22/magic-link-pitfalls/']' timed out after 60 seconds",
        "dom": "output.html",
        "favicon": "favicon.ico",
        "git": null,
        "media": "media/",
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "Magic Link Pitfalls \u00b7 Evan Todd",
        "warc": null,
        "wget": null
    },
    "link_dir": "/data/archive/1774536262.601131",
    "newest_archive_date": "2026-03-26T14:45:23.445059+00:00",
    "num_failures": 1,
    "num_outputs": 8,
    "oldest_archive_date": "2026-03-26T14:44:26.284248+00:00",
    "path": "/2026/03/22/magic-link-pitfalls/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_abid": "snp_01KMN9N0ZY7EA7601101X5KM7G",
    "snapshot_id": "cf7baf7c-804f-4e2b-aa54-a4eafa59d0f0",
    "sources": [
        "/data/sources/1774536262-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1774536262.601131",
    "title": "Magic Link Pitfalls \u00b7 Evan Todd",
    "url": "https://etodd.io/2026/03/22/magic-link-pitfalls/"
}