切换语言
切换主题

Next.js OAuth 登录完整指南:Google、GitHub、微信第三方登录配置与最佳实践

点击”使用 Google 登录”,页面跳转到 Google,点击授权,又跳回来,就自动登录成功了。

这个过程你肯定经历过无数次。但当你自己想给项目加个第三方登录时,突然就懵了:为什么要跳转两次?什么是回调地址?redirect_uri_mismatch 是什么鬼?本地测试正常,部署到线上就报错?

说实话,我第一次配置 OAuth 的时候也是这样。看了一堆文档,满屏都是”授权码”、“access_token”、“client_secret”这些术语,越看越晕。后来花了两天时间,踩了无数个坑,才算勉强搞明白。

这篇文章,我想用最直白的话讲清楚 OAuth 登录这件事。不堆砌术语,不讲大道理,就聊聊它到底是怎么工作的,以及怎么在 Next.js 里配置 Google、GitHub、微信三种登录。读完你会发现,其实也没那么玄乎。

OAuth 2.0 到底是什么?(用人话讲清楚)

先用个生活例子理解

假设你住在小区里,某天你在网上买了个东西,想让快递员帮你送到家门口。但问题来了:小区有门禁,快递员进不来。

传统做法是什么?你把门禁卡给快递员。但这样有风险啊——万一快递员拿着你的卡,以后随时能进小区怎么办?

更聪明的做法是:你去找小区保安,说”我有个快递要进来”。保安给快递员发了张临时通行证,上面写着”只能今天下午2点到4点进入,只能去A栋”。快递送完,通行证就失效了。

这就是 OAuth 的核心思想。

在这个例子里:

  • = 用户(想登录的人)
  • 快递员 = 第三方应用(比如你开发的网站)
  • 小区保安 = OAuth 提供者(Google、微信、GitHub等)
  • 门禁卡 = 你的密码(不能给别人)
  • 临时通行证 = access_token(有时效、有权限限制)

不需要把密码给第三方应用,只需要授权它去 OAuth 提供者那里拿一张”临时通行证”。

OAuth 的五步流程(授权码模式)

好,现在我们把这个流程具体化到 Next.js OAuth 登录。

第一步:用户点击你网站上的”使用 Google 登录”按钮。

第二步:你的网站把用户重定向到 Google 的授权页面,URL 大概长这样:

https://accounts.google.com/o/oauth2/auth?
  client_id=你的应用ID
  &redirect_uri=http://localhost:3000/api/auth/callback/google
  &response_type=code
  &scope=openid email profile
  &state=随机字符串

这一步,你的网站在跟 Google 说:“嘿,我是某某应用(client_id),用户想用你们的账号登录,麻烦你让用户确认一下。确认完后,请把用户送回我的这个地址(redirect_uri)。”

第三步:用户在 Google 页面看到”某某应用想访问你的基本信息”,点击”允许”。

第四步:Google 把用户重定向回你的网站(redirect_uri),并在 URL 里带上一个授权码(code)

http://localhost:3000/api/auth/callback/google?code=ABCD1234&state=随机字符串

注意,这个 code 只是个凭证,不是最终的通行证。它的有效期很短(通常 10 分钟),而且只能用一次。

第五步:你的网站后端拿着这个 code,再加上你的 client_secret(密码),去 Google 那里换真正的 access_token:

// 后端代码(简化版)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'ABCD1234',
    client_id: '你的应用ID',
    client_secret: '你的应用密码',
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code',
  }),
})

const { access_token } = await response.json()

拿到 access_token 后,你的网站就可以用它去 Google 获取用户信息(邮箱、头像、名字等)了。

第六步(可选):用 access_token 获取用户信息:

const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
})

整个流程走完,你的网站就知道”这个用户是谁”了,可以创建 session,让用户进入登录状态。

几个关键概念的人话解释

看到这里,你可能还是对几个术语有点迷糊。我再通俗地解释一遍:

  • client_id:你的应用在 Google 那里的”身份证号”。可以公开,别人看到也没事。

  • client_secret:你的应用的”密码”。绝对不能泄露,只能在后端使用。如果别人拿到了你的 client_secret,他们就能冒充你的应用去获取用户信息。

  • redirect_uri:授权成功后,Google 把用户送回哪个地址。这个地址必须提前在 Google Cloud Console 里注册,Google 会严格校验,哪怕多了一个斜杠都会报错(没错,就是那个让人抓狂的 redirect_uri_mismatch)。

  • state:一个随机字符串,用来防止 CSRF 攻击。你在发起授权时生成这个 state,Google 会原样返回。你要检查返回的 state 和你发出去的是不是同一个,如果不是,说明这个请求可能是伪造的。

  • code:临时授权码。有效期很短(10分钟左右),只能用一次。它的作用就是证明”用户已经在 Google 那里同意授权了”。

  • access_token:真正的”通行证”。有了它,你的网站就可以代表用户去 Google 获取信息。access_token 也有有效期,通常是 1 小时到几天不等。

为什么要分 code 和 access_token 两步?

你可能会想,为什么不直接返回 access_token,还要多此一举用个 code 再去换?

关键在于安全。Code 是通过浏览器重定向传递的(前端能看到),而 access_token 是在后端服务器之间传递的(前端看不到)。如果直接在 URL 里返回 access_token,浏览器历史记录、日志、网络监控都可能泄露它。用 code 换 token 的过程需要 client_secret,而 client_secret 只存在后端,这样就安全多了。

Next.js + NextAuth.js 配置 Google 登录(最简单的入门)

为什么选 NextAuth.js?

自己实现 OAuth 流程其实挺麻烦的:要处理回调、管理 session、防 CSRF 攻击、存储 token…一堆细节。

好消息是,有个库叫 NextAuth.js(现在叫 Auth.js v5)专门干这个事。它在 GitHub 上有 15k+ stars,社区很活跃,支持 50 多种 OAuth 提供者(Google、GitHub、微信、Twitter 等等),开箱即用。最新版本支持 Next.js 14+ 的 App Router,配置起来比以前简单多了。

说白了,用 NextAuth.js 能帮你省掉 80% 的重复劳动。

第一步:在 Google Cloud 创建应用

在写代码之前,你得先去 Google 那里”注册”一下你的应用,拿到 client_id 和 client_secret。

  1. 打开 Google Cloud Console,登录你的 Google 账号。

  2. 如果你之前没用过,先创建一个项目(Project)。项目名随便起,比如”My Next.js App”。

  3. 在左侧菜单找到”API 和服务” → “凭据”(Credentials)。

  4. 点击”创建凭据” → 选择”OAuth 客户端 ID”。

  5. 如果第一次用,可能会要求你先配置”OAuth 同意屏幕”。填一下应用名称、支持邮箱就行,其他先跳过(选”外部”用户类型,测试阶段不用审核)。

  6. 回到创建 OAuth 客户端 ID,选择应用类型为”Web 应用”。

  7. 重点来了:配置”已获授权的重定向 URI”。这里要填两个地址:

    • 本地开发:http://localhost:3000/api/auth/callback/google
    • 生产环境(部署后再加):https://yourdomain.com/api/auth/callback/google

    注意,这个地址必须和你代码里的完全一致,多一个斜杠、少一个斜杠都会报 redirect_uri_mismatch 错误。我刚开始就在这栽过跟头。

  8. 点击”创建”,会弹出一个对话框显示你的 Client ID 和 Client Secret。把这两个值复制下来,一会要用。

第二步:安装 NextAuth.js 并配置环境变量

在你的 Next.js 项目里,先装个包:

npm install next-auth@beta

注意要装 @beta 版本,这是 v5 版本(最新的)。

然后在项目根目录创建 .env.local 文件,把刚才拿到的 Client ID 和 Secret 填进去:

GOOGLE_CLIENT_ID=你的Client_ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=你的Client_Secret
NEXTAUTH_SECRET=随便生成一个随机字符串
NEXTAUTH_URL=http://localhost:3000

NEXTAUTH_SECRET 可以用这个命令生成:

openssl rand -base64 32

部署到生产环境时,记得把 NEXTAUTH_URL 改成你的域名。

第三步:创建 NextAuth 配置文件

app/api/auth/[...nextauth]/route.ts 创建文件(如果是 Pages Router,路径是 pages/api/auth/[...nextauth].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!,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // 登录成功时的回调,可以在这里保存用户信息到数据库
      console.log("用户登录:", user)
      return true // 返回 true 表示允许登录
    },
    async session({ session, token }) {
      // 自定义 session 内容
      if (session.user) {
        session.user.id = token.sub // 把 user id 加到 session 里
      }
      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

就这样,NextAuth.js 会自动帮你处理 OAuth 的所有流程。/api/auth/callback/google 这个路由也是自动生成的,不用你再写代码。

第四步:创建登录按钮

在任意组件里,你可以这样写登录按钮:

'use client' // App Router 需要标注客户端组件

import { signIn, signOut, useSession } from "next-auth/react"

export default function LoginButton() {
  const { data: session } = useSession()

  if (session) {
    // 用户已登录
    return (
      <div>
        <p>欢迎, {session.user?.name}</p>
        <img src={session.user?.image || ''} alt="头像" />
        <button onClick={() => signOut()}>退出登录</button>
      </div>
    )
  }

  // 用户未登录
  return <button onClick={() => signIn('google')}>使用 Google 登录</button>
}

signIn('google') 会自动跳转到 Google 授权页面,授权完成后跳回来,用户就登录了。超简单。

第五步:在根布局里包裹 SessionProvider

为了让 useSession 在所有组件里都能用,需要在根布局包一层 Provider:

// app/layout.tsx
import { SessionProvider } from "next-auth/react"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SessionProvider>{children}</SessionProvider>
      </body>
    </html>
  )
}

搞定!现在你就有一个可以用 Google 登录的 Next.js 应用了。

常见问题排查

问题 1:redirect_uri_mismatch

这是最常见的错误,我当时第一次配置就遇到了。

错误信息大概是:Error 400: redirect_uri_mismatch

原因:你在 Google Cloud Console 配置的回调地址和实际请求的不一致。

解决方法:

  1. 检查 Google Cloud Console 里的”已授权的重定向 URI”是不是 http://localhost:3000/api/auth/callback/google(注意有没有多余的斜杠)
  2. 检查你的 .env.localNEXTAUTH_URL 是不是 http://localhost:3000
  3. 如果你改了端口(比如 3001),两边都要改

问题 2:本地开发正常,部署后登录失败

这个我也踩过坑。本地测试登录一切正常,部署到 Vercel 后,点击登录按钮没反应或报错。

原因:忘了更新生产环境的环境变量。

解决方法:

  1. 在 Google Cloud Console 的”已授权的重定向 URI”里加上生产域名:https://yourdomain.com/api/auth/callback/google
  2. 在 Vercel(或你用的托管平台)的环境变量设置里,把 NEXTAUTH_URL 改成 https://yourdomain.com
  3. 重新部署

问题 3:登录后 session 是 null

如果你调用 useSession() 返回的 session 一直是 null,检查一下是不是忘了在根布局包 <SessionProvider>

问题 4:TypeError: Cannot read property ‘user’ of null

通常是因为 session 还在加载中,你就尝试访问 session.user 了。

解决方法:先判断 session 是否存在:

const { data: session, status } = useSession()

if (status === 'loading') {
  return <div>加载中...</div>
}

if (!session) {
  return <div>未登录</div>
}

// 这里才安全访问 session.user

GitHub 登录配置(理解差异)

有了 Google 登录的经验,配置 GitHub 登录就简单多了。不过 GitHub 和 Google 还是有点小差异,值得聊聊。

GitHub 和 Google OAuth 的区别

相似的地方:都是标准的 OAuth 2.0 授权码模式,流程一模一样。

不同的地方:

  1. 权限控制更细:GitHub 的 scope(权限范围)比 Google 复杂。默认只能拿到用户的公开信息,如果你想获取用户的邮箱(尤其是私有邮箱),需要单独申请 user:email 权限。
  2. 回调地址配置更宽松:Google 要求你填写完整的回调 URL,GitHub 只需要填域名就行。
  3. 应用类型:GitHub 支持个人账号和组织账号两种 OAuth App。

第一步:在 GitHub 创建 OAuth App

  1. 登录 GitHub,点击右上角头像 → Settings → 左侧菜单找到 “Developer settings”。

  2. 点击 “OAuth Apps” → “New OAuth App”。

  3. 填写应用信息:

    • Application name:你的应用名称(用户授权时会看到)
    • Homepage URL:你的网站首页,比如 http://localhost:3000
    • Authorization callback URL:填 http://localhost:3000/api/auth/callback/github
  4. 点击 “Register application”,然后点击 “Generate a new client secret”,把 Client ID 和 Client Secret 复制下来。

第二步:配置环境变量

.env.local 里加上 GitHub 的配置:

GITHUB_CLIENT_ID=你的GitHub_Client_ID
GITHUB_CLIENT_SECRET=你的GitHub_Client_Secret

第三步:更新 NextAuth 配置

在之前的 route.ts 文件里,加上 GitHubProvider:

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_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      // 如果需要获取用户私有邮箱,加上这个配置
      authorization: {
        params: {
          scope: 'read:user user:email'
        }
      }
    }),
  ],
  callbacks: {
    // ... 之前的 callbacks
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

第四步:更新登录按钮

在登录按钮组件里,加上 GitHub 登录选项:

return (
  <div>
    <button onClick={() => signIn('google')}>使用 Google 登录</button>
    <button onClick={() => signIn('github')}>使用 GitHub 登录</button>
  </div>
)

就这样,搞定!

关于 scope(权限范围)的说明

GitHub 的 scope 控制你的应用能获取哪些用户信息。常用的有:

  • read:user:读取用户的公开和私有信息(名字、头像、bio等)
  • user:email:读取用户的邮箱(包括私有邮箱)
  • public_repo:访问用户的公开仓库
  • repo:访问用户的所有仓库(公开+私有,权限很大,慎用)

对于登录场景,read:user user:email 就够了。

如果你不加 user:email scope,NextAuth.js 只能拿到用户的公开邮箱。如果用户在 GitHub 设置里隐藏了邮箱,session.user.email 就会是 null。我当时就因为这个困惑了好一阵,以为是代码哪里写错了。

一个小坑:GitHub 用户可能没有公开邮箱

不同于 Google(强制要求邮箱),GitHub 用户可以选择不公开邮箱。如果你的应用必须要用户邮箱(比如发送通知),记得在 signIn callback 里检查:

async signIn({ user, account }) {
  if (account?.provider === 'github' && !user.email) {
    // 用户没有公开邮箱,可以拒绝登录或提示用户
    console.log("GitHub 用户未提供邮箱")
    return false // 拒绝登录
  }
  return true
}

微信登录配置(国内特殊情况)

好,现在来聊聊微信登录。说实话,微信登录比 Google 和 GitHub 复杂不少,主要是因为它的生态和国外的不太一样。

微信登录为什么特殊?

先说几个关键差异:

  1. 需要扫码:PC 网站的微信登录,用户需要掏出手机扫二维码授权(不像 Google/GitHub 直接在网页上点点点就行)。
  2. 没有官方 NextAuth.js Provider:NextAuth.js 没有内置微信 provider,你得自己写一个。
  3. 回调地址限制多:微信要求回调域名必须备案,不能用 localhost,开发调试比较麻烦。
  4. 有 openid 和 unionid:微信的用户标识比较特殊,同一个用户在不同应用里的 openid 不同,如果你有多个应用想共享用户数据,需要用 unionid。

第一步:微信开放平台注册

  1. 打开 微信开放平台,注册一个账号。

  2. 创建”网站应用”(注意不是公众号也不是小程序)。

  3. 填写网站信息,上传网站截图,等待审核。审核通常需要 1-3 个工作日。

  4. 审核通过后,你会拿到 AppIDAppSecret(相当于 client_id 和 client_secret)。

  5. 在”开发信息”里配置授权回调域(注意只填域名,不需要完整路径,比如 yourdomain.com)。

第二步:自定义微信 Provider

因为 NextAuth.js 没有内置微信 provider,我们得自己写一个。在项目里创建 lib/wechat-provider.ts

import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers"

export interface WeChatProfile {
  openid: string
  nickname: string
  headimgurl: string
  sex: number
  province: string
  city: string
  country: string
  unionid?: string
}

export default function WeChatProvider<P extends WeChatProfile>(
  options: OAuthUserConfig<P>
): OAuthConfig<P> {
  return {
    id: "wechat",
    name: "WeChat",
    type: "oauth",
    
    // 微信的授权地址(PC网站应用用这个)
    authorization: {
      url: "https://open.weixin.qq.com/connect/qrconnect",
      params: {
        scope: "snsapi_login",
        appid: options.clientId,
        response_type: "code",
      },
    },
    
    // 用授权码换 access_token 的地址
    token: {
      url: "https://api.weixin.qq.com/sns/oauth2/access_token",
      params: {
        appid: options.clientId,
        secret: options.clientSecret,
        grant_type: "authorization_code",
      },
    },
    
    // 获取用户信息的地址
    userinfo: {
      url: "https://api.weixin.qq.com/sns/userinfo",
      async request({ tokens, provider }) {
        const res = await fetch(
          `${provider.userinfo?.url}?access_token=${tokens.access_token}&openid=${tokens.openid}&lang=zh_CN`
        )
        return await res.json()
      },
    },
    
    // 把微信返回的用户信息转换成 NextAuth 的标准格式
    profile(profile) {
      return {
        id: profile.openid,
        name: profile.nickname,
        email: null, // 微信不提供邮箱
        image: profile.headimgurl,
      }
    },
    
    options,
  }
}

第三步:配置环境变量

.env.local 里加上微信配置:

WECHAT_CLIENT_ID=你的微信AppID
WECHAT_CLIENT_SECRET=你的微信AppSecret

第四步:在 NextAuth 中使用

更新 route.ts

import WeChatProvider from "@/lib/wechat-provider"

export const authOptions = {
  providers: [
    GoogleProvider({...}),
    GitHubProvider({...}),
    WeChatProvider({
      clientId: process.env.WECHAT_CLIENT_ID!,
      clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    }),
  ],
}

第五步:本地开发怎么测试?

这是个痛点。因为微信不允许 localhost 作为回调域,本地开发没法直接测试。

有两种解决办法:

方案1:用内网穿透工具

ngrokcpolar 把你的本地服务暴露到公网:

# 安装 ngrok
brew install ngrok

# 启动内网穿透
ngrok http 3000

ngrok 会给你一个临时域名,比如 https://abc123.ngrok.io。把这个域名填到微信开放平台的授权回调域里,然后更新 .env.local 里的 NEXTAUTH_URL

NEXTAUTH_URL=https://abc123.ngrok.io

方案2:配置 hosts 文件

在本地 hosts 文件(Mac/Linux 是 /etc/hosts,Windows 是 C:\Windows\System32\drivers\etc\hosts)加一行:

127.0.0.1 dev.yourdomain.com

然后访问 http://dev.yourdomain.com:3000,并在微信开放平台配置回调域为 dev.yourdomain.com

但这个方案有个问题:微信要求回调域必须备案,所以 dev.yourdomain.com 还是过不了。最靠谱的还是方案1。

微信登录的特殊处理

微信用户没有邮箱,如果你的应用强依赖邮箱,需要额外处理:

async signIn({ user, account }) {
  if (account?.provider === 'wechat') {
    // 微信用户没有邮箱,可以让用户补填
    // 或者用 openid 作为唯一标识存数据库
    console.log("微信用户 openid:", user.id)
  }
  return true
}

安全最佳实践(避开常见坑)

配置完 OAuth 登录,还有一些安全细节要注意。这些坑我都踩过,血泪教训。

1. client_secret 绝对不能泄露

错误做法

// ❌ 千万别这样写!
const clientSecret = "abc123def456" // 硬编码在代码里

如果你把 client_secret 写在前端代码或提交到 Git 仓库,别人拿到后就能冒充你的应用去获取用户信息。

正确做法

  • 用环境变量存储,.env.local 加入 .gitignore
  • client_secret 只在后端使用(NextAuth.js 的 API route 是后端,所以没问题)
  • 部署时用平台的环境变量管理(Vercel 的 Settings → Environment Variables)

2. state 参数的作用(防 CSRF 攻击)

OAuth 流程里有个 state 参数,它的作用是防止 CSRF 攻击。

攻击场景:黑客构造一个恶意链接,里面包含一个伪造的授权码,诱导你点击。如果你的应用没验证 state,就可能被骗去用这个假的授权码换 token。

好消息是,NextAuth.js 自动帮你处理了 state 验证,你不用额外写代码。

如果你自己实现 OAuth(不用 NextAuth.js),记得:

  1. 发起授权时生成一个随机 state,保存到 session 或 cookie
  2. 回调时检查返回的 state 是不是和你发出去的一致
  3. 不一致就拒绝

3. 回调地址白名单

在 OAuth 提供者(Google、GitHub、微信)后台,把所有可能的回调地址都配置好:

  • 开发环境:http://localhost:3000/api/auth/callback/[provider]
  • 预览环境:https://preview.yourdomain.com/api/auth/callback/[provider]
  • 生产环境:https://yourdomain.com/api/auth/callback/[provider]

不要用通配符(比如 https://*.yourdomain.com),虽然方便,但不安全。明确列出所有域名,防止被攻击者利用。

4. Token 存储的安全性

NextAuth.js 默认用 JWT 方式存储 session,token 保存在 HttpOnly Cookie 里。这是个很好的设计:

  • HttpOnly:前端 JavaScript 无法读取这个 cookie,防止 XSS 攻击窃取 token
  • Secure(生产环境):只通过 HTTPS 传输,防止中间人攻击

你要做的:

  • 不要把 access_token 返回给前端(NextAuth.js 默认不返回,你也别主动返回)
  • 如果需要持久化用户信息,在 signIn callback 里保存到数据库,session 里只存必要信息(user id、email)

5. 授权码的时效性

OAuth 的授权码(code)有效期很短(10分钟),只能用一次。

这是个安全设计:即使黑客截获了你的 code,等他反应过来去用的时候,code 可能已经过期或被你用掉了。

如果用户在授权页面停留太久(比如去泡了杯咖啡),回来时 code 可能已经过期。NextAuth.js 会自动处理这种情况,重新发起授权。

6. 生产环境检查清单

部署之前,检查一遍这些配置:

  • 环境变量都设置了吗(NEXTAUTH_URL、NEXTAUTH_SECRET、各个 provider 的 client_id 和 client_secret)?
  • NEXTAUTH_URL 改成生产域名了吗(不是 localhost)?
  • OAuth 提供者后台配置了生产环境的回调地址吗?
  • .env.local 在 .gitignore 里吗(确保 secret 不会被提交到 Git)?
  • 生产环境的 NEXTAUTH_SECRET 是随机生成的吗(不要用开发环境的)?

总结

说了这么多,我们来快速总结一下。

OAuth 的本质其实就是”临时通行证”:你不需要把密码给第三方应用,只需要授权它去 OAuth 提供者那里拿一张有时效、有权限限制的通行证(access_token)。整个流程分两步:先用授权码(code)证明用户同意了,再用 code + client_secret 换真正的 token。

在 Next.js 里配置第三方登录,Google 最简单,是入门的最佳选择;GitHub 稍微复杂一点,需要注意 scope 配置和用户可能没有公开邮箱;微信最特殊,需要扫码、自定义 provider、回调域名备案,本地调试也比较麻烦。

安全方面,记住三个原则:

  1. client_secret 只在后端用,绝不泄露
  2. state 参数必须验证(NextAuth.js 帮你做了)
  3. 回调地址用白名单,不要通配符

如果你是第一次配置 OAuth,我建议从 Google 登录开始,跟着文章里的代码一步步来。配置成功后那种成就感,真的挺爽的。

遇到问题别慌,90% 的错误都是 redirect_uri 配置不对或者环境变量没设置。检查一遍,通常就能解决。

最后,推荐你去看看 NextAuth.js 官方文档,里面有更多高级用法(比如数据库存储 session、自定义登录页面、JWT 配置等)。OAuth 2.0 的标准规范(RFC 6749)也值得读一读,理解原理之后,再遇到问题就能举一反三了。

动手试试吧,祝你配置顺利!

Next.js OAuth 第三方登录配置完整流程

从零开始配置 Google、GitHub、微信三种第三方登录

⏱️ 预计耗时: 2 小时

  1. 1

    步骤1: 安装和初始化 NextAuth.js

    安装依赖:
    • npm install next-auth
    • 创建 app/api/auth/[...nextauth]/route.ts

    基础配置:
    • 设置 NEXTAUTH_URL(本地:http://localhost:3000,生产:实际域名)
    • 设置 NEXTAUTH_SECRET(生成随机字符串)
    • 配置基础 providers 数组
  2. 2

    步骤2: 配置 Google 登录

    步骤:
    1. 访问 Google Cloud Console
    2. 创建 OAuth 客户端 ID
    3. 设置授权回调 URI:http://localhost:3000/api/auth/callback/google
    4. 获取 Client ID 和 Client Secret
    5. 添加到环境变量:GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET
    6. 在 NextAuth 配置中添加 GoogleProvider

    注意:生产环境回调地址必须与配置完全一致
  3. 3

    步骤3: 配置 GitHub 登录

    步骤:
    1. 访问 GitHub Settings > Developer settings > OAuth Apps
    2. 创建新的 OAuth App
    3. 设置 Authorization callback URL:http://localhost:3000/api/auth/callback/github
    4. 获取 Client ID 和 Client Secret
    5. 添加到环境变量:GITHUB_CLIENT_ID、GITHUB_CLIENT_SECRET
    6. 在 NextAuth 配置中添加 GitHubProvider

    注意:scope 需要包含 user:email 才能获取邮箱
  4. 4

    步骤4: 配置微信登录(可选)

    步骤:
    1. 注册微信开放平台账号(需要企业认证)
    2. 创建网站应用,获取 AppID 和 AppSecret
    3. 设置授权回调域名(需要备案)
    4. 自定义 Provider(NextAuth 不内置微信)
    5. 实现扫码登录流程

    注意:微信登录较复杂,建议先完成 Google 和 GitHub 再尝试
  5. 5

    步骤5: 创建登录页面和按钮

    创建登录组件:
    • 使用 signIn('google') 触发登录
    • 使用 signOut() 退出登录
    • 使用 useSession() 获取用户信息
    • 使用 SessionProvider 包裹应用

    示例:
    <button onClick={() => signIn('google')}>
    使用 Google 登录
    </button>
  6. 6

    步骤6: 测试和调试

    测试要点:
    • 本地测试:确保回调地址是 http://localhost:3000
    • 生产环境:确保回调地址与实际域名一致
    • 检查环境变量是否正确设置
    • 查看浏览器控制台和服务器日志

    常见错误:
    • redirect_uri_mismatch:回调地址不匹配
    • invalid_client:Client ID 或 Secret 错误
    • access_denied:用户拒绝授权

常见问题

OAuth 2.0 的工作原理是什么?
OAuth 2.0 允许用户授权第三方应用访问其资源,而不需要提供密码。流程是:用户点击登录 → 跳转到 OAuth 提供商 → 用户授权 → 返回授权码 → 用授权码换取 access_token → 使用 token 获取用户信息。
redirect_uri_mismatch 错误怎么解决?
这个错误表示回调地址不匹配。

解决方法:
1) 确保 OAuth 提供商后台配置的回调地址与代码中的完全一致(包括协议、域名、端口、路径)
2) 本地开发用 http://localhost:3000,生产环境用实际域名
3) 检查是否有多余的斜杠或参数
NextAuth.js 和手动实现 OAuth 有什么区别?
NextAuth.js 是封装好的 OAuth 解决方案:
• 支持 50+ 提供商
• 自动处理授权流程、session 管理、CSRF 防护等

手动实现需要自己处理:
• 授权码交换
• token 存储
• state 验证等

代码量大且容易出错,建议使用 NextAuth.js。
如何获取用户的邮箱地址?
不同提供商获取邮箱的方式不同:
• Google:默认返回邮箱
• GitHub:需要在 scope 中包含 user:email,且用户必须设置邮箱为公开
• 微信:需要通过 unionid 查询

如果获取不到,可以在登录后让用户手动填写。
本地测试正常,部署到生产环境就报错?
通常是回调地址配置问题。

检查:
1) 生产环境的 NEXTAUTH_URL 是否正确
2) OAuth 提供商后台的回调地址是否包含生产域名
3) 环境变量是否正确设置
4) 是否有防火墙或代理影响
可以同时支持多个登录方式吗?
可以。NextAuth.js 支持配置多个 providers,用户可以选择使用 Google、GitHub、微信等任意一种方式登录。在 signIn() 函数中指定 provider 名称即可。
OAuth 登录安全吗?
OAuth 2.0 是行业标准,相对安全。

但需要注意:
1) client_secret 必须保密,只在服务端使用
2) 使用 state 参数防止 CSRF 攻击(NextAuth.js 自动处理)
3) 回调地址使用白名单,不要用通配符
4) 定期更新依赖包

18 分钟阅读 · 发布于: 2025年12月19日 · 修改于: 2026年1月22日

评论

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

相关文章