NextAuth.js GitHub登录返回AccessDenied,profile未定义问题求助
问题现象
- 终端抛出错误:
Error: Unauthorized - Session not found - 浏览器跳转至
http://localhost:3000/api/auth/error?error=AccessDenied,提示访问被拒绝 - Navbar组件中
console.log("Session:", session)始终返回null
已确认配置
- .env文件中正确配置了
GITHUB_ID和GITHUB_SECRET - GitHub OAuth应用的授权回调URL设置为
http://localhost:3000/api/auth/callback/github - 使用环境:Next.js App Router(最新版) + NextAuth v4 + Sanity CMS
相关代码片段
auth.ts 认证逻辑
import NextAuth from "next-auth"; import GitHub from "next-auth/providers/github"; import { AUTHOR_BY_GITHUB_ID_QUERY } from "@/sanity/lib/queries"; import { client } from "@/sanity/lib/client"; import { writeClient } from "@/sanity/lib/write-client"; export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [GitHub], callbacks: { async signIn({ user: { name, email, image }, profile }) { console.log("SIGNIN PROFILE:", profile); if (!profile) { console.error("Profile missing!"); return false; } const { id, login, bio } = profile; const existingUser = await client .withConfig({ useCdn: false }) .fetch(AUTHOR_BY_GITHUB_ID_QUERY, { id, }); console.log("Existing user:", existingUser); if (!existingUser) { await writeClient.create({ _id: `author.${id}`, _type: "author", id, name, username: login, email, image, bio: bio || "", }); } return true; }, async jwt({ token, account, profile }) { if (account && profile) { const user = await client .withConfig({ useCdn: false }) .fetch(AUTHOR_BY_GITHUB_ID_QUERY, { id: profile?.id, }); token.id = user?._id; } return token; }, async session({ session, token }) { Object.assign(session, { id: token.id }); return session; }, }, });
next-auth.d.ts 类型声明
import { DefaultSession } from "next-auth"; declare module "next-auth" { interface Session { user: { id: string; } & DefaultSession["user"]; } } declare module "next-auth/jwt" { interface JWT { id: string; } }
Navbar.tsx 组件代码
// app/components/Navbar.tsx import { auth } from "@/auth"; import Image from "next/image"; import Link from "next/link"; import { LoginButton, LogoutButton } from "./AuthButtons"; const Navbar = async () => { const session = await auth(); console.log("Session:", session); return ( <header className="px-5 py-3 bg-white shadow-sm font-work-sans"> <nav className="flex justify-between items-center"> <Link href="/"> <Image src="/logo.png" alt="logo" width={144} height={30} /> </Link> <div className="flex items-center gap-5 text-black"> {session && session?.user ? ( <> <Link href="/startup/create"> <span>Create</span> </Link> <LogoutButton /> <Link href={`/user/${session?.user?.id}`}> {session?.user?.name} </Link> </> ) : ( <LoginButton /> )} </div> </nav> </header> ); }; export default Navbar;
排查与解决方向
1. 捕获signIn回调中的异步异常
当前signIn回调中的Sanity查询/创建用户操作未做错误捕获,一旦出现网络错误、权限错误或查询失败,会直接导致回调返回false,触发AccessDenied。添加try/catch块排查:
async signIn({ user: { name, email, image }, profile }) { console.log("SIGNIN PROFILE:", profile); if (!profile) { console.error("Profile missing!"); return false; } const { id, login, bio } = profile; try { const existingUser = await client .withConfig({ useCdn: false }) .fetch(AUTHOR_BY_GITHUB_ID_QUERY, { id }); console.log("Existing user:", existingUser); if (!existingUser) { await writeClient.create({ _id: `author.${id}`, _type: "author", id, name, username: login, email, image, bio: bio || "", }); } return true; } catch (err) { console.error("SignIn callback error:", err); return false; } },
2. 显式指定Session策略
NextAuth v4默认使用JWT策略,但显式声明可避免潜在的配置问题:
export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [GitHub], session: { strategy: "jwt" }, // 显式配置JWT策略 callbacks: { /* ... */ }, });
3. 修正Session回调的赋值逻辑
根据你扩展的Session类型,应将id赋值给session.user而非直接给session对象,否则会导致类型不兼容和数据丢失:
async session({ session, token }) { if (session.user) { session.user.id = token.id as string; } return session; },
4. 验证Sanity查询语句
确认AUTHOR_BY_GITHUB_ID_QUERY的GROQ查询是否正确,需确保能通过GitHub id匹配到Sanity中的author文档:
*[_type == "author" && id == $id][0]
如果查询返回undefined,会导致token.id为空,进而影响session生成。
5. 检查环境变量加载
在auth.ts开头添加日志,确认环境变量是否正确加载:
console.log("GITHUB_ID:", process.env.GITHUB_ID); console.log("GITHUB_SECRET:", process.env.GITHUB_SECRET);
注意Next.js默认优先加载.env.local文件,确保变量存放在正确的文件中。
6. 确认NextAuth路由入口
确保在app/api/auth/[...nextauth]/route.ts中正确导出handlers:
import { handlers } from "@/auth"; export const { GET, POST } = handlers;
该文件是App Router模式下NextAuth处理认证请求的必要入口,缺失会导致认证流程失败。
内容的提问来源于stack exchange,提问作者MegaMindTheCoder
相关产品推荐
相关产品推荐

