Files
Vaibhav 23064c0b5b fix(docs): add missing variables to api_settings_steps partial calls (#41364)
PR #41200 introduced template variables ({{ .tab }}, {{ .framework }})
to api_settings_steps.mdx for deep-linking to the Connect dialog.
However, 4 auth docs pages were calling the partial without passing
the required variables prop, causing MDX parsing errors:

- Could not parse expression with acorn: Unexpected token

This resulted in 404 errors on:
- /docs/guides/auth/server-side/creating-a-client
- /docs/guides/auth/quickstarts/nextjs
- /docs/guides/auth/quickstarts/react-native
- /docs/guides/auth/quickstarts/react

Fixes the issue by adding the variables prop to match the pattern
used in other quickstart pages.
2025-12-15 14:27:04 -07:00

290 lines
9.0 KiB
Plaintext

---
title: 'Use Supabase Auth with React'
subtitle: 'Learn how to use Supabase Auth with React.js.'
breadcrumb: 'Auth Quickstarts'
hideToc: true
---
<StepHikeCompact>
<StepHikeCompact.Step step={1}>
<StepHikeCompact.Details title="Create a new Supabase project">
[Launch a new project](/dashboard) in the Supabase Dashboard.
Your new database has a table for storing your users. You can see that this table is currently empty by running some SQL in the [SQL Editor](/dashboard/project/_/sql).
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```sql name=SQL_EDITOR
select * from auth.users;
````
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={2}>
<StepHikeCompact.Details title="Create a React app">
Create a React app using a [Vite](https://vitejs.dev/guide/) template.
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```bash name=Terminal
npm create vite@latest my-app -- --template react
```
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={3}>
<StepHikeCompact.Details title="Install the Supabase client library">
Navigate to the React app and install the Supabase libraries.
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```bash name=Terminal
cd my-app && npm install @supabase/supabase-js
```
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={4}>
<StepHikeCompact.Details title="Declare Supabase Environment Variables">
Rename `.env.example` to `.env.local` and populate with your Supabase connection variables:
<ProjectConfigVariables variable="url" />
<ProjectConfigVariables variable="publishable" />
<ProjectConfigVariables variable="anon" />
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```text name=.env.local
VITE_SUPABASE_URL=your-project-url
VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY=sb_publishable_... or anon key
```
<$Partial path="api_settings_steps.mdx" variables={{ "framework": "react", "tab": "frameworks" }} />
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={5}>
<StepHikeCompact.Details title="Set up your login component">
<$Partial path="uiLibCta.mdx" />
In `App.jsx`, create a Supabase client using your Project URL and key.
You can configure the Auth component to display whenever there is no session inside `supabase.auth.getSession()`
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```jsx name=src/App.jsx
import "./index.css";
import { useState, useEffect } from "react";
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY);
export default function App() {
const [loading, setLoading] = useState(false);
const [email, setEmail] = useState("");
const [session, setSession] = useState(null);
// Check URL params on initial render
const params = new URLSearchParams(window.location.search);
const hasTokenHash = params.get("token_hash");
const [verifying, setVerifying] = useState(!!hasTokenHash);
const [authError, setAuthError] = useState(null);
const [authSuccess, setAuthSuccess] = useState(false);
useEffect(() => {
// Check if we have token_hash in URL (magic link callback)
const params = new URLSearchParams(window.location.search);
const token_hash = params.get("token_hash");
const type = params.get("type");
if (token_hash) {
// Verify the OTP token
supabase.auth.verifyOtp({
token_hash,
type: type || "email",
}).then(({ error }) => {
if (error) {
setAuthError(error.message);
} else {
setAuthSuccess(true);
// Clear URL params
window.history.replaceState({}, document.title, "/");
}
setVerifying(false);
});
}
// Check for existing session
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
});
// Listen for auth changes
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});
return () => subscription.unsubscribe();
}, []);
const handleLogin = async (event) => {
event.preventDefault();
setLoading(true);
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
emailRedirectTo: window.location.origin,
}
});
if (error) {
alert(error.error_description || error.message);
} else {
alert("Check your email for the login link!");
}
setLoading(false);
};
const handleLogout = async () => {
await supabase.auth.signOut();
setSession(null);
};
// Show verification state
if (verifying) {
return (
<div>
<h1>Authentication</h1>
<p>Confirming your magic link...</p>
<p>Loading...</p>
</div>
);
}
// Show auth error
if (authError) {
return (
<div>
<h1>Authentication</h1>
<p>✗ Authentication failed</p>
<p>{authError}</p>
<button
onClick={() => {
setAuthError(null);
window.history.replaceState({}, document.title, "/");
}}
>
Return to login
</button>
</div>
);
}
// Show auth success (briefly before session loads)
if (authSuccess && !session) {
return (
<div>
<h1>Authentication</h1>
<p>✓ Authentication successful!</p>
<p>Loading your account...</p>
</div>
);
}
// If user is logged in, show welcome screen
if (session) {
return (
<div>
<h1>Welcome!</h1>
<p>You are logged in as: {session.user.email}</p>
<button onClick={handleLogout}>
Sign Out
</button>
</div>
);
}
// Show login form
return (
<div>
<h1>Supabase + React</h1>
<p>Sign in via magic link with your email below</p>
<form onSubmit={handleLogin}>
<input
type="email"
placeholder="Your email"
value={email}
required={true}
onChange={(e) => setEmail(e.target.value)}
/>
<button disabled={loading}>
{loading ? <span>Loading</span> : <span>Send magic link</span>}
</button>
</form>
</div>
);
}
```
</StepHikeCompact.Code>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={6}>
<StepHikeCompact.Details title="Customize email template">
Before proceeding, change the email template to support support a server-side authentication flow that sends a token hash:
- Go to the [Auth templates](/dashboard/project/_/auth/templates) page in your dashboard.
- Select the Confirm sign up template.
- Change `{{ .ConfirmationURL }}` to `{{ .SiteURL }}?token_hash={{ .TokenHash }}&type=email`.
- Change your [Site URL](/dashboard/project/_/auth/url-configuration) to `https://localhost:5173`
</StepHikeCompact.Details>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={7}>
<StepHikeCompact.Details title="Start the app">
Start the app, go to http://localhost:5173 in a browser, and open the browser console and you should be able to register and log in.
</StepHikeCompact.Details>
<StepHikeCompact.Code>
```bash name=Terminal
npm run dev
```
</StepHikeCompact.Code>
</StepHikeCompact.Step>
</StepHikeCompact>