Skip to content
Auth

在 React 中使用 Supabase 认证

Learn how to use Supabase Auth with React.js.

快速入门 #

🌐 Quickstart

1
Create a new Supabase project

在 Supabase 仪表板中启动一个新项目。

你的新数据库有一个用于存储用户的表。你可以通过在 SQL 编辑器 中运行一些 SQL 来查看这个表当前是空的。

SQL_EDITOR
select * from auth.users;
2
Create a React app

使用 Vite 模板创建一个 React 应用。

Terminal
npm create vite@latest my-app -- --template react
3
Install the Supabase client library

进入 React 应用并安装 Supabase 库。

Terminal
cd my-app && npm install @supabase/supabase-js
4
Declare Supabase Environment Variables

将 .env.example 重命名为 .env.local 并填写你的 Supabase 连接变量:

获取 API 详情 #

🌐 Get API details

要与数据库表中的数据进行交互,你可以使用封装了自动生成的数据 API 端点的客户端库,并使用来自项目 Connect 对话框的项目 URL 和密钥进行认证。

🌐 To interact with data in database tables, you use the client libraries that wrap the auto-generated Data API endpoints, authenticating using the Project URL and key from the project Connect dialog.

.env.local
VITE_SUPABASE_URL=your-project-url
VITE_SUPABASE_PUBLISHABLE_KEY=your-publishable-key-or-anon-key
View source
5
Set up your sign-in component

在 App.jsx 中,使用你的项目 URL 和密钥创建一个 Supabase 客户端。

这段代码在 App.jsx 中使用 getClaims 方法来验证本地 JWT,然后再显示已登录的用户。

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_KEY
)
export default function App() {
const [loading, setLoading] = useState(false)
const [email, setEmail] = useState('')
const [claims, setClaims] = 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 using getClaims
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
// Listen for auth changes
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(() => {
supabase.auth.getClaims().then(({ data: { claims } }) => {
setClaims(claims)
})
})
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()
setClaims(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 claims load)
if (authSuccess && !claims) {
return (
<div>
<h1>Authentication</h1>
<p>✓ Authentication successful!</p>
<p>Loading your account...</p>
</div>
)
}
// If user is logged in, show welcome screen
if (claims) {
return (
<div>
<h1>Welcome!</h1>
<p>You are logged in as: {claims.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>
)
}
View source
6
Customize email template

在继续之前,先修改邮件模板以支持服务器端身份验证流程,该流程会发送一个令牌哈希:

  • 在你的仪表板上打开 Auth 模板 页面。
  • 选择确认注册模板。
  • 把 {{ .ConfirmationURL }} 改成 {{ .SiteURL }}?token_hash={{ .TokenHash }}&type=email。
  • 把你的网站 URL改成 https://localhost:5173
7
Terminal
npm run dev