Skip to content

Commit f3c1b4a

Browse files
tomusdrwclaude
andauthored
feat: magic-link-first auth flow (#77)
* docs: add design spec for magic-link-first auth flow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add implementation plan for magic-link-first auth flow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add AuthFlow tests for magic-link-first redesign Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: redesign AuthFlow to magic-link-first Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add AuthCallback tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add AuthCallback component for magic link redirects Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add PasswordUpdate tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add PasswordUpdate component for settings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add password management to Settings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: export AuthCallback and PasswordUpdate from supabase Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: update AuthFlow stories for magic-link-first design Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: update demo app with magic link auth callback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove unused vi import from AuthFlow tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: AuthCallback race condition + update docs - Fix race condition where AuthCallback misses SIGNED_IN if SupabaseProvider already processed the magic link tokens - Stabilize callback refs to avoid effect re-runs - Update Supabase.mdx with magic link auth flow docs - Remove boilerplate file comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Supabase config with custom email templates Initialize supabase/config.toml and add branded HTML email templates for magic link sign-in and email confirmation. Update Supabase.mdx with deployment instructions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: align config.toml with production Supabase settings Restore site_url, redirect_urls, email confirmations, MFA TOTP, OTP length, and email frequency to match the hosted project. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add supabase .gitignore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review comments - Fix AuthCallback timeout not cancelled after SIGNED_IN event - Use document.baseURI for demo callback URLs (fixes basename hosting) - Disable screen-switch buttons during auth submission - Harden pre-fill test with password screen assertion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: update plan with portable paths and reviewed code fixes - Replace hardcoded absolute paths with repo-relative commands - Update AuthCallback code with settled flag and race condition fix - Update AuthFlow code with disabled buttons during submit - Update test with password assertion for pre-fill check - Update demo code with document.baseURI for basename support - Remove unused vi import from test code Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e5cf075 commit f3c1b4a

18 files changed

Lines changed: 2042 additions & 97 deletions

demo/src/App.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { initializeTheme } from "../../lib/components/DarkMode";
66
import { SupabaseProvider } from "../../lib/supabase/SupabaseProvider";
77
import { UserMenu } from "../../lib/supabase/UserMenu";
88
import { AuthFlow } from "../../lib/supabase/AuthFlow";
9+
import { AuthCallback } from "../../lib/supabase/AuthCallback";
910
import { Settings } from "../../lib/supabase/Settings";
1011
import { SubscriptionStatus } from "../../lib/supabase/SubscriptionStatus";
1112
import { PricingCard } from "../../lib/supabase/PricingCard";
@@ -22,7 +23,7 @@ const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY || "";
2223

2324
initializeTheme();
2425

25-
type Page = "home" | "login" | "settings" | "pricing" | "gated";
26+
type Page = "home" | "login" | "settings" | "pricing" | "gated" | "auth-callback";
2627

2728
export function App() {
2829
if (!SUPABASE_URL || !SUPABASE_ANON_KEY) {
@@ -46,8 +47,14 @@ export function App() {
4647
);
4748
}
4849

50+
const AUTH_CALLBACK_PATH = new URL("auth/callback", document.baseURI).pathname;
51+
const HOME_PATH = new URL(".", document.baseURI).pathname;
52+
4953
function DemoApp() {
50-
const [page, setPage] = useState<Page>("home");
54+
const [page, setPage] = useState<Page>(() => {
55+
if (window.location.pathname === AUTH_CALLBACK_PATH) return "auth-callback";
56+
return "home";
57+
});
5158

5259
return (
5360
<div className="flex min-h-screen flex-col">
@@ -77,6 +84,15 @@ function PageContent({ page, setPage }: { page: Page; setPage: (p: Page) => void
7784
return <PricingPage />;
7885
case "gated":
7986
return <GatedFeaturePage />;
87+
case "auth-callback":
88+
return (
89+
<AuthCallback
90+
onSuccess={() => {
91+
window.history.replaceState({}, "", HOME_PATH);
92+
setPage("home");
93+
}}
94+
/>
95+
);
8096
default:
8197
return <HomePage setPage={setPage} />;
8298
}
@@ -126,7 +142,7 @@ function HomePage({ setPage }: { setPage: (p: Page) => void }) {
126142
function LoginPage({ onSuccess }: { onSuccess: () => void }) {
127143
return (
128144
<div className="mx-auto max-w-sm pt-8">
129-
<AuthFlow onSuccess={onSuccess} />
145+
<AuthFlow onSuccess={onSuccess} redirectTo={new URL("auth/callback", document.baseURI).toString()} />
130146
</div>
131147
);
132148
}

0 commit comments

Comments
 (0)