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

OAuth, Magic Link, 다중 사용자 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

두 번째 사람이 앱에 들어오면 identity-management 영역 넘은 거. 패턴이 더 specialized.

흔한 세 패턴

패턴적합마찰
OAuth (Google/GitHub/Apple 로 sign in)그 provider 중 하나에 stable identity 이미 있는 사용자가장 낮음 — 1 클릭; IdP 에 vendor lock-in
Magic link (이메일)비밀번호 없이 per-user 계정 원하는 솔로 개발자낮음 — 이메일 타이핑, 링크 클릭; 이메일 신뢰성에 의존
Passkey-only signup기술 편한 사용자 베이스, 모던 디바이스중간 — 'passkey 만들기' 가 여전히 새로운 UX

Magic link 패턴 (가장 싼 per-user 솔루션)

장점: 비밀번호 0, per-user 책임, 복구는 그냥 "magic link 또 보내". 단점: 이메일 보안에 완전 의존 — 사용자 이메일 비밀번호가 네 앱한테 transitive credential 됨.

Code

Magic link 발급·python
# 1. 사용자 이메일 입력
# 2. 서버가 one-time 토큰 생성
token = secrets.token_urlsafe(32)
db.execute(
    "INSERT INTO magic_links(email, token, expires_at) VALUES (?,?,?)",
    (email, token, now() + 900)  # 15분
)
# 3. 링크 이메일: https://app/auth/magic?token=<token>
# 4. 사용자 클릭; 서버 토큰 검증, expire, session 쿠키 발급
authlib + FastAPI 로 OAuth·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"],  # keychain 에서, .env X
    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 — 기본 닫힘·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, "이 앱은 등록 안 받습니다.")
    # ...

External links

Exercise

선택: 다음 다중 사용자 앱이 OAuth, magic link, passkey 중 어느 걸 쓸까? 옵션마다 한 문장으로 답 적어 — *네 사용자* 기준 (기술 능숙? Google 계정 있어? 폰 아니면 노트북?). 운동은 종이 위 '가장 안전' 이 아니라 사용자 현실에 auth 선택 매칭.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.