Auth0 Next.js SDK 是一个用于在 Next.js 应用程序中实现用户身份验证的库。
文档 - 入门 - API 参考 - 反馈
快速入门 - 我们将 Auth0 添加到 Next.js 应用程序的指南。
常见问题解答 - 有关 nextjs-auth0 的常见问题。
示例 - 针对不同用例的大量示例。
安全 - 您应该检查的一些重要安全声明。
架构 - SDK 的架构概述。
测试 - 一些帮助测试您的 nextjs-auth0 应用程序。
部署 - 我们如何将示例应用程序部署到 Vercel。
文档站点 - 浏览我们的文档站点并了解有关 Auth0 的更多信息。
使用 npm:
npm install @auth0/nextjs-auth0
该库需要 Node.js 16 LTS 和更新的 LTS 版本。
在 Auth0 仪表板中创建常规 Web 应用程序。
如果您使用的是现有应用程序,请验证您是否已在常规 Web 应用程序中配置以下设置:
单击应用程序页面的“设置”选项卡。
向下滚动并单击“显示高级设置”链接。
在“高级设置”下,单击“OAuth”选项卡。
确保“JsonWebToken 签名算法”设置为
RS256
并启用“OIDC Conformant”。
接下来,在“设置”页面的“应用程序 URI”部分下为您的应用程序配置以下 URL:
允许的回调 URL : http://localhost:3000/api/auth/callback
允许的注销 URL : http://localhost:3000/
记下“基本信息”部分下的Client ID 、 Client Secret和Domain值。您在下一步中将需要这些值。
您需要允许 Next.js 应用程序与 Auth0 正确通信。您可以通过在根项目目录下创建一个.env.local
文件来定义必要的 Auth0 配置值,如下所示:
# 用于加密会话 cookie 的长秘密值AUTH0_SECRET='LONG_RANDOM_VALUE'# 应用程序的基本 urlAUTH0_BASE_URL='http://localhost:3000'# Auth0 租户域的 urlAUTH0_ISSUER_BASE_URL='https://YOUR_AUTH0_DOMAIN.auth0 .com'# 您的 Auth0 应用程序的客户端IDAUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'# 您的 Auth0 应用程序的客户端密钥AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_SECRET'
您可以执行以下命令来为AUTH0_SECRET
值生成合适的字符串:
节点-e“console.log(crypto.randomBytes(32).toString('hex'))”
您可以在“模块配置”文档的“配置属性”部分中查看 Auth0 配置选项的完整列表。
有关在 Next.js 中加载环境变量的更多详细信息,请访问“环境变量”文档。
将handleAuth()
添加到您的应用程序中,这会在后台创建以下路由处理程序,执行身份验证流程的不同部分:
/api/auth/login
:您的 Next.js 应用程序将用户重定向到您的身份提供商以便他们登录(您可以选择传递returnTo
参数以在登录后返回到自定义相对 URL,例如/api/auth/login?returnTo=/profile
)。
/api/auth/callback
:您的身份提供商在用户成功登录后将用户重定向到此路由。
/api/auth/logout
:您的 Next.js 应用程序注销用户。
/api/auth/me
:您可以获取 JSON 格式的用户个人资料信息。
根据您的路由器继续设置:
页面路由器
应用路由器
在/pages/api
目录下创建动态 API 路由处理程序:
在/pages/api/
目录下创建auth
目录。
在新创建的auth
目录下创建[auth0].js
文件。
动态 API 路由文件的路径为/pages/api/auth/[auth0].js
。按如下方式填充该文件:
从'@auth0/nextjs-auth0'导入{handleAuth};导出默认handleAuth();
使用UserProvider
组件包装pages/_app.js
组件:
//pages/_app.jsimport React from 'react';import { UserProvider } from '@auth0/nextjs-auth0/client';导出默认函数 App({ Component, pageProps }) { return (<UserProvider> <Component {...pageProps} /></UserProvider> );}
现在,您可以通过检查useUser()
挂钩返回的user
对象是否已定义来确定用户是否已通过身份验证。您还可以通过将用户重定向到适当的自动生成的路由,从 Next.js 应用程序的前端层登录或注销用户:
// pages/index.jsimport { useUser } from '@auth0/nextjs-auth0/client';导出默认函数 Index() { const { 用户,错误,正在加载 } = useUser(); if (isLoading) return <div>正在加载...</div>; 如果(错误)返回<div>{error.message}</div>; if (user) {return ( <div>欢迎{user.name}!<a href="/api/auth/logout">注销</a> </div>); } 返回<a href="/api/auth/login">登录</a>;}
接下来的 linting 规则可能建议使用
Link
组件而不是锚标记。Link
组件旨在执行页面之间的客户端转换。由于链接指向 API 路由而不是页面,因此您应该将它们保留为锚标记。
在继续之前,请先查看将此 SDK 与 React Server 组件一起使用。
在/app/api
目录下创建一个包罗万象的动态 API 路由处理程序(严格来说,您不需要将 API 路由放在/api
下,但为了简单起见,我们保留了约定):
在/app/
目录下创建一个api
目录。
在新创建的/app/api/
目录下创建auth
目录。
在新创建的auth
目录下创建[auth0]
目录。
在新创建的[auth0]
目录下创建route.js
文件。
动态 API 路由文件的路径为/app/api/auth/[auth0]/route.js
。按如下方式填充该文件:
从'@auth0/nextjs-auth0'导入{handleAuth};导出const GET =handleAuth();
UserProvider
添加到您的布局中使用UserProvider
组件包装您的app/layout.js
组件:
// app/layout.jsimport React from 'react';import { UserProvider } from '@auth0/nextjs-auth0/client';导出默认函数 App({children }) { 返回(<UserProvider> <body>{children}</body></UserProvider> );}
现在,您可以通过检查useUser()
挂钩返回的user
对象是否已定义来确定用户是否已通过身份验证。您还可以通过将用户重定向到适当的自动生成的路由,从 Next.js 应用程序的前端层登录或注销用户:
// pages/index.js'use client';import { useUser } from '@auth0/nextjs-auth0/client';导出默认函数 Index() { const { 用户,错误,正在加载 } = useUser(); if (isLoading) return <div>正在加载...</div>; 如果(错误)返回<div>{error.message}</div>; if (user) {return ( <div>欢迎{user.name}!<a href="/api/auth/logout">注销</a> </div>); } 返回<a href="/api/auth/login">登录</a>;}
接下来的 linting 规则可能建议使用
Link
组件而不是锚标记。Link
组件旨在执行页面之间的客户端转换。由于链接指向 API 路由而不是页面,因此您应该将它们保留为锚标记。
应用程序目录中的服务器组件(包括页面和布局)无法写入 cookie。
如果您仅依赖服务器组件来读取和更新会话,您应该注意以下事项:
如果您有滚动会话(此 SDK 的默认设置),则当用户访问您的网站时,到期日期不会更新。因此会话可能会比您预期的更早过期(您可以使用withMiddlewareAuthRequired
来缓解这种情况)。
如果刷新访问令牌,新的访问令牌将不会保留在会话中。因此,后续尝试获取访问令牌将始终导致刷新会话中过期的访问令牌。
如果您对会话进行任何其他更新,它们将不会在请求之间保留。
cookie可以从中间件、路由处理程序和服务器操作写入。
有关其他综合示例,请参阅 Examples.md 文档。
import * from @auth0/nextjs-auth0
import * from @auth0/nextjs-auth0/edge
配置选项和环境变量
初始化Auth0
处理授权
处理登录
处理回调
处理注销
句柄配置文件
withApiAuthRequired
需要页面验证
获取会话
更新会话
获取访问令牌
withMiddlewareAuthRequired(仅限 Edge)
import * from @auth0/nextjs-auth0/client
用户提供者
使用用户
需要页面验证
import * from @auth0/nextjs-auth0/testing
生成会话Cookie
访问自动生成的 API 文档了解更多详细信息
所有 cookie 将设置为HttpOnly, SameSite=Lax
,如果应用程序的AUTH0_BASE_URL
为https
,则所有 cookie 将设置为Secure
。
HttpOnly
设置将确保客户端 JavaScript 无法访问 cookie,以减少 XSS 攻击的攻击面。
SameSite=Lax
设置将有助于减轻 CSRF 攻击。通过阅读“即将发生的浏览器行为变化:开发人员需要了解的内容”博客文章,了解有关 SameSite 的更多信息。
许多托管提供商将提供在边缘缓存您的内容的服务,以便尽快向您的用户提供数据。例如,如果您在响应中提供必要的缓存标头,Vercel 将在 Vercel Edge Network 上缓存所有静态内容和无服务器功能的内容。
缓存任何需要身份验证的响应通常是一个坏主意,即使响应的内容看起来可以安全地缓存,但响应中可能还有其他不安全的数据。
默认情况下,此 SDK 提供滚动会话,这意味着读取会话的任何响应都将具有Set-Cookie
标头来更新 cookie 的过期时间。 Vercel 和潜在的其他托管提供商在缓存的响应中包含Set-Cookie
标头,因此即使您认为可以公开缓存响应的内容,响应的Set-Cookie
标头也不能。
检查您的托管提供商的缓存规则,但一般来说,您不应该缓存需要身份验证或什至触摸会话来检查身份验证的响应(例如,当使用withApiAuthRequired
、 withPageAuthRequired
甚至只是getSession
或getAccessToken
时)。
来自redirect_uri
回调中的Auth0 的错误可能包含通过OpenID Connect error
和error_description
查询参数反映的用户输入。因此,我们对IdentityProviderError
的message
、 error
和error_description
属性进行一些基本的转义。
但是,如果您编写自己的错误处理程序,则不应在不使用模板引擎的情况下呈现错误message
或error
和error_description
属性,该模板引擎首先会正确地将它们转义为其他 HTML 上下文。
借助 Next.js,您可以使用基本路径在域的子路径下部署 Next.js 应用程序,并使用国际化路由提供国际化 (i18n) 路由。
如果您使用这些功能,您的应用程序的 url 将发生变化,因此 nextjs-auth0 路由的 url 将发生变化。为了适应这种情况,您可以在 SDK 中的多个位置自定义 url。
例如,如果basePath: '/foo'
您应该将其添加到Auth0Provider
中指定的loginUrl
和profileUrl
之前:
// _app.jsxfunction App({ Component, pageProps }) { return (<UserProvider loginUrl="/foo/api/auth/login" profileUrl="/foo/api/auth/me"> <Component {...pageProps} /></UserProvider> );}
此外,任何登录或注销的链接都应包含basePath
:
<a href="/foo/api/auth/login">登录</a><br /><a href="/foo/api/auth/logout">注销</a>
您应该配置 baseUrl (或AUTH0_BASE_URL
环境变量)。例如:
# .env.localAUTH0_BASE_URL=http://localhost:3000/foo
对于受服务器端 withPageAuthRequired 保护的任何页面,如有必要,您应该根据basePath
和locale
更新returnTo
参数。
// ./pages/my-ssr-page.jsxexport 默认 MySsrPage = () => <></>;const getFullReturnTo = (ctx) => { // TODO: 基于 ctx.resolvedUrl, ctx.locale 实现 getFullReturnTo // 以及你的 next.config.js 的 basePath 和 i18n 设置。 return '/foo/en-US/my-ssr-page';};export const getServerSideProps = (ctx) => { const returnTo = getFullReturnTo(ctx.req); return withPageAuthRequired({ returnTo })(ctx);};
我们还提供了 Auth0 React SDK,auth0-react,它可能适合您的 Next.js 应用程序。
auth0-react
使用的 SPA 安全模型与该 SDK 使用的 Web 应用程序安全模型不同。简而言之,该 SDK 使用 cookie 会话保护页面和 API 路由(请参阅“Cookie 和安全性”)。像auth0-react
这样的 SPA 库将直接在浏览器中存储用户的 ID 令牌和访问令牌,并使用它们直接访问外部 API。
您应该了解这两种模型的安全隐患。但是,如果您满足以下任一场景,auth0-react可能更适合您的需求:
您正在将静态 HTML 导出与 Next.js 结合使用。
您不需要在服务器端渲染期间访问用户数据。
您希望获取访问令牌并直接从前端层调用外部 API,而不是使用 Next.js API 路由作为代理来调用外部 API。
默认情况下,SDK 创建并管理一个在应用程序的生命周期内运行的单例实例。测试应用程序时,您可能需要重置此实例,以便其状态不会在测试之间泄漏。
如果您使用 Jest,我们建议在每次测试后使用jest.resetModules()
。或者,您可以考虑创建自己的 SDK 实例,以便可以在测试之间重新创建它。
对于端到端测试,请查看我们如何使用模拟 OIDC 提供程序。
对于部署,请查看我们如何将示例应用程序部署到 Vercel。
我们感谢对此存储库的反馈和贡献!在开始之前,请阅读以下内容:
Auth0 的一般贡献指南
Auth0 的行为准则指南
本仓库的贡献指南
请不要在公共 GitHub 问题跟踪器上报告安全漏洞。负责任的披露计划详细说明了披露安全问题的程序。
Auth0是一个易于实施、适应性强的身份验证和授权平台。要了解更多信息,请查看为什么选择 Auth0?
该项目已获得 MIT 许可。有关详细信息,请参阅许可证文件。