
上一篇讲了 OAuth 登录的通用流程。这一篇我们用 GitHub 登录做一次完整配置。
GitHub 登录很适合面向开发者、独立开发者、开源用户、技术团队的 SaaS 产品。它能降低注册成本,也能让你更容易拿到用户的开发者身份信息。
不过 GitHub OAuth 接入时,有几个细节必须处理好:OAuth App 创建、callback URL、Client Secret、scope、state、邮箱获取和账号绑定。
本文基于 GitHub 官方 OAuth App 文档整理,配置入口和流程以当前 GitHub 文档为准:
第一步:创建 GitHub OAuth App
登录 GitHub 后,进入右上角头像菜单,点击 Settings。
在左侧找到 Developer settings,进入后选择 OAuth apps,然后点击 New OAuth App。如果你之前没有创建过应用,按钮可能显示为 Register a new application。
创建时需要填写几个字段:
sql
Application name:你的产品名称
Homepage URL:你的产品首页地址
Application description:可选,写给用户看的说明
Authorization callback URL:你的 OAuth 回调地址
这些信息会展示给授权用户,所以不要填内部测试信息、敏感路径或不希望公开的内容。
第二步:配置 callback URL
callback URL 是 GitHub 授权完成后跳回你系统的地址。
例如:
ruby
开发环境:http://localhost:3000/api/auth/callback/github
生产环境:https://example.com/api/auth/callback/github
GitHub 官方文档提醒:OAuth App 不能像 GitHub App 那样配置多个 callback URL。因此你要为开发、测试、生产环境做好规划。
常见做法有两种。
第一,为不同环境创建不同 OAuth App。比如开发环境一个,生产环境一个。这样最清晰,也最不容易混淆。
第二,用统一域名和中转逻辑处理不同环境。但这会增加复杂度,早期不推荐。
独立开发者最稳妥的做法,是开发和生产分开创建两个 OAuth App。
第三步:保存 Client ID 和 Client Secret
创建完成后,GitHub 会给你一个 Client ID,你还可以生成 Client Secret。
这两个值的用途不同:
arduino
Client ID:可以用于生成授权链接
Client Secret:只能放在服务端,用于 code 换 token
不要把 Client Secret 放进前端代码,不要写进公开仓库,也不要发给别人。它应该放在服务端环境变量里。
例如:
ini
GITHUB_CLIENT_ID=xxx
GITHUB_CLIENT_SECRET=xxx
GITHUB_CALLBACK_URL=https://example.com/api/auth/callback/github
如果 secret 泄露,要立刻在 GitHub 后台重新生成。
第四步:生成 GitHub 授权链接
用户点击"使用 GitHub 登录"时,你要把用户跳转到 GitHub 授权地址:
ruby
https://github.com/login/oauth/authorize
常见参数包括:
arduino
client_id:GitHub OAuth App 的 Client ID
redirect_uri:你的 callback URL
scope:申请的权限范围
state:随机字符串,用来防止伪造请求
示例:
ini
https://github.com/login/oauth/authorize
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://example.com/api/auth/callback/github
&scope=read:user user:email
&state=RANDOM_STATE
state 必须在发起登录时保存,回调时再校验。
第五步:scope 不要申请太多
如果你只是做 GitHub 登录,通常只需要基础用户信息和邮箱。
常见 scope:
makefile
read:user:读取用户基础资料
user:email:读取用户邮箱
不要一开始就申请 repo 等敏感权限。用户看到过多权限会犹豫,也会增加安全风险。
权限应该服务产品功能。登录需要什么,就只申请什么。
第六步:处理 GitHub 回调
用户同意授权后,GitHub 会跳回你的 callback URL,并带上 code 和 state。
例如:
ini
https://example.com/api/auth/callback/github?code=xxx&state=yyy
你的服务端要先校验 state。如果 state 不一致,直接拒绝。
校验通过后,用 code 换取 access token。请求地址是:
ruby
POST https://github.com/login/oauth/access_token
请求参数通常包括:
css
client_id
client_secret
code
redirect_uri
建议请求时设置 Accept: application/json,让 GitHub 返回 JSON,便于解析。
第七步:获取 GitHub 用户信息
拿到 access token 后,可以请求 GitHub 用户信息接口:
sql
GET https://api.github.com/user
Authorization: Bearer ACCESS_TOKEN
你可以拿到 GitHub 用户 ID、用户名、头像、主页等信息。
如果需要邮箱,再请求:
sql
GET https://api.github.com/user/emails
Authorization: Bearer ACCESS_TOKEN
注意:GitHub 用户资料里的邮箱可能为空,尤其当用户隐藏邮箱时。更稳妥的做法是请求邮箱列表,选择已验证、主要邮箱作为登录邮箱。
第八步:绑定本地用户
不要只用 GitHub 用户名或邮箱作为本地用户唯一标识。
更稳妥的绑定方式是保存 GitHub 的 provider user id:
ini
user_id
provider = github
provider_user_id = GitHub user id
provider_login = GitHub username
provider_email = primary verified email
如果 provider_user_id 已经存在,就登录对应用户。如果不存在,再决定创建新用户还是提示绑定已有账号。
邮箱相同不一定意味着可以自动合并账号。尤其在已有邮箱密码登录的系统里,自动合并要非常谨慎。
第九步:创建自己的 session
GitHub token 只是访问 GitHub API 的凭证,不应该直接作为你产品的登录态。
GitHub 登录成功后,你应该创建自己系统的 session 或 cookie,然后跳转回产品页面。
如果你只是用于登录,不需要长期调用 GitHub API,可以不长期保存 access token。
如果你后续要读取仓库、组织或其他 GitHub 数据,再根据功能需要保存 token,并做好加密、刷新和撤销处理。
第十步:常见错误检查
GitHub 登录失败时,优先检查这些问题:
arduino
callback URL 是否和 GitHub 后台一致
开发环境和生产环境是否用了不同 OAuth App
Client Secret 是否只在服务端使用
state 是否正确保存和校验
scope 是否足够获取邮箱
是否处理了邮箱为空的情况
是否用 provider_user_id 绑定账号
是否创建了本地 session
大多数 GitHub 登录问题,都出在 callback URL、环境变量和邮箱处理上。
写在最后
GitHub 登录配置并不复杂,但它连接了第三方授权和你自己的用户系统,不能只看"能跳回来"。
一个稳妥的 GitHub 登录流程,应该做到:环境分离、secret 安全、state 校验、最小权限、邮箱兜底、provider id 绑定、本地 session 创建。
下一篇,我们继续讲另一个常见登录方式:Google 登录配置。