Use Supabase Auth with React
Learn how to use Supabase Auth with React.js.
Create a new Supabase project
Launch a new project 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.
SQL_EDITOR
1select * from auth.users;Create a React app
Create a React app using a Vite template.
Terminal
1npm create vite@latest my-app -- --template reactInstall the Supabase client library
Navigate to the React app and install the Supabase libraries.
Terminal
1cd my-app && npm install @supabase/supabase-jsDeclare Supabase Environment Variables
Rename .env.example to .env.local and populate with your Supabase connection variables:
Project URL
Publishable key
Anon key
.env.local
1VITE_SUPABASE_URL=your-project-url2VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY=sb_publishable_... or anon keyYou can also get the Project URL and key from the project's Connect dialog.
Changes to API keys
Supabase is changing the way keys work to improve project security and developer experience. You can read the full announcement, but in the transition period, you can use both the current anon and service_role keys and the new publishable key with the form sb_publishable_xxx which will replace the older keys.
In most cases, you can get the correct key from the Project's Connect dialog, but if you want a specific key, you can find all keys in the API Keys section of a Project's Settings page:
- For legacy keys, copy the
anonkey for client-side operations and theservice_rolekey for server-side operations from the Legacy API Keys tab. - For new keys, open the API Keys tab, if you don't have a publishable key already, click Create new API Keys, and copy the value from the Publishable key section.
Read the API keys docs for a full explanation of all key types and their uses.
Set up your login component
Explore drop-in UI components for your Supabase app.
UI components built on shadcn/ui that connect to Supabase via a single command.
Explore ComponentsIn 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()
src/App.jsx
1import "./index.css";2import { useState, useEffect } from "react";3import { createClient } from "@supabase/supabase-js";45const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY);67export default function App() {8 const [loading, setLoading] = useState(false);9 const [email, setEmail] = useState("");10 const [session, setSession] = useState(null);1112 // Check URL params on initial render13 const params = new URLSearchParams(window.location.search);14 const hasTokenHash = params.get("token_hash");1516 const [verifying, setVerifying] = useState(!!hasTokenHash);17 const [authError, setAuthError] = useState(null);18 const [authSuccess, setAuthSuccess] = useState(false);1920 useEffect(() => {21 // Check if we have token_hash in URL (magic link callback)22 const params = new URLSearchParams(window.location.search);23 const token_hash = params.get("token_hash");24 const type = params.get("type");2526 if (token_hash) {27 // Verify the OTP token28 supabase.auth.verifyOtp({29 token_hash,30 type: type || "email",31 }).then(({ error }) => {32 if (error) {33 setAuthError(error.message);34 } else {35 setAuthSuccess(true);36 // Clear URL params37 window.history.replaceState({}, document.title, "/");38 }39 setVerifying(false);40 });41 }4243 // Check for existing session44 supabase.auth.getSession().then(({ data: { session } }) => {45 setSession(session);46 });4748 // Listen for auth changes49 const {50 data: { subscription },51 } = supabase.auth.onAuthStateChange((_event, session) => {52 setSession(session);53 });5455 return () => subscription.unsubscribe();56 }, []);5758 const handleLogin = async (event) => {59 event.preventDefault();60 setLoading(true);61 const { error } = await supabase.auth.signInWithOtp({62 email,63 options: {64 emailRedirectTo: window.location.origin,65 }66 });67 if (error) {68 alert(error.error_description || error.message);69 } else {70 alert("Check your email for the login link!");71 }72 setLoading(false);73 };7475 const handleLogout = async () => {76 await supabase.auth.signOut();77 setSession(null);78 };7980 // Show verification state81 if (verifying) {82 return (83 <div>84 <h1>Authentication</h1>85 <p>Confirming your magic link...</p>86 <p>Loading...</p>87 </div>88 );89 }9091 // Show auth error92 if (authError) {93 return (94 <div>95 <h1>Authentication</h1>96 <p>ā Authentication failed</p>97 <p>{authError}</p>98 <button99 onClick={() => {100 setAuthError(null);101 window.history.replaceState({}, document.title, "/");102 }}103 >104 Return to login105 </button>106 </div>107 );108 }109110 // Show auth success (briefly before session loads)111 if (authSuccess && !session) {112 return (113 <div>114 <h1>Authentication</h1>115 <p>ā Authentication successful!</p>116 <p>Loading your account...</p>117 </div>118 );119 }120121 // If user is logged in, show welcome screen122 if (session) {123 return (124 <div>125 <h1>Welcome!</h1>126 <p>You are logged in as: {session.user.email}</p>127 <button onClick={handleLogout}>128 Sign Out129 </button>130 </div>131 );132 }133134 // Show login form135 return (136 <div>137 <h1>Supabase + React</h1>138 <p>Sign in via magic link with your email below</p>139 <form onSubmit={handleLogin}>140 <input141 type="email"142 placeholder="Your email"143 value={email}144 required={true}145 onChange={(e) => setEmail(e.target.value)}146 />147 <button disabled={loading}>148 {loading ? <span>Loading</span> : <span>Send magic link</span>}149 </button>150 </form>151 </div>152 );153}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 page in your dashboard.
- Select the Confirm sign up template.
- Change
{{ .ConfirmationURL }}to{{ .SiteURL }}?token_hash={{ .TokenHash }}&type=email. - Change your Site URL to
https://localhost:5173
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.
Terminal
1npm run dev