ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Supabase][Auth] auth.admin.generateLink로 custom mailer를 붙일 때 action_link만 저장하면 안 되고 어떤 필드를 같이 남겨야 하나
    카테고리 없음 2026. 7. 13. 20:15

    IT 리서치 노트

    [Supabase][Auth] auth.admin.generateLink로 custom mailer를 붙일 때 action_link만 저장하면 안 되고 어떤 필드를 같이 남겨야 하나

    Supabase 초대 흐름에서 auth.admin.generateLink()를 써 custom mailer를 붙이면 많은 팀이 action_link만 메일 본문에 넣고 끝낸다. 하지만 2026년 7월 13일 기준 Supabase 공식 문서를 다시 보면 generateLink는 custom email provider용 링크와 OTP를 만드는 경로이고, 이메일 템플릿과 redirect 가이드는 수락 뒤 UX를 바꾸는 변수들을 별도로 설명한다. 이 글은 custom mailer 운영에서 action_link 하나만 저장하면 왜 부족한지, 어떤 필드를 같이 남겨야 재발송과 수락 실패를 덜 헤매는지 정리한 것이다.

    1. 개요

    결론부터 말하면 custom mailer에서 action_link만 보관하면 메일 클릭 경로만 재현되고, 수락 타입과 첫 화면 도착지, 만료 재현 기준은 남지 않는다. 최소한 redirect_to, verification type, 토큰 검증용 메모를 같은 trace에 남겨야 이후의 invalid link, expired link, wrong redirect를 따로 구분해 볼 수 있다.

    이미 generateLink와 inviteUserByEmail 분기 글이 메일 발송 주체를 갈랐다면, 이번 글은 generateLink를 택한 뒤 custom mailer 운영에서 무엇을 저장해야 하는지로 더 좁혀 간다.

    2. 어디서 실제로 막히는가

    현장에서 주로 꼬이는 지점은 네 가지다. 첫째, 메일 본문에 실린 action_link만 저장해 두고 실제 어떤 redirect가 붙었는지 남기지 않는다. 둘째, invite와 recovery와 magiclink를 같은 템플릿 helper로 감싸 verification type을 로그에서 잃어버린다. 셋째, 수락 실패가 나면 메일 발송 실패와 토큰 만료를 같은 장애로 본다. 넷째, custom mailer 운영인데도 만료 재전송과 첫 비밀번호 화면을 기본 템플릿 흐름처럼 생각한다.

    Supabase의 generateLink 문서는 링크와 OTP를 custom email provider로 보내는 경로라고 설명하고, 이메일 템플릿 문서는 ConfirmationURL과 TokenHash, RedirectTo가 후속 UX를 바꾼다고 설명한다. redirect URL 가이드는 허용 목록 밖 경로로는 유저를 보낼 수 없다고 적는다. 2026년 4월 8일 수정된 troubleshooting 문서는 invalid or expired 계열 실패가 모두 토큰 유효성 축으로 모일 수 있다고 정리한다. 이 네 문서를 같이 놓으면 메일 본문 링크 하나만 저장하는 구현이 왜 운영에 약한지 분명해진다.

    • 증상: 메일은 갔는데 수락 화면에서 invalid or expired가 반복된다.
    • 실패: action_link만 남기고 redirect와 type을 잃어버린다.
    • 막힘: invite와 recovery를 같은 verify 경로로 보내 타입이 꼬인다.
    • 누락: 발송 성공 로그와 검증 실패 로그를 분리하지 않는다.
    상황 먼저 볼 것 판단 기준
    메일은 발송됐는데 첫 화면이 다르다 redirect_to 허용 URL과 실제 링크 도착지를 비교한다
    verifyOtp가 틀린 타입처럼 보인다 verification type invite인지 recovery인지부터 자른다
    링크 만료와 재발송이 엉킨다 토큰 검증용 메모와 created_at 같은 링크 재사용인지 새 링크인지 본다

    3. 실무에서 적용하는 순서

    실무에서는 다섯 단계로 정리하는 편이 가장 덜 꼬인다. 먼저 custom mailer로 보낸 링크의 verification type을 명시적으로 남긴다. 두 번째로 메일 본문에 들어간 action_link와 로그용 redirect_to를 같이 저장한다. 세 번째로 토큰 검증 실패를 재현할 수 있도록 token debug key, invite created time, resend count를 별도 메모에 남긴다. 네 번째로 메일 발송 성공 이벤트와 verify 실패 이벤트를 다른 로그 이름으로 분리한다. 마지막으로 만료 재발송이 들어오면 새 링크 발급 시점과 이전 링크 클릭 시점을 비교한다.

    1. verification type을 먼저 고정한다.
    2. action_link와 redirect_to를 같은 trace에 남긴다.
    3. 토큰 검증용 메모와 생성 시각을 별도 저장한다.
    4. 발송 성공 로그와 verify 실패 로그를 분리한다.
    5. 재발송 시 새 링크와 이전 링크를 구분한다.

    이때 운영 로그에는 mail_owner, verification_type, redirect_to, invite_created_at, resend_count 정도를 남겨 두는 편이 실용적이다. 이 필드가 있으면 메일 채널 문제와 토큰 유효성 문제를 빨리 분리할 수 있고, custom mailer를 붙인 뒤에도 기본 템플릿 흐름과 어디서 달라졌는지 추적하기 쉽다.

    운영 메모 예시
    {
      "mail_owner": "app_mailer",
      "verification_type": "invite",
      "redirect_to": "/invite/accept",
      "invite_created_at": "2026-07-13T12:42:00+09:00",
      "resend_count": 0
    }

    이렇게 쪼개 두면 메일은 정상인데 token이 만료된 경우와, token은 아직 유효한데 redirect가 틀린 경우를 따로 재현할 수 있다. custom mailer를 붙인 generateLink 운영은 링크를 보내는 것보다 어떤 맥락을 같이 저장하느냐가 더 중요하다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 자료는 generateLink() 문서의 정의다. Supabase는 이 API를 custom email provider로 보낼 링크와 OTP를 생성하는 경로라고 직접 설명한다. 즉 이 시점부터 메일 본문 구성과 재발송 추적을 애플리케이션이 더 많이 책임진다.

    Supabase generateLink 문서는 custom email provider로 보낼 링크와 OTP를 생성하는 경로라고 설명한다.
    Supabase generateLink 문서는 custom email provider로 보낼 링크와 OTP를 생성하는 경로라고 설명한다.

    이 정의를 기준으로 보면 action_link만 메일에 꽂는 구현은 절반짜리다. 운영에서는 어떤 redirect와 어떤 verification type으로 보냈는지, 재전송 시 어떤 링크를 무효화할지 같이 남겨야 나중에 수락 실패를 자를 수 있다.

    두 번째 자료는 이메일 템플릿 가이드다. 여기서는 ConfirmationURL, TokenHash, RedirectTo 같은 변수가 링크 이후 UX를 갈라 놓는다는 점을 확인한다. custom mailer를 붙이면 이 변수들을 어떤 형식으로 메일 본문과 수락 화면에 전달할지 앱이 직접 결정해야 한다.

    이메일 템플릿 가이드는 ConfirmationURL, TokenHash, RedirectTo가 수락 뒤 UX에 직접 닿는다고 보여 준다.
    이메일 템플릿 가이드는 ConfirmationURL, TokenHash, RedirectTo가 수락 뒤 UX에 직접 닿는다고 보여 준다.

    따라서 링크 하나만 보관하면 비밀번호 설정 화면과 재검증 화면이 뒤엉키기 쉽다. 메일 문면과 첫 화면을 따로 제어하려면 action_link와 함께 redirect와 verification type 맥락을 남겨야 한다.

    세 번째 자료는 2026년 4월 8일 수정된 Supabase troubleshooting 문서다. 이 문서는 otp_expired, invalid link, 403 verification 실패가 모두 토큰 유효성 문제로 모일 수 있다고 정리한다. 즉 custom mailer 운영에서는 메일 발송 성공 로그와 토큰 검증 실패 로그를 분리해 남겨야 한다.

    Supabase troubleshooting 문서는 otp_expired, invalid link, 403 verification 실패를 같은 토큰 유효성 축에서 읽으라고 안내한다.
    Supabase troubleshooting 문서는 otp_expired, invalid link, 403 verification 실패를 같은 토큰 유효성 축에서 읽으라고 안내한다.

    이 축이 없으면 메일이 안 간 것인지, 링크는 갔지만 만료된 것인지, redirect가 틀린 것인지 운영 기록에서 분간이 안 된다. action_link만 저장한 구현이 왜 부족한지 가장 분명하게 드러나는 대목이다.

    실무에서는 어떤 필드를 남길지 먼저 표로 고정하는 편이 가장 빠르다. action_link는 클릭 경로를 재현하는 키고, redirect와 verification type은 첫 화면 라우팅을 재현하는 키다. email_otp나 hashed token 계열 값은 수동 검증이나 fallback 화면을 붙일 때 판단 재료가 된다.

    generateLink custom mailer 운영에서 action_link 외에 같이 남겨야 하는 필드 체크리스트다.
    generateLink custom mailer 운영에서 action_link 외에 같이 남겨야 하는 필드 체크리스트다.

    이 표를 기준으로 로그를 남기면 이미 발행한 mail-owner 기준 분기 글, token_hash 수락 순서 글과도 자연스럽게 이어진다. 이번 글은 custom mailer 쪽 저장 기준을 더 좁힌 후속편이다.

    마지막 자료는 안전한 서버 로그 예시다. 핵심은 메일 본문에 넣은 값과 운영 추적용 값을 섞지 않고 같은 trace에 남기는 것이다. custom mailer에서 필요한 필드는 메일 body 하나보다 운영 메모를 분리한 쪽이 훨씬 안전하다.

    generateLink custom mailer에서는 발송 payload와 운영 추적 필드를 같은 trace로 남기는 편이 안전하다.
    generateLink custom mailer에서는 발송 payload와 운영 추적 필드를 같은 trace로 남기는 편이 안전하다.

    이 구조를 잡아 두면 redirectTo 점검 글, 만료 뒤 재발송 글과도 바로 연결된다. 메일 발송 성공과 링크 수락 성공을 같은 이벤트로 뭉개지 않는 것이 핵심이다.

    5. 주의사항과 리스크

    첫 번째 리스크는 action_link만 남기고 verification type을 잃어버리는 것이다. 두 번째 리스크는 redirect 허용 목록을 업데이트하지 않은 채 custom mailer 쪽 링크만 바꾸는 것이다. 세 번째 리스크는 invalid or expired를 전부 메일 발송 문제로 해석해 verify 단계 로그를 놓치는 것이다.

    운영 전에 확인할 것은 세 가지다. 실제 메일 본문에 어떤 링크가 들어갔는지, 그 링크가 어떤 redirect를 품는지, verify 실패 시 어떤 type으로 재현되는지다. 이 셋을 안 남기면 수락 장애가 생길 때 메일러와 앱 라우팅과 auth 검증을 매번 동시에 뒤져야 한다.

    • action_link는 클릭 경로 재현용이고, redirect와 type은 수락 UX 재현용이다.
    • 메일 발송 성공과 verify 실패를 같은 이벤트로 합치지 않는다.
    • 재발송 시각과 이전 링크 클릭 시각을 분리해 본다.

    6. 결론

    Supabase generateLink로 custom mailer를 붙일 때는 action_link만 저장해서는 부족하다. redirect_to, verification type, 토큰 검증용 메모까지 같은 trace에 남겨야 invalid link, expired link, wrong redirect를 실제로 분리해 낼 수 있다. custom mailer 운영은 메일 본문보다 운영 기록 설계가 더 중요하다.

    만약 저장 필드까지는 정리했는데도 invite 링크가 사용자의 실제 클릭 전에 먼저 만료된다면, 다음 단계는 mail scanner 선열림과 1회용 만료·재발송 분기 글로 이어서 보는 편이 빠르다. 오늘 글이 저장 기준이라면 저 글은 클릭 순서와 재발송 UX 기준을 다룬다.

    • action_link만 저장하지 말고 redirect와 type을 같이 남긴다.
    • 토큰 검증 실패는 메일 발송 실패와 별도 로그로 본다.
    • 재발송과 첫 수락 화면을 같은 표에서 관리한다.

    7. 참고 링크

    1. https://supabase.com/docs/reference/javascript/auth-admin-generatelink
    2. https://supabase.com/docs/guides/auth/auth-email-templates
    3. https://supabase.com/docs/guides/auth/redirect-urls
    4. https://supabase.com/docs/guides/troubleshooting/otp-verification-failures-token-has-expired-or-otp_expired-errors-5ee4d0
Designed by Tistory.