
字节笔记本
2026年10月6日 · 约 13 分钟读完
Supabase 对接 GitHub 登录:本地全流程
想让网站支持 GitHub 账号一键登录,又不想自己维护一套账号密码体系,Supabase 内置的 OAuth 能力是目前最省事的路径之一:开发者只需要注册应用、填几项配置、写少量代码,跳转授权、令牌交换与会话管理都由 Supabase 托底。本文以 Next.js 为例,在 localhost:3000 本地开发环境中完整走一遍 GitHub OAuth 登录的接入流程,从两边的控制台配置讲到登录组件与回调接口的实现,最后汇总几个最容易踩的坑。
整体流程:四方协作的一次登录

整条链路涉及浏览器、Next.js 应用、GitHub 与 Supabase 四方。用户在页面上点击登录按钮后,由 supabase-js 的 signInWithOAuth 方法引导跳转到 GitHub 授权页;用户确认授权,GitHub 携带一次性授权码回调 Next.js 的 API 路由;回调接口再通过 exchangeCodeForSession 把授权码换成 Supabase 会话,登录态就此建立。之后前端通过 onAuthStateChange 监听状态变化,即可在页面上展示用户邮箱与头像。
第一步:注册 GitHub OAuth 应用
- 登录 GitHub,进入 Developer Settings 的 OAuth Apps 页面(github.com/settings/developers)。
- 点击 New OAuth App,填写应用信息:Application name 取一个可辨识的名字,例如 My Supabase App;Homepage URL 填 http://localhost:3000;Authorization callback URL 填 http://localhost:3000/api/auth/callback。
- 点击 Register application 完成注册。
注册完成后会拿到 Client ID 与 Client Secret。Secret 只在创建时完整显示一次,务必先保存,后面配置 Supabase 时两处都要用。
第二步:配置 Supabase 项目
登录 supabase.com 创建一个新项目,在项目仪表盘的 API 页面复制 SUPABASE_URL 与 SUPABASE_ANON_KEY。接着启用 GitHub 提供方:点击左侧 Authentication 图标,进入 Providers 配置,找到 GitHub 展开后启用,填入上一步的 Client ID 与 Client Secret,点击 Save 保存。到这里,两边的门牌就对上了。
第三步:创建项目并安装依赖
npx create-next-app@latest my-supabase-app
cd my-supabase-app
npm install @supabase/supabase-js
npm install --save-dev dotenv第四步:写入环境变量
在项目根目录创建 .env.local,放入三个键:
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key注意这个文件不要提交到版本控制系统。前两个带 NEXT_PUBLIC_ 前缀的键会暴露给浏览器,属于公开信息;服务角色密钥则只能留在服务端,后面细说。
第五步:封装 Supabase 客户端
创建 lib/supabaseClient.js,把初始化逻辑收敛到一个文件里:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);第六步:登录组件与首页会话
创建 components/Auth.js,提供登录与登出两个按钮:
import { supabase } from '../lib/supabaseClient';
const Auth = () => {
const signInWithGithub = async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: 'http://localhost:3000/api/auth/callback',
},
});
if (error) console.error('Error: ', error.message);
};
const signOut = async () => {
const { error } = await supabase.auth.signOut();
if (error) console.error('Error: ', error.message);
};
return (
<div>
<button onClick={signInWithGithub}>使用GitHub登录</button>
<button onClick={signOut}>登出</button>
</div>
);
};
export default Auth;在 pages/index.js 中挂载这个组件,并用 onAuthStateChange 订阅会话变化:
import { useEffect, useState } from 'react';
import { supabase } from '../lib/supabaseClient';
import Auth from '../components/Auth';
export default function Home() {
const [session, setSession] = useState(null);
useEffect(() => {
setSession(supabase.auth.session());
const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
setSession(session);
}
);
return () => {
authListener.subscription.unsubscribe();
};
}, []);
return (
<div>
<h1>欢迎来到Supabase GitHub OAuth示例</h1>
<Auth />
{session && (
<div>
<p>登录用户: {session.user.email}</p>
<img src={session.user.user_metadata.avatar_url} alt="Avatar" width={50} />
</div>
)}
</div>
);
}登录成功后,页面会显示用户邮箱和 GitHub 头像,说明整条链路已经打通。
第七步:处理授权回调
GitHub 回调的是 pages/api/auth/callback.js,它负责把授权码换成会话,再重定向回首页:
import { supabase } from '../../../lib/supabaseClient';
export default async function handler(req, res) {
const { code, state } = req.query;
const { data, error } = await supabase.auth.exchangeCodeForSession(code);
if (error) {
console.error('Error exchanging code for session:', error.message);
return res.redirect('/auth/auth-code-error');
}
res.redirect('/');
}另外建议在 pages/_app.js 里也挂一个全局监听,把认证事件打进控制台,调试时能直观看到 SIGNED_IN、SIGNED_OUT 等事件的流转。
配置清单与目录结构总览

完整的目录结构如下:
my-supabase-app/
├── components/
│ └── Auth.js
├── lib/
│ └── supabaseClient.js
├── pages/
│ ├── api/
│ │ └── auth/
│ │ └── callback.js
│ ├── index.js
│ └── _app.js
├── .env.local
└── package.json所有环境变量配置无误后,运行 npm run dev,访问 http://localhost:3000,点击「使用GitHub登录」,跳转 GitHub 完成授权后回到应用,用户信息正常展示,接入就算完成了。
常见问题排查
回调地址不生效:GitHub OAuth 应用里的 Authorization callback URL 与 signInWithOAuth 的 redirectTo 必须和实际路由完全一致,域名、协议、端口任何一处不匹配都会失败,本地调试时格外留意是否误填了生产域名。
授权码换不到会话:先确认 Supabase 的 GitHub Provider 中 Client ID 与 Client Secret 填写无误,再检查 .env.local 的键名与取值;环境变量改动要重启 dev server 才会生效。
服务角色密钥泄露风险:SUPABASE_SERVICE_ROLE_KEY 拥有绕过行级安全的高权限,只能出现在 API 路由等服务端代码中,绝不能写进客户端组件,也不要给它加 NEXT_PUBLIC_ 前缀。
版本差异:文中 supabase.auth.session() 是 v1 的取会话写法,supabase-js v2 起已改为 supabase.auth.getSession(),如果安装的是新版依赖,注意同步替换这一处调用。
小结
整套接入的固定成本只有三处配置加三个文件:GitHub 侧注册应用拿到密钥对,Supabase 侧启用 Provider,项目里写好客户端封装、登录组件和回调路由。本地跑通之后,搬上生产环境要做的只是把 localhost:3000 换成真实域名,并在 GitHub 与 Supabase 两边同步更新回调地址。与其自己造一套账号体系,不如把这个流程收进常用工具箱。



