C.W.K.
Stream
Lesson 03 of 05 · published

OAuth, Magic Links, and Multi-User Onboarding

~15 min · oauth, magic-links, allowlist

Level 0Greenhorn
0 XP0/53 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Once a second human enters your app, you've crossed into identity-management territory. The patterns get more specialized.

The three common patterns

PatternBest forFriction
OAuth (Sign in with Google/GitHub/Apple)Apps where users already have a stable identity at one of those providersLowest — 1 click; vendor lock-in to the IdP
Magic links (email)Solo dev who wants per-user accounts without passwordsLow — type email, click link; depends on email reliability
Passkey-only signupTech-comfortable user base, modern devicesMedium — 'create a passkey' is still novel UX

The magic link pattern (cheapest per-user solution)

Pros: zero passwords, per-user accountability, recovery is just "send another magic link". Cons: depends entirely on email security — the user's email password becomes a transitive credential for your app.

Code

Magic link issuance·python
# 1. User enters email
# 2. Server generates a one-time token
token = secrets.token_urlsafe(32)
db.execute(
    "INSERT INTO magic_links(email, token, expires_at) VALUES (?,?,?)",
    (email, token, now() + 900)  # 15 min
)
# 3. Email a link: https://app/auth/magic?token=<token>
# 4. User clicks; server validates token, expires it, issues session cookie
OAuth with authlib + FastAPI·python
from authlib.integrations.starlette_client import OAuth

oauth = OAuth()
oauth.register(
    name="google",
    client_id=os.environ["GOOGLE_CLIENT_ID"],
    client_secret=os.environ["GOOGLE_CLIENT_SECRET"],  # from keychain, not .env
    server_metadata_url="https://accounts.google.com/.well-known/openid-configuration",
    client_kwargs={"scope": "openid email profile"},
)

@app.get("/auth/google")
async def google_login(request: Request):
    return await oauth.google.authorize_redirect(request, "https://app/auth/google/callback")

@app.get("/auth/google/callback")
async def google_callback(request: Request):
    token = await oauth.google.authorize_access_token(request)
    userinfo = token["userinfo"]
    user = upsert_user(email=userinfo["email"], name=userinfo["name"])
    issue_session_cookie(user)
    return RedirectResponse("/")
Allowlist — default closed·python
ALLOWED_EMAILS = {"me@example.com", "partner@example.com", "friend@example.com"}

def upsert_user(email: str, name: str):
    if email not in ALLOWED_EMAILS:
        raise HTTPException(403, "This app is not open for registration.")
    # ...

External links

Exercise

Pick: would your next multi-user app use OAuth, magic links, or passkeys? Write the answer in one sentence per option, justifying based on YOUR users (tech-savvy? have Google accounts? on phones or laptops?). The exercise is matching auth choice to user reality, not picking the 'most secure' on paper.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.