Next.js OAuth登录实战:手把手接入Google、GitHub、微信第三方登录
上周接了个社区项目,产品经理丢过来一句:“加个Google登录吧,应该很快。“我想着不就是第三方登录嘛,之前也看过几篇教程,半小时搞定。结果配了一下午,各种redirect_uri错误、token获取失败,控制台的红色错误信息一条接一条。最崩溃的是,明明按着官方文档一步步来的,就是跑不通。
后来我发现,问题不在代码,而是我对OAuth流程理解得太浅了。什么authorization code、access token、callback这些概念,每个单独看都懂,但组合起来就蒙圈。如果你也被第三方登录折磨过,或者正准备给Next.js项目加登录功能,这篇文章能帮到你。
这次我会用大白话把OAuth流程讲清楚——不是照搬RFC文档那种抽象描述,而是用”代取快递”这种生活场景来类比。你会知道为什么需要code和token两个东西,callback到底在干嘛,以及那些容易出错的配置细节。然后手把手带你配置三种登录:Google(国际标准)、GitHub(开发者友好)、微信(国内必备但最折腾)。
说实话,微信登录是最坑的部分,文档不友好、需要企业资质、本地调试麻烦。但既然做国内项目绕不开,我就把踩过的坑都写出来,包括怎么用内网穿透调试、怎么配置自定义Provider。读完这篇,你应该能用一套代码架构搞定国内外登录需求。
OAuth流程到底是怎么回事
用代取快递理解OAuth
我第一次接触OAuth的时候,看到authorization code、access token这些概念就头大。后来想明白了,就是代取快递的逻辑。
想象一下:你在快递站有个包裹(用户信息),但你现在在公司,没法亲自去拿。这时候你朋友(你的Next.js应用)说帮你代取。快递站不能随便把东西给别人,得确认是你授权的,所以流程是这样的:
1. 你给朋友一个取件码 - 这就是authorization code。你点击”用Google登录”按钮后,会跳转到Google的授权页面,点同意后,Google会生成一个临时的code,通过URL参数传给你的应用。
2. 朋友拿着取件码去快递站 - 这就是你的应用后端用code去换access token。但快递站还要核实一下,这个朋友是不是你真正信任的人,所以需要你提前在快递站登记过朋友的身份证号(client_secret)。
3. 核实身份后给快递 - 快递站确认取件码+身份证号都对,就把包裹(用户信息)给朋友,朋友再交给你。这就是用access_token获取用户信息的过程。
关键点在这:取件码(code)是一次性的,而且任何人看到都没用,因为没有身份证号(secret)配合,快递站不会给东西。这就是为什么code可以在浏览器URL里明文传输,但secret必须藏在后端。
四个关键步骤拆解
具体到技术流程,就是这四步:
步骤1:跳转到OAuth服务器授权页面
用户点击”用Google登录”,你的前端会构造一个URL,把用户重定向到Google:
https://accounts.google.com/o/oauth2/v2/auth?
client_id=你的应用ID
&redirect_uri=http://localhost:3000/api/auth/callback/google
&response_type=code
&scope=email profile
这里面几个参数:
client_id:你的应用在Google那边的身份证redirect_uri:Google授权后把用户送回哪scope:你要访问哪些用户信息
步骤2:用户同意授权,获得code
用户在Google页面点”允许”后,Google会重定向回你的应用,URL变成:
http://localhost:3000/api/auth/callback/google?code=4/0AfJohXl...&state=random123
这个code就是取件码,有效期很短,一般只有5-10分钟,而且只能用一次。
步骤3:后端用code换access_token
你的应用后端(注意是后端,不是前端)拿着code,再加上client_secret,发请求给Google:
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
body: JSON.stringify({
code: '刚才拿到的code',
client_id: 'your_client_id',
client_secret: 'your_secret', // 这个绝不能暴露给前端
redirect_uri: 'http://localhost:3000/api/auth/callback/google',
grant_type: 'authorization_code'
})
})
const { access_token } = await response.json()
拿到access_token后,这才是真正能获取用户信息的钥匙。
步骤4:用access_token获取用户信息
有了token,就能调用Google的API获取用户数据了:
const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: {
Authorization: `Bearer ${access_token}`
}
})
const user = await userInfo.json()
// { email: "[email protected]", name: "张三", picture: "头像URL" }
拿到用户信息后,你就可以在自己的数据库里创建或更新用户记录,然后生成session,完成登录。
关键概念速查表
我把常见术语整理了下,方便对照:
| 术语 | 通俗解释 | 在哪里能看到 |
|---|---|---|
| Client ID | 你应用的身份证号,可以公开 | .env.local文件,浏览器URL参数 |
| Client Secret | 应用的密码,绝对保密 | 只能在后端代码和环境变量里 |
| Authorization Code | 一次性取件码 | 回调URL的code参数 |
| Access Token | 真正能获取信息的钥匙 | 后端代码里,不传给前端 |
| Redirect URI | 授权后回跳的地址 | OAuth应用配置、授权URL参数 |
| Scope | 要访问的权限范围 | 授权URL参数,如”email profile” |
| State | 防CSRF攻击的随机字符串 | 授权URL参数和回调URL参数 |
State参数的作用:你发起授权时生成一个随机字符串(比如”abc123”),存在session里,同时传给OAuth服务器。回调时检查返回的state是不是”abc123”。如果不是,说明可能被攻击了,直接拒绝。NextAuth.js会自动帮你处理这个。
为什么不能直接返回token?
你可能会想,既然最终需要的是access_token,为啥不直接在URL里返回token,还要多一步code换token?
安全考虑。
浏览器地址栏的URL是明文的,会被浏览器历史记录、服务器日志、浏览器插件看到。如果直接返回token,等于把用户信息的钥匙明文传播了,风险太大。
而code即使被截获也没用,因为:
- Code只能用一次,用过就作废
- 换token必须同时提供client_secret,这个只有你的后端知道
- OAuth服务器还会验证redirect_uri是否匹配
这样就算攻击者截获了code,没有secret也换不到token,用户信息还是安全的。
这个设计叫”Authorization Code Flow”,是OAuth 2.0最安全的一种授权方式,特别适合有后端服务器的Web应用。还有种”Implicit Flow”直接返回token,但已经不推荐用了,太不安全。
NextAuth.js快速上手
为什么选NextAuth.js
Next.js OAuth登录有几种实现方式,可以完全手写,也可以用库。我试过自己写,踩了无数坑后果断投降,改用NextAuth.js。
为啥推荐它:
原因1:官方背书,生态成熟
NextAuth.js是Next.js官方文档推荐的认证方案,GitHub上7万+星,维护活跃。2024年11月刚发布的v5版本完美支持App Router和Server Components,不用担心兼容性问题。
原因2:内置30+OAuth提供者
Google、GitHub、Facebook、Twitter这些常见的开箱即用,配置几行代码就能跑。对于像微信这种没内置的,也提供了自定义Provider的机制,不用从零写OAuth流程。
原因3:自动处理复杂逻辑
Session管理、JWT签名、数据库存储、CSRF防护,这些全自动。你只需要关注业务逻辑,比如”用户第一次登录时要不要发欢迎邮件”。
核心配置文件结构
NextAuth.js的核心是一个API route,如果你用的是App Router(Next.js 13+),文件路径是:
app/api/auth/[...nextauth]/route.ts
这个[...nextauth]是Next.js的catch-all route,意思是所有/api/auth/*的请求都会被这个文件处理,包括:
/api/auth/signin- 登录页/api/auth/callback/google- Google回调/api/auth/signout- 登出/api/auth/session- 获取当前session
基础配置长这样:
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
// 可选:自定义登录页
pages: {
signIn: '/login',
},
// 可选:回调函数,处理登录后的逻辑
callbacks: {
async signIn({ user, account, profile }) {
// 可以在这里检查用户是否在白名单里
return true // 返回false会阻止登录
},
async session({ session, token }) {
// 给session添加额外信息
session.user.id = token.sub
return session
},
},
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
最后一行export { handler as GET, handler as POST }很重要,App Router需要明确导出HTTP方法的处理函数。
环境变量命名规范
NextAuth.js对环境变量命名有点讲究,特别是v5版本:
必需的环境变量:
# .env.local
# NextAuth配置
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here
# 或者用新的命名(v5推荐)
AUTH_SECRET=your-secret-key-here
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# 或者用AUTH_前缀(v5自动识别)
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret
# GitHub OAuth
GITHUB_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret
# 或者
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret
几个关键点:
-
NEXTAUTH_URL:你的应用完整URL,开发环境是
http://localhost:3000,生产环境必须是你的实际域名(含https)。 -
NEXTAUTH_SECRET / AUTH_SECRET:用来签名JWT的密钥,必须是随机字符串。生成方式:
openssl rand -base64 32
这个东西千万别泄露,也别提交到Git。如果泄露了,赶紧换一个,不然别人能伪造session。
- AUTH_前缀的魔法:NextAuth.js v5会自动识别
AUTH_PROVIDER_ID和AUTH_PROVIDER_SECRET格式的变量,不用在代码里写process.env.XXX,更方便。
安装和最小化配置
说了这么多,上手很简单:
步骤1:安装
npm install next-auth
# 或
pnpm add next-auth
步骤2:创建API route
创建app/api/auth/[...nextauth]/route.ts,粘贴前面的代码。
步骤3:创建.env.local
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=运行 openssl rand -base64 32 生成的字符串
步骤4:在前端加个登录按钮
// app/login/page.tsx
'use client'
import { signIn } from 'next-auth/react'
export default function LoginPage() {
return (
<div>
<button onClick={() => signIn('google')}>
用Google登录
</button>
<button onClick={() => signIn('github')}>
用GitHub登录
</button>
</div>
)
}
步骤5:用Provider包裹应用
如果要在客户端组件里使用useSession(),需要加个Provider:
// app/layout.tsx
import { SessionProvider } from 'next-auth/react'
export default function RootLayout({ children }) {
return (
<html>
<body>
<SessionProvider>
{children}
</SessionProvider>
</body>
</html>
)
}
配置完这些,基本骨架就有了。当然现在点登录按钮会报错,因为还没配置Google和GitHub的OAuth应用,这个接下来讲。
Google登录实战配置
Google Cloud Console配置
Google OAuth配置分两部分:在Google Cloud Console创建OAuth应用,然后在Next.js里对接。
第1步:进入Google Cloud Console
访问 https://console.cloud.google.com,用你的Google账号登录。如果是第一次用,会提示你创建项目,随便起个名字,比如”我的博客”。
第2步:启用Google+ API
虽然Google+早就关了,但OAuth还是依赖这个API。点左侧菜单”APIs & Services” → “Library”,搜索”Google+ API”,点进去,点”Enable”。
第3步:创建OAuth凭据
- 点左侧”Credentials”
- 点顶部”Create Credentials” → “OAuth client ID”
- 如果是第一次,会让你先配置”OAuth consent screen”,填一下应用名称、用户支持邮箱,其他可以先跳过
- Application type选”Web application”
- Name随便填,比如”Next.js App”
第4步:配置Redirect URIs(重中之重)
这是最容易出错的地方。Authorized redirect URIs要填两个:
开发环境:
http://localhost:3000/api/auth/callback/google
生产环境(等部署后再加):
https://yourdomain.com/api/auth/callback/google
注意几个细节:
httpvshttps:本地开发用http,生产必须https,Google不允许生产环境用http- 端口号:如果你本地跑在3001,就得写
localhost:3001,不能省略端口 - 路径:
/api/auth/callback/google一个字母都不能错,多个斜杠或者少个斜杠都不行 - 不要加查询参数:只需要写到
/google,后面的?code=xxx是Google自动加的
配置完点”Create”,会弹出Client ID和Client Secret,复制保存好。
第5步:复制到.env.local
GOOGLE_CLIENT_ID=你的Client ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx
Next.js代码集成
前面NextAuth.js的配置已经加了GoogleProvider,只要环境变量对,就能用了。但我们可以优化一下:
// app/api/auth/[...nextauth]/route.ts
import GoogleProvider from "next-auth/providers/google"
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code"
}
}
}),
],
}
这里加了authorization.params:
prompt: "consent":每次登录都会显示授权页面,方便测试。生产环境可以去掉,Google会记住用户的选择access_type: "offline":会返回refresh token,用户登录一次后,即使offline也能刷新token(如果你需要长期访问用户数据才加这个)response_type: "code":明确使用authorization code flow
测试登录流程
启动Next.js:
npm run dev
访问 http://localhost:3000/login,点”用Google登录”,会跳转到Google授权页。点”允许”后,应该会回跳到你的应用。
在任意页面获取session:
// app/page.tsx
import { getServerSession } from "next-auth"
import { authOptions } from "./api/auth/[...nextauth]/route"
export default async function Home() {
const session = await getServerSession(authOptions)
if (session) {
return <div>你好, {session.user?.name}</div>
}
return <div>未登录</div>
}
或者在客户端组件里:
'use client'
import { useSession } from "next-auth/react"
export default function Profile() {
const { data: session, status } = useSession()
if (status === "loading") return <div>加载中...</div>
if (!session) return <div>未登录</div>
return (
<div>
<img src={session.user?.image} alt="头像" />
<p>{session.user?.name}</p>
<p>{session.user?.email}</p>
</div>
)
}
常见错误排查
错误1: redirect_uri_mismatch
完整报错:
Error 400: redirect_uri_mismatch
The redirect URI in the request, http://localhost:3000/api/auth/callback/google,
does not match the ones authorized for the OAuth client.
原因:你在Google Console配置的URI和实际callback的URI不完全匹配。
排查步骤:
- 打开浏览器开发者工具 → Network标签
- 点登录按钮,看跳转到Google时的URL
- 找到
redirect_uri参数,复制完整的值 - 回到Google Console,一字不差地粘贴到Authorized redirect URIs
- 注意协议(http/https)、端口、路径、有没有多余的斜杠
错误2: Access blocked: This app’s request is invalid
说明你没配置OAuth consent screen,或者没加测试用户。
解决:
- 回到Google Console → “OAuth consent screen”
- User Type选”External”(对外发布)或”Internal”(企业内部)
- 填写应用信息
- 如果是External且未发布,需要在”Test users”添加你的测试账号邮箱
错误3: 端口号问题
本地开发如果用localhost:3001跑,但redirect URI配的是localhost:3000,也会报错。
简单办法:统一用3000端口,或者在Google Console多加几个redirect URI(3000、3001、3002都加上)。
错误4: HTTPS要求
生产环境部署后,如果你的域名还是http,Google会拒绝。必须用https。Vercel、Netlify这些平台自动给你https,不用担心。
GitHub登录配置
GitHub OAuth App配置
GitHub的OAuth配置比Google简单,不需要启用API,直接创建OAuth App就行。
第1步:进入Developer settings
登录GitHub,点右上角头像 → Settings → 左侧拉到最底下 → Developer settings → OAuth Apps → New OAuth App。
第2步:填写应用信息
- Application name:随便填,用户看不到
- Homepage URL:本地开发填
http://localhost:3000,生产填你的域名 - Authorization callback URL:填
http://localhost:3000/api/auth/callback/github
注意GitHub的callback URL比较灵活,可以后期再改,不像Google那么严格。
点Register application,会生成Client ID。再点”Generate a new client secret”,生成Secret(只显示一次,记得保存)。
第3步:复制到.env.local
GITHUB_ID=你的Client ID
GITHUB_SECRET=你的Client Secret
Next.js集成
NextAuth.js配置:
import GitHubProvider from "next-auth/providers/github"
export const authOptions = {
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
}
就这么简单,不需要额外配置。
GitHub vs Google的差异
| 对比项 | GitHub | |
|---|---|---|
| 配置难度 | 中等,需要启用API | 简单,直接创建 |
| Redirect URI | 严格,必须完全匹配 | 宽松,支持通配符 |
| HTTPS要求 | 生产环境必须 | localhost可以http |
| Scope配置 | 需要明确指定 | 默认就够用 |
| 用户信息 | email、name、picture | login、email、avatar_url |
有一点要注意:GitHub的邮箱可能为null,如果用户设置了邮箱隐私保护。所以代码里要做判断:
const userEmail = session.user?.email || '未提供邮箱'
微信登录配置(国内场景)
微信登录的三种方式
这是最容易搞混的地方,微信有三种登录,适用场景完全不同:
| 登录方式 | 适用场景 | 要求 | 用户体验 |
|---|---|---|---|
| 开放平台-网站应用 | 独立网站 | 企业资质、备案域名、HTTPS | 扫码登录,支持PC |
| 公众号网页授权 | 微信内H5页面 | 认证公众号 | 仅微信浏览器内 |
| 企业微信 | 企业内部系统 | 企业微信账号 | 仅企业员工 |
我们这里讲第一种:开放平台网站应用登录,适合独立的Next.js网站。
微信开放平台配置(门槛较高)
前置条件:
- 企业营业执照(个人开发者不行)
- 已备案的域名
- HTTPS证书
第1步:注册开发者账号
访问 https://open.weixin.qq.com,点”注册”,选择”网站应用开发者”,上传营业执照,等待审核(一般1-2个工作日)。
第2步:创建网站应用
审核通过后,管理中心 → 网站应用 → 创建网站应用,填写:
- 应用名称
- 应用简介
- 应用官网:你的域名(必须已备案)
- 授权回调域:只填域名,不含协议和路径,如
yourdomain.com
注意这里和Google/GitHub不同,微信只需要填域名,不是完整URL。微信会自动匹配该域名下的所有路径。
提交后再等审核(1-7天),通过后会分配AppID和AppSecret。
第3步:环境变量
WECHAT_APP_ID=你的AppID
WECHAT_APP_SECRET=你的AppSecret
NextAuth.js自定义Provider
微信没有内置Provider,需要自己写。好消息是NextAuth.js提供了自定义Provider的机制:
// app/api/auth/[...nextauth]/route.ts
const WeChatProvider = {
id: "wechat",
name: "WeChat",
type: "oauth",
authorization: {
url: "https://open.weixin.qq.com/connect/qrconnect",
params: {
appid: process.env.WECHAT_APP_ID,
scope: "snsapi_login",
response_type: "code",
},
},
token: {
url: "https://api.weixin.qq.com/sns/oauth2/access_token",
async request({ params, provider }) {
const response = await fetch(
`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${process.env.WECHAT_APP_ID}&secret=${process.env.WECHAT_APP_SECRET}&code=${params.code}&grant_type=authorization_code`
)
const tokens = await response.json()
return { tokens }
},
},
userinfo: {
url: "https://api.weixin.qq.com/sns/userinfo",
async request({ tokens }) {
const response = await fetch(
`https://api.weixin.qq.com/sns/userinfo?access_token=${tokens.access_token}&openid=${tokens.openid}`
)
return await response.json()
},
},
profile(profile) {
return {
id: profile.unionid || profile.openid,
name: profile.nickname,
email: null, // 微信不提供邮箱
image: profile.headimgurl,
}
},
}
export const authOptions = {
providers: [
WeChatProvider,
// ...其他providers
],
}
开发环境调试方案
微信登录最麻烦的是本地调试,因为必须HTTPS且域名已备案。我一般用这两种方案:
方案1:内网穿透(推荐)
使用ngrok或cpolar把本地3000端口映射到公网:
# 使用ngrok
ngrok http 3000
# 或使用cpolar(国内更稳定)
cpolar http 3000
会生成一个临时域名,如https://abc123.ngrok.io,把这个域名配置到微信开放平台的授权回调域。
方案2:使用测试号
微信提供测试号,无需企业资质:
- 访问 https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
- 扫码登录后会分配测试用的AppID和Secret
- 配置回调域可以用内网穿透的临时域名
但测试号只能你自己用,其他人扫码会提示”未关注公众号”。
微信登录的独特之处
不同点1:返回openid和unionid
openid:用户在当前应用下的唯一标识unionid:用户在同一开放平台账号下所有应用的唯一标识(需要绑定多个应用才有)
建议用unionid做用户标识,如果没有unionid就用openid。
不同点2:不提供邮箱
微信API不返回邮箱,所以profile里email是null。如果你的用户系统需要邮箱,得让用户额外补填。
不同点3:access_token有效期短
Google/GitHub的token一般1小时,微信只有2小时,而且每天刷新次数有限(好像是10次)。所以要妥善处理token刷新逻辑。
总结
从OAuth原理到三大平台的实战配置,我们走了一遍完整的第三方登录流程。
核心要点回顾:
- OAuth的code和token两步设计是为了安全,code在浏览器明文传输没关系,但secret必须藏在后端
- NextAuth.js让你专注业务逻辑,不用操心Session管理、CSRF防护这些底层细节
- Google配置最严格,redirect URI必须完全匹配;GitHub最友好;微信门槛最高但国内必备
- 微信登录需要企业资质和备案域名,开发阶段可以用内网穿透+测试号调试
实用技巧:
- 用
openssl rand -base64 32生成NEXTAUTH_SECRET,别手写 - Google Console多配几个端口的redirect URI,避免端口切换时报错
- GitHub的邮箱可能为null,记得做空值处理
- 微信的unionid比openid更适合做跨应用的用户唯一标识
说实话,第三方登录最难的不是写代码,而是理解OAuth的设计思路,以及各平台的配置差异。这篇文章如果能帮你少踩几个坑,我就很开心了。
下次你接到”加个Google登录”的需求,应该不会再配一下午了。
Next.js OAuth登录完整配置流程
从理解OAuth原理到配置Google、GitHub、微信三种登录的完整步骤
⏱️ 预计耗时: 2 小时
- 1
步骤1: 理解OAuth流程(代取快递类比)
OAuth核心思想:不需要把密码给第三方应用,只需要授权它去OAuth提供者那里拿临时通行证。
代取快递类比:
• 你(用户)→ 想登录的人
• 朋友(Next.js应用)→ 帮你代取快递
• 快递站(OAuth提供者)→ Google、GitHub、微信
• 门禁卡(密码)→ 不能给别人
• 临时通行证(access_token)→ 有时效、有权限限制
四步流程:
1. 你给朋友取件码(authorization code)
2. 朋友拿取件码+身份证去快递站(code+client_secret换access_token)
3. 快递站核实身份后给包裹(用户信息)
4. 朋友把包裹交给你(登录成功)
关键点:
• 取件码(code)是一次性的,有效期短(通常10分钟)
• 身份证(client_secret)必须保密,只在服务端使用
• 临时通行证(access_token)有时效、有权限限制 - 2
步骤2: 配置Google登录
1. 在Google Cloud Console创建OAuth客户端:
• 访问 https://console.cloud.google.com
• 创建项目 → API和服务 → 凭据 → 创建OAuth客户端ID
• 应用类型:Web应用
• 授权重定向URI:http://localhost:3000/api/auth/callback/google
2. 获取client_id和client_secret
3. 配置NextAuth.js:
```ts
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
})
],
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
```
4. 设置环境变量:
```
GOOGLE_CLIENT_ID=你的client_id
GOOGLE_CLIENT_SECRET=你的client_secret
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=随机字符串
```
5. 在页面中使用:
```tsx
import { signIn } from 'next-auth/react'
<button onClick={() => signIn('google')}>
使用Google登录
</button>
``` - 3
步骤3: 配置GitHub登录
1. 在GitHub创建OAuth App:
• 访问 https://github.com/settings/developers
• New OAuth App
• Authorization callback URL:http://localhost:3000/api/auth/callback/github
2. 获取Client ID和Client Secret
3. 配置NextAuth.js:
```ts
import GitHubProvider from 'next-auth/providers/github'
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
})
]
```
4. 设置环境变量:
```
GITHUB_CLIENT_ID=你的client_id
GITHUB_CLIENT_SECRET=你的client_secret
```
关键点:GitHub的配置流程和Google类似,只是OAuth提供者不同 - 4
步骤4: 配置微信登录(特殊处理)
1. 在微信开放平台注册应用:
• 访问 https://open.weixin.qq.com
• 创建网站应用
• 获取AppID和AppSecret
• 需要企业资质
2. 配置授权回调域名:
• 格式:yourdomain.com(不要带http://或https://)
• 需要ICP备案的域名
3. 配置自定义Provider:
```ts
import WeChatProvider from 'next-auth/providers/wechat'
providers: [
WeChatProvider({
clientId: process.env.WECHAT_CLIENT_ID!,
clientSecret: process.env.WECHAT_CLIENT_SECRET!,
})
]
```
4. 本地调试用内网穿透:
• 使用ngrok或frp
• 配置回调地址为内网穿透地址
• 测试完成后改为生产地址
关键点:
• 微信登录需要企业资质
• 本地调试用内网穿透
• unionid比openid更适合做用户唯一标识 - 5
步骤5: 解决常见错误
错误1:redirect_uri_mismatch
• 原因:回调地址不匹配
• 解决:在OAuth提供者后台配置正确的redirect_uri
• 注意:本地和线上的回调地址都要配置
错误2:环境变量没设置
• 检查:.env.local文件是否存在
• 检查:环境变量名是否正确
• 检查:Vercel Dashboard中是否配置了环境变量
错误3:本地测试正常,部署到线上就报错
• 原因:线上和本地的回调地址不同
• 解决:在OAuth提供者后台配置生产环境的redirect_uri
• 格式:https://yourdomain.com/api/auth/callback/google
安全建议:
• client_secret必须保密,只在服务端使用
• 使用state参数防CSRF攻击
• 验证回调URL的state参数
常见问题
OAuth流程到底是怎么回事?
场景:你在快递站有个包裹(用户信息),但你现在在公司,没法亲自去拿。你朋友(Next.js应用)说帮你代取。
流程:
1. 你给朋友一个取件码(authorization code)
• 你点击"用Google登录"按钮后,会跳转到Google的授权页面
• 点同意后,Google会生成一个临时的code,通过URL参数传给你的应用
2. 朋友拿着取件码去快递站(code+client_secret换access_token)
• 你的应用后端用code+client_secret去Google那里换access_token
• 但Google还要核实一下,这个朋友是不是你真正信任的人(client_secret)
3. 核实身份后给快递(用户信息)
• Google确认code+client_secret都对,就把包裹(用户信息)给朋友
• 朋友再交给你(登录成功)
关键点:
• 取件码(code)是一次性的,有效期短(通常10分钟)
• 身份证(client_secret)必须保密,只在服务端使用
• 临时通行证(access_token)有时效、有权限限制
优势:你不需要把密码给第三方应用,只需要授权它去OAuth提供者那里拿临时通行证。
redirect_uri_mismatch是什么错误?
OAuth提供者会验证回调地址,如果和配置的不一致,就会报这个错误。
解决方法:
1. 在OAuth提供者后台配置正确的redirect_uri
2. 本地开发:http://localhost:3000/api/auth/callback/google
3. 生产环境:https://yourdomain.com/api/auth/callback/google
4. 注意:本地和线上的回调地址都要配置
常见错误:
• 只配置了本地,没配置生产环境
• 回调地址写错了(多了/少了斜杠)
• 协议不对(http vs https)
检查方法:
• 查看NextAuth.js的默认回调路径:/api/auth/callback/[provider]
• 确认OAuth提供者后台配置的redirect_uri和这个路径完全一致
注意:配置后需要等待几分钟生效。
微信登录为什么最坑?
1. 需要企业资质
• 个人开发者无法申请
• 需要营业执照等材料
• 审核时间通常1-3个工作日
2. 文档不友好
• 官方文档写得不够清楚
• 错误信息不够明确
• 调试困难
3. 本地调试麻烦
• 需要内网穿透(ngrok或frp)
• 回调地址配置复杂
• 测试环境限制多
4. 配置复杂
• 需要配置自定义Provider
• unionid和openid的区别
• 授权回调域名需要ICP备案
解决方案:
• 使用内网穿透调试
• 配置自定义Provider
• unionid比openid更适合做用户唯一标识
• 耐心等待审核
建议:如果可能,优先用Google或GitHub登录,微信登录作为补充。
如何配置自定义Provider?
```ts
import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers'
function WeChatProvider(options: OAuthUserConfig<WeChatProfile>): OAuthConfig<WeChatProfile> {
return {
id: 'wechat',
name: 'WeChat',
type: 'oauth',
authorization: {
url: 'https://open.weixin.qq.com/connect/qrconnect',
params: {
appid: options.clientId,
redirect_uri: options.callbackUrl,
response_type: 'code',
scope: 'snsapi_login',
state: 'state',
},
},
token: {
url: 'https://api.weixin.qq.com/sns/oauth2/access_token',
},
userinfo: {
url: 'https://api.weixin.qq.com/sns/userinfo',
},
profile(profile) {
return {
id: profile.openid,
name: profile.nickname,
email: null,
image: profile.headimgurl,
}
},
...options,
}
}
```
关键点:
• 配置authorization URL
• 配置token URL
• 配置userinfo URL
• 实现profile函数
注意:微信登录的配置比较复杂,建议参考官方文档或使用现成的Provider。
unionid和openid有什么区别?
• 用户在当前应用下的唯一标识
• 不同应用的openid不同
• 适合单应用场景
unionid:
• 用户在微信开放平台下的唯一标识
• 同一用户在不同应用下的unionid相同
• 适合多应用场景
选择建议:
• 单应用 → 用openid
• 多应用 → 用unionid
代码示例:
```ts
// 获取unionid
const response = await fetch(
`https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openid}`
)
const data = await response.json()
const unionid = data.unionid // 用户唯一标识
```
关键点:
• unionid比openid更适合做用户唯一标识
• 需要用户授权才能获取unionid
• 配置微信开放平台才能使用unionid
本地调试微信登录怎么处理?
解决方案:使用内网穿透
1. 使用ngrok:
```bash
ngrok http 3000
```
2. 获取公网地址:
```
https://xxxxx.ngrok.io
```
3. 配置回调地址:
• 在微信开放平台配置:https://xxxxx.ngrok.io/api/auth/callback/wechat
• 在.env.local中配置:NEXTAUTH_URL=https://xxxxx.ngrok.io
4. 测试:
• 访问 https://xxxxx.ngrok.io
• 点击微信登录
• 测试流程
注意事项:
• ngrok免费版地址会变,每次重启都要更新
• 生产环境不要用ngrok
• 测试完成后改为生产地址
建议:使用frp等自建内网穿透,地址更稳定。
18 分钟阅读 · 发布于: 2025年12月19日 · 修改于: 2026年1月22日
相关文章
Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 单元测试实战:Jest + React Testing Library 完整配置指南

评论
使用 GitHub 账号登录后即可评论