diff --git a/internal/auth/service.go b/internal/auth/service.go index ad0d3b8..e642a43 100644 --- a/internal/auth/service.go +++ b/internal/auth/service.go @@ -99,7 +99,12 @@ func (s *Service) RequestLogin(ctx context.Context, email string) error { if err != nil { return err } - link := s.baseURL + "/auth/verify?token=" + url.QueryEscape(plaintext) + // The magic link must land on the SPA page (verify.html), not the + // JSON API endpoint /auth/verify. The page reads the token from + // the URL, POSTs it to /auth/verify, stores the JWT and redirects + // to /app.html. Pointing the email at /auth/verify exposes the + // raw JSON body to anyone who clicks the link. + link := s.baseURL + "/verify.html?token=" + url.QueryEscape(plaintext) if err := s.mailer.SendMagicLink(ctx, email, link); err != nil { return fmt.Errorf("send mail: %w", err) }