基于Next.js与Next-Auth授权实现YouTube视频上传求助
问题:NextAuth Google OAuth授权后实现YouTube上传及频道选择功能
我已通过NextAuth完成Google OAuth授权,目前需要实现两个核心功能:
- YouTube视频上传功能
- 复刻TunesToTube的频道选择功能——用户登录后可选择自己的YouTube频道
尝试多种方法均未实现频道选择功能,全网搜索也未找到有效解决方案,附上我的route.ts代码:
import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; export const authOptions: any = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID ?? "", clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? "", }), ], authorization: { params: { scope: [ "openid", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/youtube", ].join(" "), }, }, session: { strategy: 'jwt', }, secret: process.env.NEXTAUTH_SECRET, } export const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
解决方案
一、实现用户YouTube频道选择功能
1. 调整NextAuth配置,保存并传递access_token
在authOptions中添加回调函数,将Google返回的access_token存入JWT并同步到session,方便后续API调用:
callbacks: { async jwt({ token, account }) { // 登录时保存access_token和过期时间 if (account) { token.accessToken = account.access_token; token.expiresAt = account.expires_at; token.refreshToken = account.refresh_token; } return token; }, async session({ session, token }) { // 将token中的凭证传递到前端session session.user.accessToken = token.accessToken; session.user.expiresAt = token.expiresAt; return session; }, }
2. 调用YouTube Data API获取用户频道列表
通过access_token调用channels.list接口,获取用户名下所有YouTube频道:
- 请求地址:
GET https://www.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails&mine=true - 请求头:
Authorization: Bearer {access_token}
返回结果中会包含频道ID、名称、封面等信息,可将这些数据渲染为选择列表供用户选择。
二、实现YouTube视频上传功能
1. 确认权限范围
确保OAuth scope包含https://www.googleapis.com/auth/youtube.upload(已配置的youtube权限已包含该上传权限,无需额外添加)。
2. 后端上传逻辑示例(Next.js API路由)
import { getServerSession } from "next-auth/next"; import { authOptions } from "./auth/[...nextauth]/route"; export async function POST(request: Request) { const session = await getServerSession(authOptions); if (!session?.user.accessToken) { return new Response("Unauthorized", { status: 401 }); } const formData = await request.formData(); const videoFile = formData.get("video") as File; const title = formData.get("title") as string; const description = formData.get("description") as string; const channelId = formData.get("channelId") as string; // 用户选择的频道ID // 构建视频元数据 const metadata = { snippet: { title, description, categoryId: "22", // 视频分类ID,可根据需求调整 channelId }, status: { privacyStatus: "public" // 公开状态:public/private/unlisted } }; // 发起multipart上传请求 const boundary = "youtube-upload-boundary"; const blobParts = [ `--${boundary}\r\n`, `Content-Type: application/json\r\n\r\n`, JSON.stringify(metadata) + "\r\n", `--${boundary}\r\n`, `Content-Type: ${videoFile.type}\r\n\r\n`, videoFile, `\r\n--${boundary}--` ]; const uploadResponse = await fetch( "https://www.googleapis.com/upload/youtube/v3/videos?part=snippet,status", { method: "POST", headers: { Authorization: `Bearer ${session.user.accessToken}`, "Content-Type": `multipart/related; boundary=${boundary}` }, body: new Blob(blobParts) } ); const result = await uploadResponse.json(); return Response.json(result); }
关键注意事项
- 需在Google Cloud Console中启用YouTube Data API v3,否则所有API调用会返回权限错误
- OAuth consent screen需添加所有用到的scope,若面向外部用户需将应用发布为"生产"状态
- access_token有过期时间,NextAuth会自动用refresh_token刷新(需确保配置中保留了refresh_token的存储)
内容的提问来源于stack exchange,提问作者th1n
相关产品推荐
相关产品推荐

