From 2de5fb91258c556deb92b096ac7f7a0c55baabd5 Mon Sep 17 00:00:00 2001 From: wangsijie Date: Wed, 8 Jan 2025 14:39:18 +0800 Subject: [PATCH] refactor: rewrite next-auth quick start (#961) --- .../framework/next-auth/README.mdx | 43 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ ...{_config-provider.mdx => _integration.mdx} | 112 ++++++++--- .../next-auth/_scopes-and-claims-code.md | 13 -- .../next-auth/_scopes-and-claims.mdx | 5 - .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../fragments/_scopes-claims-introduction.mdx | 37 ++++ .../framework/next-auth/README.mdx | 47 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 182 ++++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../fragments/_scopes-claims-introduction.mdx | 37 ++++ .../framework/next-auth/README.mdx | 45 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 182 ++++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../fragments/_scopes-claims-introduction.md | 4 +- .../framework/next-auth/README.mdx | 43 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 182 ++++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../fragments/_scopes-claims-introduction.md | 8 +- .../framework/next-auth/README.mdx | 43 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 182 ++++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../framework/next-auth/README.mdx | 47 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 182 ++++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ .../fragments/_scopes-claims-introduction.mdx | 37 ++++ .../framework/next-auth/README.mdx | 45 +++-- .../next-auth/_get-user-information.mdx | 128 ++++++++++++ .../framework/next-auth/_installation.mdx | 32 +++ .../framework/next-auth/_integration.mdx | 180 +++++++++++++++++ .../api-resources/_config-api-resources.mdx | 11 ++ .../_fetch-access-token-for-api-resources.mdx | 3 + .../_fetch-organization-token-for-user.mdx | 10 + .../code/_config-organization-code.md | 19 ++ .../code/_config-resources-code.md | 20 ++ .../_config-resources-with-scopes-code.md | 20 ++ ...onfig-resources-with-shared-scopes-code.md | 20 ++ .../code/_get-access-token-code.mdx | 83 ++++++++ .../_get-organization-access-token-code.mdx | 36 ++++ 98 files changed, 4192 insertions(+), 138 deletions(-) create mode 100644 docs/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 docs/quick-starts/framework/next-auth/_installation.mdx rename docs/quick-starts/framework/next-auth/{_config-provider.mdx => _integration.mdx} (58%) delete mode 100644 docs/quick-starts/framework/next-auth/_scopes-and-claims-code.md delete mode 100644 docs/quick-starts/framework/next-auth/_scopes-and-claims.mdx create mode 100644 docs/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 docs/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 docs/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 docs/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx diff --git a/docs/quick-starts/framework/next-auth/README.mdx b/docs/quick-starts/framework/next-auth/README.mdx index 565d7ef008e..7d78f4e394e 100644 --- a/docs/quick-starts/framework/next-auth/README.mdx +++ b/docs/quick-starts/framework/next-auth/README.mdx @@ -1,20 +1,25 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Authentication for Next.js. --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# Add authentication to your Next Auth application +# Add authentication to your Auth.js (Next Auth) application -This guide will show you how to integrate Logto into your Next.js application with [Next Auth](https://next-auth.js.org/). +This guide will show you how to integrate Logto into your Next.js application with [Auth.js](https://authjs.dev/), previously known as Next Auth. @@ -22,21 +27,35 @@ This guide will show you how to integrate Logto into your Next.js application wi - A [Logto Cloud](https://cloud.logto.io) account or a [self-hosted Logto](/introduction/set-up-logto-oss). - A Logto traditional application created. -- A Next.js project with Next Auth, check out the [Next Auth documentation](https://next-auth.js.org/getting-started/introduction). +- A Next.js project with Auth.js, check out the [Auth.js documentation](https://authjs.dev/getting-started/installation). + +## Installation \{#installation} + + ## Integration \{#integration} -### Config Next Auth provider \{#config-next-auth-provider} + + +## Fetch user information \{#fetch-user-information} + + + +## API resources \{#api-resources} + + + +### Configure Logto provider \{#configure-logto-provider} - + -### Checkpoint \{#checkpoint} +### Fetch access token for the API resource \{#fetch-access-token-for-the-api-resource} -Now, you can test your application to see if the authentication works as expected. + -## Scopes and claims \{#scopes-and-claims} +### Fetch organization tokens \{#fetch-organization-tokens} - + ## Further readings \{#further-readings} diff --git a/docs/quick-starts/framework/next-auth/_get-user-information.mdx b/docs/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..25f6e7a4ee0 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### Display user information \{#display-user-information} + +When user is signed in, the return value of `auth()` will be an object containing the user's information. You can display this information in your app: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

Claims:

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
NameValue
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### Request additional claims \{#request-additional-claims} + + + + + +To request additional scopes, you can configure the params of Logto provider: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### Claims that need network requests \{#claims-that-need-network-requests} + +To prevent bloating the ID token, some claims require network requests to fetch. For example, the `custom_data` claim is not included in the user object even if it's requested in the scopes. To access these claims, you need to make a network request to fetch the user info. + +#### Get access token \{#get-access-token} + +Update the `NextAuth` config so that we can get the access token: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // Inject the access token into the session object + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### Fetch user info \{#fetch-user-info} + +Now access the OIDC user info endpoint with the access token: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // Replace the URL with your Logto endpoint, should ends with `/oidc/me` + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +Above is a simple example. Remember to handle the error cases. + +#### Access token refresh \{#access-token-refresh} + +An access token is valid for a short period of time. By defualt, Next.js will only fetch one when the session is created. To implement auto access token refresh, see [Refresh token rotation](https://next-auth.js.org/v3/tutorials/refresh-token-rotation). + +### Scopes and claims \{#scopes-and-claims} + + diff --git a/docs/quick-starts/framework/next-auth/_installation.mdx b/docs/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..447e251dd0e --- /dev/null +++ b/docs/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Install Auth.js via your favorite package manager: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +See [Auth.js documentation](https://authjs.dev/getting-started/installation) for more details. diff --git a/docs/quick-starts/framework/next-auth/_config-provider.mdx b/docs/quick-starts/framework/next-auth/_integration.mdx similarity index 58% rename from docs/quick-starts/framework/next-auth/_config-provider.mdx rename to docs/quick-starts/framework/next-auth/_integration.mdx index 0a3273d4151..5c07f2336b5 100644 --- a/docs/quick-starts/framework/next-auth/_config-provider.mdx +++ b/docs/quick-starts/framework/next-auth/_integration.mdx @@ -7,38 +7,25 @@ import GetAppSecret from '../../fragments/_get-app-secret.mdx'; import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; - - - - -#### Configure sign-in redirect URI \{#configure-sign-in-redirect-uri} - - - -#### Set up Next Auth provider \{#set-up-next-auth-provider} +### Set up Auth.js provider \{#set-up-authjs-provider} -Modify your API route config of Next Auth, if you are using Pages Router, the file is in `pages/api/auth/[...nextauth].js`, if you are using App Router, the file is in `app/api/auth/[...nextauth]/route.ts`. - -The following is an example of App Router: +Modify your API route config of Auth.js, add Logto as an OIDC provider: - + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` -```ts +```ts title="./auth.ts" import NextAuth from 'next-auth'; -export const { - handlers: { GET, POST }, - signIn, - signOut, - auth, -} = NextAuth({ +export const { handlers, signIn, signOut, auth } = NextAuth({ providers: [ { id: 'logto', @@ -70,11 +57,17 @@ export const { 2. Replace the `clientId` and `clientSecret` with your Logto application's ID and secret. 3. Customize the `profile` function to map the user profile to the Next Auth user object, the default mapping is shown in the example. +Then you can also add an optional Middleware to keep the session alive: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + -```ts +```ts title="app/api/auth/[...nextauth]/route.ts" import NextAuth from 'next-auth'; const handler = NextAuth({ @@ -116,3 +109,74 @@ export { handler as GET, handler as POST }; + +You can find more details in the [Auth.js documentation](https://authjs.dev/getting-started/installation). + +### Configure sign-in redirect URI \{#configure-sign-in-redirect-uri} + + + + + + + +### Implement sign-in and sign-out \{#implement-sign-in-and-sign-out} + +#### Implement sign-in and sign-out button \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### Show sign-in and sign-out button in the page \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +Above is a simple example, you can check the [Auth.js documentation](https://authjs.dev/getting-started/session-management/login) for more details. + +### Checkpoint \{#checkpoint} + +Now, you can test your application to see if the authentication works as expected. diff --git a/docs/quick-starts/framework/next-auth/_scopes-and-claims-code.md b/docs/quick-starts/framework/next-auth/_scopes-and-claims-code.md deleted file mode 100644 index ddf7ae41225..00000000000 --- a/docs/quick-starts/framework/next-auth/_scopes-and-claims-code.md +++ /dev/null @@ -1,13 +0,0 @@ -```ts -const handler = NextAuth({ - providers: [ - { - id: 'logto', - name: 'Logto', - // ... other options - authorization: { params: { scope: 'openid offline_access profile email' } }, - // ... other options - }, - ], -}); -``` diff --git a/docs/quick-starts/framework/next-auth/_scopes-and-claims.mdx b/docs/quick-starts/framework/next-auth/_scopes-and-claims.mdx deleted file mode 100644 index 7c4ba9d1799..00000000000 --- a/docs/quick-starts/framework/next-auth/_scopes-and-claims.mdx +++ /dev/null @@ -1,5 +0,0 @@ -import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; - -import ScopesAndClaimsCode from './_scopes-and-claims-code.md'; - -} /> diff --git a/docs/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/docs/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/docs/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/docs/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/docs/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/docs/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/docs/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..c62993a44d4 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/docs/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..34443cb87e4 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js will only fetch the access token once without resource parameter. We need to implement the access token fetching by ourselves. + +#### Get refresh token \{#get-refresh-token} + +Update Logto provider config, add "prompt" parameter and set it to `consent`, and ensure `offline_access` scope is included: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +Then add a callback to save the `refresh_token` to the session: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### Fetch access token \{#fetch-access-token} + +With the `refresh_token`, we can fetch the access token from Logto's OIDC token endpoint. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Replace the app ID and secret with your own, you can check the "Integration" section. + const basicAuth = Buffer.from(':').toString('base64'); + + // Replace the URL with your Logto endpoint, should ends with `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/docs/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/docs/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..163ed67cdf6 --- /dev/null +++ b/docs/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +Similar to the access token for API resources, we can use the refresh token to fetch the organization access token. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Replace the app ID and secret with your own, you can check the "Integration" section. + const basicAuth = Buffer.from(':').toString('base64'); + + // Replace the URL with your Logto endpoint, should ends with `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx new file mode 100644 index 00000000000..8d3dd804811 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx @@ -0,0 +1,37 @@ +Standardmäßig werden begrenzte Ansprüche zurückgegeben. Wenn du mehr Informationen benötigst, kannst du zusätzliche Berechtigungen anfordern, um auf mehr Ansprüche zuzugreifen. + +:::info +Ein "Anspruch (Claim)" ist eine Behauptung über ein Subjekt; eine "Berechtigung (Scope)" ist eine Gruppe von Ansprüchen. Im aktuellen Fall ist ein Anspruch ein Informationsstück über den Benutzer. +::: + +Hier ist ein nicht-normatives Beispiel für die Beziehung zwischen Berechtigung und Anspruch: + +```mermaid +classDiagram + class openid { + +sub + } + + class profile { + +name + +username + +picture + +... + } + + class email { + +email + +email_verified + } + + class phone { + +phone_number + +phone_number_verified + } +``` + +:::tip +Der "sub"-Anspruch bedeutet "Subjekt", was der eindeutige Identifikator des Benutzers ist (d. h. Benutzer-ID). +::: + +Das Logto SDK wird immer drei Berechtigungen anfordern: `openid`, `profile` und `offline_access`. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index b2839a2447f..feb96b8898e 100644 --- a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,42 +1,61 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Authentifizierung für Next.js. --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# Authentifizierung zu deiner Next Auth-Anwendung hinzufügen +# Authentifizierung zu deiner Auth.js (Next Auth)-Anwendung hinzufügen -Dieser Leitfaden zeigt dir, wie du Logto in deine Next.js-Anwendung mit [Next Auth](https://next-auth.js.org/) integrierst. +Dieser Leitfaden zeigt dir, wie du Logto in deine Next.js-Anwendung mit [Auth.js](https://authjs.dev/) integrierst, früher bekannt als Next Auth. ## Voraussetzungen \{#prerequisites} -- Ein [Logto Cloud](https://cloud.logto.io) Konto oder ein [selbst gehostetes Logto](/introduction/set-up-logto-oss). -- Eine Logto-Traditionelle Anwendung erstellt. -- Ein Next.js-Projekt mit Next Auth, siehe die [Next Auth Dokumentation](https://next-auth.js.org/getting-started/introduction). +- Ein [Logto Cloud](https://cloud.logto.io)-Konto oder ein [selbst gehostetes Logto](/introduction/set-up-logto-oss). +- Eine erstellte traditionelle Logto-Anwendung. +- Ein Next.js-Projekt mit Auth.js, siehe die [Auth.js-Dokumentation](https://authjs.dev/getting-started/installation). + +## Installation \{#installation} + + ## Integration \{#integration} -### Next Auth-Anbieter konfigurieren \{#config-next-auth-provider} + + +## Benutzerinformationen abrufen \{#fetch-user-information} + + + +## API-Ressourcen \{#api-resources} + + + +### Logto-Anbieter konfigurieren \{#configure-logto-provider} - + -### Kontrollpunkt \{#checkpoint} +### Zugangstoken für die API-Ressource abrufen \{#fetch-access-token-for-the-api-resource} -Jetzt kannst du deine Anwendung testen, um zu sehen, ob die Authentifizierung wie erwartet funktioniert. + -## Berechtigungen und Ansprüche \{#scopes-and-claims} +### Organisationstokens abrufen \{#fetch-organization-tokens} - + ## Weiterführende Lektüre \{#further-readings} diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..1be7232e00e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### Benutzerinformationen anzeigen \{#display-user-information} + +Wenn der Benutzer angemeldet ist, wird der Rückgabewert von `auth()` ein Objekt sein, das die Informationen des Benutzers enthält. Du kannst diese Informationen in deiner App anzeigen: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

Ansprüche (Claims):

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
NameWert
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### Zusätzliche Ansprüche anfordern \{#request-additional-claims} + + + + + +Um zusätzliche Berechtigungen anzufordern, kannst du die Parameter des Logto-Providers konfigurieren: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### Ansprüche, die Netzwerk-Anfragen benötigen \{#claims-that-need-network-requests} + +Um das Aufblähen des ID-Tokens zu verhindern, erfordern einige Ansprüche Netzwerk-Anfragen, um sie abzurufen. Zum Beispiel ist der `custom_data` Anspruch nicht im Benutzerobjekt enthalten, selbst wenn er in den Berechtigungen angefordert wird. Um auf diese Ansprüche zuzugreifen, musst du eine Netzwerk-Anfrage stellen, um die Benutzerinformationen abzurufen. + +#### Zugangstoken erhalten \{#get-access-token} + +Aktualisiere die `NextAuth`-Konfiguration, damit wir das Zugangstoken erhalten können: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // Injektion des Zugangstokens in das Sitzungsobjekt + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### Benutzerinformationen abrufen \{#fetch-user-info} + +Greife nun mit dem Zugangstoken auf den OIDC-Benutzerinfo-Endpunkt zu: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // Ersetze die URL mit deinem Logto-Endpunkt, sollte mit `/oidc/me` enden + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +Oben ist ein einfaches Beispiel. Denke daran, die Fehlerfälle zu behandeln. + +#### Zugangstoken-Auffrischung \{#access-token-refresh} + +Ein Zugangstoken ist nur für einen kurzen Zeitraum gültig. Standardmäßig wird Next.js nur eines abrufen, wenn die Sitzung erstellt wird. Um eine automatische Zugangstoken-Auffrischung zu implementieren, siehe [Refresh token rotation](https://next-auth.js.org/v3/tutorials/refresh-token-rotation). + +### Berechtigungen und Ansprüche \{#scopes-and-claims} + + diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..f7b3ab3ed3d --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Installiere Auth.js über deinen bevorzugten Paketmanager: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +Siehe [Auth.js Dokumentation](https://authjs.dev/getting-started/installation) für weitere Details. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..f159b0cbe62 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,182 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### Auth.js-Provider einrichten \{#set-up-authjs-provider} + + + +Modifiziere deine API-Routen-Konfiguration von Auth.js und füge Logto als OIDC-Provider hinzu: + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // Du kannst den Ausstellerwert von der Logto-Anwendungsdetailseite erhalten, + // im Feld "Issuer endpoint" + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // Du kannst hier die Zuordnung des Benutzerprofils anpassen + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. Ersetze die `issuer` URL durch den "Issuer endpoint" deiner Logto-Anwendung. +2. Ersetze die `clientId` und `clientSecret` durch die ID und das Geheimnis deiner Logto-Anwendung. +3. Passe die `profile` Funktion an, um das Benutzerprofil auf das Next Auth-Benutzerobjekt abzubilden, die Standardzuordnung ist im Beispiel gezeigt. + +Dann kannst du auch eine optionale Middleware hinzufügen, um die Sitzung am Leben zu halten: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // Du kannst die bekannte URL von der Logto-Anwendungsdetailseite erhalten, + // im Feld "OpenID Provider configuration endpoint" + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // Du kannst hier die Zuordnung des Benutzerprofils anpassen + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. Ersetze die `wellKnown` URL durch den "OpenID Provider configuration endpoint" deiner Logto-Anwendung. +2. Ersetze die `clientId` und `clientSecret` durch die ID und das Geheimnis deiner Logto-Anwendung. +3. Passe die `profile` Funktion an, um das Benutzerprofil auf das Next Auth-Benutzerobjekt abzubilden, die Standardzuordnung ist im Beispiel gezeigt. +4. Denke daran, den `id_token_signed_response_alg` auf `ES384` zu setzen. + + + + + +Weitere Details findest du in der [Auth.js-Dokumentation](https://authjs.dev/getting-started/installation). + +### Anmelde-Redirect-URI konfigurieren \{#configure-sign-in-redirect-uri} + + + + + + + +### Anmeldung und Abmeldung implementieren \{#implement-sign-in-and-sign-out} + +#### Anmelde- und Abmeldebutton implementieren \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### Anmelde- und Abmeldebutton auf der Seite anzeigen \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +Oben ist ein einfaches Beispiel, du kannst die [Auth.js-Dokumentation](https://authjs.dev/getting-started/session-management/login) für weitere Details einsehen. + +### Checkpoint \{#checkpoint} + +Jetzt kannst du deine Anwendung testen, um zu sehen, ob die Authentifizierung wie erwartet funktioniert. diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..eea4f23cbb5 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..91784265100 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..48894b407e9 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..9ea22501f69 --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..93385b5e50e --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js wird das Zugangstoken nur einmal ohne Ressourcenparameter abrufen. Wir müssen das Abrufen des Zugangstokens selbst implementieren. + +#### Auffrischungstoken erhalten \{#get-refresh-token} + +Aktualisiere die Logto-Provider-Konfiguration, füge den "prompt"-Parameter hinzu und setze ihn auf `consent`, und stelle sicher, dass der `offline_access`-Berechtigung enthalten ist: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +Füge dann einen Callback hinzu, um das `refresh_token` in der Sitzung zu speichern: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### Zugangstoken abrufen \{#fetch-access-token} + +Mit dem `refresh_token` können wir das Zugangstoken vom Logto OIDC-Token-Endpunkt abrufen. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Ersetze die App-ID und das Geheimnis durch deine eigenen, du kannst den Abschnitt "Integration" überprüfen. + const basicAuth = Buffer.from(':').toString('base64'); + + // Ersetze die URL mit deinem Logto-Endpunkt, sollte mit `/oidc/token` enden + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..baf4d7482dd --- /dev/null +++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +Ähnlich wie das Zugangstoken für API-Ressourcen können wir das Auffrischungstoken verwenden, um das Organisations-Zugangstoken abzurufen. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Ersetze die App-ID und das Geheimnis durch deine eigenen, du kannst den Abschnitt "Integration" überprüfen. + const basicAuth = Buffer.from(':').toString('base64'); + + // Ersetze die URL mit deinem Logto-Endpunkt, sollte mit `/oidc/token` enden + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx new file mode 100644 index 00000000000..cccaf40f8c2 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx @@ -0,0 +1,37 @@ +De forma predeterminada, se devuelven reclamos limitados. Si necesitas más información, puedes solicitar alcances adicionales para acceder a más reclamos. + +:::info +Un "reclamo (Claim)" es una afirmación hecha sobre un sujeto; un "alcance (Scope)" es un grupo de reclamos. En el caso actual, un reclamo es una pieza de información sobre el usuario. +::: + +Aquí tienes un ejemplo no normativo de la relación alcance - reclamo: + +```mermaid +classDiagram + class openid { + +sub + } + + class profile { + +name + +username + +picture + +... + } + + class email { + +email + +email_verified + } + + class phone { + +phone_number + +phone_number_verified + } +``` + +:::tip +El reclamo "sub" significa "sujeto", que es el identificador único del usuario (es decir, ID de usuario). +::: + +El SDK de Logto siempre solicitará tres alcances: `openid`, `profile` y `offline_access`. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index 5fe5851eb52..2bffb95f4fd 100644 --- a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,20 +1,25 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Autenticación para Next.js. --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# Añade autenticación a tu aplicación Next Auth +# Añade autenticación a tu aplicación Auth.js (Next Auth) -Esta guía te mostrará cómo integrar Logto en tu aplicación Next.js con [Next Auth](https://next-auth.js.org/). +Esta guía te mostrará cómo integrar Logto en tu aplicación Next.js con [Auth.js](https://authjs.dev/), anteriormente conocido como Next Auth. @@ -22,26 +27,40 @@ Esta guía te mostrará cómo integrar Logto en tu aplicación Next.js con [Next - Una cuenta de [Logto Cloud](https://cloud.logto.io) o un [Logto autoalojado](/introduction/set-up-logto-oss). - Una aplicación tradicional de Logto creada. -- Un proyecto Next.js con Next Auth, consulta la [documentación de Next Auth](https://next-auth.js.org/getting-started/introduction). +- Un proyecto Next.js con Auth.js, consulta la [documentación de Auth.js](https://authjs.dev/getting-started/installation). + +## Instalación \{#installation} + + ## Integración \{#integration} -### Configurar el proveedor de Next Auth \{#config-next-auth-provider} + + +## Obtener información del usuario \{#fetch-user-information} + + + +## Recursos de API \{#api-resources} + + + +### Configurar el proveedor Logto \{#configure-logto-provider} - + -### Punto de control \{#checkpoint} +### Obtener token de acceso para el recurso de API \{#fetch-access-token-for-the-api-resource} -Ahora, puedes probar tu aplicación para ver si la autenticación funciona como se espera. + -## Alcances y reclamos \{#scopes-and-claims} +### Obtener tokens de organización \{#fetch-organization-tokens} - + ## Lecturas adicionales \{#further-readings} - Migración de la integración de Logto de NextAuth.js v4 a v5 + Migrando la integración de Logto de NextAuth.js v4 a v5 diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..9cd9c382454 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### Mostrar información del usuario \{#display-user-information} + +Cuando el usuario ha iniciado sesión, el valor de retorno de `auth()` será un objeto que contiene la información del usuario. Puedes mostrar esta información en tu aplicación: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

Reclamos (Claims):

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
NombreValor
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### Solicitar reclamos adicionales \{#request-additional-claims} + + + + + +Para solicitar alcances adicionales, puedes configurar los parámetros del proveedor de Logto: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### Reclamos que necesitan solicitudes de red \{#claims-that-need-network-requests} + +Para evitar sobrecargar el Token de ID, algunos reclamos requieren solicitudes de red para ser obtenidos. Por ejemplo, el reclamo `custom_data` no está incluido en el objeto de usuario incluso si se solicita en los alcances. Para acceder a estos reclamos, necesitas hacer una solicitud de red para obtener la información del usuario. + +#### Obtener token de acceso \{#get-access-token} + +Actualiza la configuración de `NextAuth` para que podamos obtener el token de acceso: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // Inyecta el token de acceso en el objeto de sesión + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### Obtener información del usuario \{#fetch-user-info} + +Ahora accede al endpoint de información del usuario OIDC con el token de acceso: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // Reemplaza la URL con tu endpoint de Logto, debe terminar con `/oidc/me` + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +Arriba hay un ejemplo simple. Recuerda manejar los casos de error. + +#### Actualización del token de acceso \{#access-token-refresh} + +Un token de acceso es válido por un corto período de tiempo. Por defecto, Next.js solo obtendrá uno cuando se crea la sesión. Para implementar la actualización automática del token de acceso, consulta [Rotación de token de actualización](https://next-auth.js.org/v3/tutorials/refresh-token-rotation). + +### Alcances y reclamos \{#scopes-and-claims} + + diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..c3ce1baeb5c --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instala Auth.js a través de tu gestor de paquetes favorito: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +Consulta la [documentación de Auth.js](https://authjs.dev/getting-started/installation) para más detalles. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..93b05ea8571 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,182 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### Configura el proveedor Auth.js \{#set-up-authjs-provider} + + + +Modifica la configuración de la ruta de tu API de Auth.js, añade Logto como un proveedor OIDC: + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // Puedes obtener el valor del emisor desde la página de Detalles de la Aplicación de Logto, + // en el campo "Punto final del emisor" + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // Puedes personalizar el mapeo del perfil de usuario aquí + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. Reemplaza la URL del `issuer` con el "Punto final del emisor" de tu aplicación Logto. +2. Reemplaza el `clientId` y el `clientSecret` con el ID y el secreto de tu aplicación Logto. +3. Personaliza la función `profile` para mapear el perfil de usuario al objeto de usuario de Next Auth, el mapeo predeterminado se muestra en el ejemplo. + +Luego, también puedes añadir un Middleware opcional para mantener la sesión activa: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // Puedes obtener la URL conocida desde la página de Detalles de la Aplicación de Logto, + // en el campo "Punto final de configuración del proveedor OpenID" + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // Puedes personalizar el mapeo del perfil de usuario aquí + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. Reemplaza la URL de `wellKnown` con el "Punto final de configuración del proveedor OpenID" de tu aplicación Logto. +2. Reemplaza el `clientId` y el `clientSecret` con el ID y el secreto de tu aplicación Logto. +3. Personaliza la función `profile` para mapear el perfil de usuario al objeto de usuario de Next Auth, el mapeo predeterminado se muestra en el ejemplo. +4. Recuerda establecer el `id_token_signed_response_alg` en `ES384`. + + + + + +Puedes encontrar más detalles en la [documentación de Auth.js](https://authjs.dev/getting-started/installation). + +### Configura el URI de redirección de inicio de sesión \{#configure-sign-in-redirect-uri} + + + + + + + +### Implementa el inicio y cierre de sesión \{#implement-sign-in-and-sign-out} + +#### Implementa el botón de inicio y cierre de sesión \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### Muestra el botón de inicio y cierre de sesión en la página \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +Arriba hay un ejemplo simple, puedes consultar la [documentación de Auth.js](https://authjs.dev/getting-started/session-management/login) para más detalles. + +### Punto de control \{#checkpoint} + +Ahora, puedes probar tu aplicación para ver si la autenticación funciona como se espera. diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..eea4f23cbb5 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..82313d06942 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js solo obtendrá el token de acceso una vez sin el parámetro de recurso. Necesitamos implementar la obtención del token de acceso por nosotros mismos. + +#### Obtener token de actualización \{#get-refresh-token} + +Actualiza la configuración del proveedor de Logto, añade el parámetro "prompt" y configúralo en `consent`, y asegúrate de que el alcance `offline_access` esté incluido: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +Luego añade un callback para guardar el `refresh_token` en la sesión: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### Obtener token de acceso \{#fetch-access-token} + +Con el `refresh_token`, podemos obtener el token de acceso desde el endpoint de token OIDC de Logto. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Reemplaza el ID y el secreto de la aplicación con los tuyos propios, puedes verificar la sección "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Reemplaza la URL con tu endpoint de Logto, debe terminar con `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..69cd0d90d17 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +Similar al token de acceso para recursos de API, podemos usar el token de actualización para obtener el token de acceso de la organización. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Reemplaza el ID y el secreto de la aplicación con los tuyos, puedes verificar la sección "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Reemplaza la URL con tu endpoint de Logto, debe terminar con `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md index 746ab6b6c36..1dc75b98cc4 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md @@ -1,7 +1,7 @@ Par défaut, des revendications limitées sont retournées. Si vous avez besoin de plus d'informations, vous pouvez demander des portées supplémentaires pour accéder à plus de revendications. :::info -Une "revendication" est une assertion faite à propos d'un sujet ; une "portée" est un groupe de revendications. Dans le cas actuel, une revendication est une information sur l'utilisateur. +Une "revendication" est une affirmation faite à propos d'un sujet ; une "portée" est un groupe de revendications. Dans le cas actuel, une revendication est une information sur l'utilisateur. ::: Voici un exemple non normatif de la relation portée - revendication : @@ -34,4 +34,4 @@ classDiagram La revendication "sub" signifie "sujet", qui est l'identifiant unique de l'utilisateur (c'est-à-dire l'ID utilisateur). ::: -Le SDK Logto demandera toujours trois portées : `openid`, `profile` et `offline_access`. +Le SDK Logto demandera toujours trois portées : `openid`, `profile`, et `offline_access`. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index 550e768e429..38a539671ae 100644 --- a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,20 +1,25 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Authentification pour Next.js. --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# Ajoutez l’authentification à votre application Next Auth +# Ajoutez l’authentification à votre application Auth.js (Next Auth) -Ce guide vous montrera comment intégrer Logto dans votre application Next.js avec [Next Auth](https://next-auth.js.org/). +Ce guide vous montrera comment intégrer Logto dans votre application Next.js avec [Auth.js](https://authjs.dev/), précédemment connu sous le nom de Next Auth. @@ -22,21 +27,35 @@ Ce guide vous montrera comment intégrer Logto dans votre application Next.js av - Un compte [Logto Cloud](https://cloud.logto.io) ou un [Logto auto-hébergé](/introduction/set-up-logto-oss). - Une application traditionnelle Logto créée. -- Un projet Next.js avec Next Auth, consultez la [documentation Next Auth](https://next-auth.js.org/getting-started/introduction). +- Un projet Next.js avec Auth.js, consultez la [documentation Auth.js](https://authjs.dev/getting-started/installation). + +## Installation \{#installation} + + ## Intégration \{#integration} -### Configurer le fournisseur Next Auth \{#config-next-auth-provider} + + +## Récupérer les informations utilisateur \{#fetch-user-information} + + + +## Ressources API \{#api-resources} + + + +### Configurer le fournisseur Logto \{#configure-logto-provider} - + -### Point de contrôle \{#checkpoint} +### Récupérer le jeton d’accès pour la ressource API \{#fetch-access-token-for-the-api-resource} -Vous pouvez maintenant tester votre application pour voir si l'authentification fonctionne comme prévu. + -## Portées et revendications \{#scopes-and-claims} +### Récupérer les jetons d’organisation \{#fetch-organization-tokens} - + ## Lectures complémentaires \{#further-readings} diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..cd229eb2e19 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### Afficher les informations de l'utilisateur \{#display-user-information} + +Lorsque l'utilisateur est connecté, la valeur de retour de `auth()` sera un objet contenant les informations de l'utilisateur. Vous pouvez afficher ces informations dans votre application : + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

Revendications :

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
NomValeur
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### Demander des revendications supplémentaires \{#request-additional-claims} + + + + + +Pour demander des portées supplémentaires, vous pouvez configurer les paramètres du fournisseur Logto : + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### Revendications nécessitant des requêtes réseau \{#claims-that-need-network-requests} + +Pour éviter de surcharger le jeton d’identifiant, certaines revendications nécessitent des requêtes réseau pour être récupérées. Par exemple, la revendication `custom_data` n'est pas incluse dans l'objet utilisateur même si elle est demandée dans les portées. Pour accéder à ces revendications, vous devez effectuer une requête réseau pour récupérer les informations de l'utilisateur. + +#### Obtenir le jeton d’accès \{#get-access-token} + +Mettez à jour la configuration `NextAuth` pour que nous puissions obtenir le jeton d’accès : + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // Injecter le jeton d’accès dans l'objet session + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### Récupérer les informations de l'utilisateur \{#fetch-user-info} + +Accédez maintenant au point de terminaison des informations utilisateur OIDC avec le jeton d’accès : + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // Remplacez l'URL par votre point de terminaison Logto, doit se terminer par `/oidc/me` + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +Ci-dessus est un exemple simple. N'oubliez pas de gérer les cas d'erreur. + +#### Rafraîchissement du jeton d’accès \{#access-token-refresh} + +Un jeton d’accès est valide pour une courte période de temps. Par défaut, Next.js n'en récupérera qu'un lorsque la session est créée. Pour implémenter le rafraîchissement automatique du jeton d’accès, voir [Rotation du jeton de rafraîchissement](https://next-auth.js.org/v3/tutorials/refresh-token-rotation). + +### Portées et revendications \{#scopes-and-claims} + + diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..64e135a8ef5 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Installez Auth.js via votre gestionnaire de paquets préféré : + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +Voir la [documentation Auth.js](https://authjs.dev/getting-started/installation) pour plus de détails. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..613df454b56 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,182 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### Configurer le fournisseur Auth.js \{#set-up-authjs-provider} + + + +Modifiez votre configuration de route API d'Auth.js, ajoutez Logto en tant que fournisseur OIDC : + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // Vous pouvez obtenir la valeur de l'émetteur depuis la page Détails de l'application Logto, + // dans le champ "Endpoint de l'émetteur" + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // Vous pouvez personnaliser le mappage du profil utilisateur ici + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. Remplacez l'URL `issuer` par le "Endpoint de l'émetteur" de votre application Logto. +2. Remplacez le `clientId` et le `clientSecret` par l'ID et le secret de votre application Logto. +3. Personnalisez la fonction `profile` pour mapper le profil utilisateur à l'objet utilisateur de Next Auth, le mappage par défaut est montré dans l'exemple. + +Ensuite, vous pouvez également ajouter un Middleware optionnel pour maintenir la session active : + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // Vous pouvez obtenir l'URL bien connue depuis la page Détails de l'application Logto, + // dans le champ "Endpoint de configuration du fournisseur OpenID" + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // Vous pouvez personnaliser le mappage du profil utilisateur ici + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. Remplacez l'URL `wellKnown` par le "Endpoint de configuration du fournisseur OpenID" de votre application Logto. +2. Remplacez le `clientId` et le `clientSecret` par l'ID et le secret de votre application Logto. +3. Personnalisez la fonction `profile` pour mapper le profil utilisateur à l'objet utilisateur de Next Auth, le mappage par défaut est montré dans l'exemple. +4. N'oubliez pas de définir le `id_token_signed_response_alg` sur `ES384`. + + + + + +Vous pouvez trouver plus de détails dans la [documentation Auth.js](https://authjs.dev/getting-started/installation). + +### Configurer l'URI de redirection de connexion \{#configure-sign-in-redirect-uri} + + + + + + + +### Implémenter la connexion et la déconnexion \{#implement-sign-in-and-sign-out} + +#### Implémenter le bouton de connexion et de déconnexion \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### Afficher le bouton de connexion et de déconnexion sur la page \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +Ci-dessus est un exemple simple, vous pouvez consulter la [documentation Auth.js](https://authjs.dev/getting-started/session-management/login) pour plus de détails. + +### Point de contrôle \{#checkpoint} + +Maintenant, vous pouvez tester votre application pour voir si l'authentification fonctionne comme prévu. diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..eea4f23cbb5 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..19a8135b6a4 --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js ne récupérera le jeton d’accès qu'une seule fois sans paramètre de ressource. Nous devons implémenter nous-mêmes la récupération du jeton d’accès. + +#### Obtenir le jeton de rafraîchissement \{#get-refresh-token} + +Mettez à jour la configuration du fournisseur Logto, ajoutez le paramètre "prompt" et définissez-le sur `consent`, et assurez-vous que la portée `offline_access` est incluse : + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +Ajoutez ensuite un callback pour enregistrer le `refresh_token` dans la session : + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### Récupérer le jeton d’accès \{#fetch-access-token} + +Avec le `refresh_token`, nous pouvons récupérer le jeton d’accès à partir du point de terminaison de jeton OIDC de Logto. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Remplacez l'ID et le secret de l'application par les vôtres, vous pouvez vérifier la section "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Remplacez l'URL par votre point de terminaison Logto, doit se terminer par `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..51a0a25f56f --- /dev/null +++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +Similaire au jeton d’accès pour les ressources API, nous pouvons utiliser le jeton de rafraîchissement pour récupérer le jeton d’accès de l’organisation. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Remplacez l'ID et le secret de l'application par les vôtres, vous pouvez vérifier la section "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Remplacez l'URL par votre point de terminaison Logto, elle doit se terminer par `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md index 79162e901ca..51140373883 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.md @@ -1,10 +1,10 @@ -デフォルトでは、限られたクレーム (Claim) が返されます。より多くの情報が必要な場合は、追加のスコープ (Scope) をリクエストして、より多くのクレーム (Claim) にアクセスできます。 +デフォルトでは、限られたクレーム (Claims) が返されます。より多くの情報が必要な場合は、追加のスコープ (Scopes) をリクエストして、より多くのクレーム (Claims) にアクセスできます。 :::info -「クレーム (Claim)」はサブジェクトについての主張であり、「スコープ (Scope)」はクレーム (Claim) のグループです。現在のケースでは、クレーム (Claim) はユーザーに関する情報の一部です。 +「クレーム (Claim)」はサブジェクトについての主張であり、「スコープ (Scope)」はクレーム (Claims) のグループです。現在のケースでは、クレーム (Claim) はユーザーに関する情報の一部です。 ::: -スコープ - クレーム (Claim) 関係の非規範的な例を示します: +スコープ (Scope) とクレーム (Claim) の関係の非規範的な例を示します: ```mermaid classDiagram @@ -34,4 +34,4 @@ classDiagram 「sub」クレーム (Claim) は「サブジェクト (Subject)」を意味し、ユーザーの一意の識別子(つまり、ユーザー ID)です。 ::: -Logto SDK は常に 3 つのスコープ (Scope) をリクエストします:`openid`、`profile`、および `offline_access`。 +Logto SDK は常に 3 つのスコープ (Scopes) をリクエストします:`openid`、`profile`、および `offline_access`。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index e837a084182..7f1e4ae8665 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,20 +1,25 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Next.js のための認証 (Authentication)。 --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# あなたの Next Auth アプリケーションに認証 (Authentication) を追加する +# あなたの Auth.js (Next Auth) アプリケーションに認証 (Authentication) を追加する -このガイドでは、[Next Auth](https://next-auth.js.org/) を使用して Logto を Next.js アプリケーションに統合する方法を紹介します。 +このガイドでは、以前は Next Auth として知られていた [Auth.js](https://authjs.dev/) を使用して、Logto を Next.js アプリケーションに統合する方法を紹介します。 @@ -22,21 +27,35 @@ import ScopesAndClaims from './_scopes-and-claims.mdx'; - [Logto Cloud](https://cloud.logto.io) アカウントまたは [セルフホスト Logto](/introduction/set-up-logto-oss)。 - 作成された Logto の従来のアプリケーション。 -- Next Auth を使用した Next.js プロジェクト。詳細は [Next Auth ドキュメント](https://next-auth.js.org/getting-started/introduction) を参照してください。 +- Auth.js を使用した Next.js プロジェクト、[Auth.js ドキュメント](https://authjs.dev/getting-started/installation)を確認してください。 + +## インストール \{#installation} + + ## 統合 \{#integration} -### Next Auth プロバイダーの設定 \{#config-next-auth-provider} + + +## ユーザー情報の取得 \{#fetch-user-information} + + + +## API リソース \{#api-resources} + + + +### Logto プロバイダーの設定 \{#configure-logto-provider} - + -### チェックポイント \{#checkpoint} +### API リソースのためのアクセス トークンの取得 \{#fetch-access-token-for-the-api-resource} -これで、アプリケーションをテストして、認証 (Authentication) が期待通りに動作するか確認できます。 + -## スコープとクレーム \{#scopes-and-claims} +### 組織トークンの取得 \{#fetch-organization-tokens} - + ## さらなる読み物 \{#further-readings} diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..59cdbca755f --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### ユーザー情報を表示する \{#display-user-information} + +ユーザーがサインインすると、`auth()` の戻り値はユーザー情報を含むオブジェクトになります。この情報をアプリで表示できます: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

クレーム (Claims):

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
名前
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### 追加のクレーム (Claims) をリクエストする \{#request-additional-claims} + + + + + +追加のスコープをリクエストするには、Logto プロバイダーのパラメータを設定します: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### ネットワークリクエストが必要なクレーム (Claims) \{#claims-that-need-network-requests} + +ID トークンの肥大化を防ぐために、一部のクレーム (Claims) は取得するためにネットワークリクエストが必要です。例えば、`custom_data` クレーム (Claim) はスコープでリクエストされてもユーザーオブジェクトに含まれません。これらのクレーム (Claims) にアクセスするには、ユーザー情報を取得するためのネットワークリクエストを行う必要があります。 + +#### アクセス トークンを取得する \{#get-access-token} + +`NextAuth` の設定を更新して、アクセス トークンを取得できるようにします: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // アクセス トークンをセッションオブジェクトに注入する + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### ユーザー情報を取得する \{#fetch-user-info} + +次に、アクセス トークンを使用して OIDC ユーザー情報エンドポイントにアクセスします: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // URL をあなたの Logto エンドポイントに置き換え、`/oidc/me` で終わる必要があります + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +上記は簡単な例です。エラーケースを処理することを忘れないでください。 + +#### アクセス トークンのリフレッシュ \{#access-token-refresh} + +アクセス トークンは短期間のみ有効です。デフォルトでは、Next.js はセッションが作成されたときにのみ取得します。自動アクセス トークンリフレッシュを実装するには、[リフレッシュ トークンのローテーション](https://next-auth.js.org/v3/tutorials/refresh-token-rotation) を参照してください。 + +### スコープとクレーム (Claims) \{#scopes-and-claims} + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..73f6b1a427c --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +お気に入りのパッケージマネージャーを使用して Auth.js をインストールします: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +詳細については、 [Auth.js のドキュメント](https://authjs.dev/getting-started/installation) を参照してください。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..07007cf3870 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,182 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### Auth.js プロバイダーを設定する \{#set-up-authjs-provider} + + + +Auth.js の API ルート設定を変更し、Logto を OIDC プロバイダーとして追加します: + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // Logto アプリケーションの詳細ページから発行者 (Issuer) の値を取得できます。 + // フィールド「Issuer endpoint」にあります。 + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // ユーザープロファイルのマッピングをここでカスタマイズできます + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. `issuer` URL をあなたの Logto アプリケーションの「Issuer endpoint」に置き換えます。 +2. `clientId` と `clientSecret` をあなたの Logto アプリケーションの ID とシークレットに置き換えます。 +3. ユーザープロファイルを Next Auth ユーザーオブジェクトにマッピングするために `profile` 関数をカスタマイズします。デフォルトのマッピングは例に示されています。 + +次に、セッションを維持するためのオプションのミドルウェアを追加することもできます: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // Logto アプリケーションの詳細ページから well-known URL を取得できます。 + // フィールド「OpenID Provider configuration endpoint」にあります。 + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // ユーザープロファイルのマッピングをここでカスタマイズできます + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. `wellKnown` URL をあなたの Logto アプリケーションの「OpenID Provider configuration endpoint」に置き換えます。 +2. `clientId` と `clientSecret` をあなたの Logto アプリケーションの ID とシークレットに置き換えます。 +3. ユーザープロファイルを Next Auth ユーザーオブジェクトにマッピングするために `profile` 関数をカスタマイズします。デフォルトのマッピングは例に示されています。 +4. `id_token_signed_response_alg` を `ES384` に設定することを忘れないでください。 + + + + + +詳細は [Auth.js ドキュメント](https://authjs.dev/getting-started/installation) を参照してください。 + +### サインインリダイレクト URI を設定する \{#configure-sign-in-redirect-uri} + + + + + + + +### サインインとサインアウトを実装する \{#implement-sign-in-and-sign-out} + +#### サインインとサインアウトボタンを実装する \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### ページにサインインとサインアウトボタンを表示する \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +上記はシンプルな例です。詳細は [Auth.js ドキュメント](https://authjs.dev/getting-started/session-management/login) を参照してください。 + +### チェックポイント \{#checkpoint} + +これで、認証 (Authentication) が期待通りに機能するかどうかを確認するためにアプリケーションをテストできます。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..eea4f23cbb5 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..5dc7d26018a --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js はリソースパラメーターなしでアクセス トークンを一度だけ取得します。アクセス トークンの取得を自分で実装する必要があります。 + +#### リフレッシュ トークンを取得する \{#get-refresh-token} + +Logto プロバイダーの設定を更新し、「prompt」パラメーターを追加して `consent` に設定し、`offline_access` スコープが含まれていることを確認します: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +次に、`refresh_token` をセッションに保存するコールバックを追加します: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### アクセス トークンを取得する \{#fetch-access-token} + +`refresh_token` を使用して、Logto の OIDC トークンエンドポイントからアクセス トークンを取得できます。 + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // アプリ ID とシークレットを自分のものに置き換えてください。「Integration」セクションを確認できます。 + const basicAuth = Buffer.from(':').toString('base64'); + + // URL を Logto エンドポイントに置き換えてください。`/oidc/token` で終わる必要があります + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..250379e2a17 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +API リソースのアクセス トークンと同様に、リフレッシュ トークンを使用して組織アクセス トークンを取得できます。 + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // アプリ ID とシークレットを自分のものに置き換えてください。「Integration」セクションを確認できます。 + const basicAuth = Buffer.from(':').toString('base64'); + + // URL を Logto エンドポイントに置き換えてください。`/oidc/token` で終わる必要があります。 + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index 1efe8ae0cbc..695df03624c 100644 --- a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,47 +1,66 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' description: Autenticação para Next.js. --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# Adicionar autenticação ao seu aplicativo Next Auth +# Adicionar autenticação ao seu aplicativo Auth.js (Next Auth) -Este guia mostrará como integrar o Logto em seu aplicativo Next.js com [Next Auth](https://next-auth.js.org/). +Este guia mostrará como integrar o Logto em seu aplicativo Next.js com [Auth.js](https://authjs.dev/), anteriormente conhecido como Next Auth. ## Pré-requisitos \{#prerequisites} -- Uma conta no [Logto Cloud](https://cloud.logto.io) ou um [Logto auto-hospedado](/introduction/set-up-logto-oss). +- Uma conta [Logto Cloud](https://cloud.logto.io) ou um [Logto auto-hospedado](/introduction/set-up-logto-oss). - Um aplicativo tradicional Logto criado. -- Um projeto Next.js com Next Auth, confira a [documentação do Next Auth](https://next-auth.js.org/getting-started/introduction). +- Um projeto Next.js com Auth.js, confira a [documentação do Auth.js](https://authjs.dev/getting-started/installation). + +## Instalação \{#installation} + + ## Integração \{#integration} -### Configurar o provedor Next Auth \{#config-next-auth-provider} + + +## Buscar informações do usuário \{#fetch-user-information} + + + +## Recursos de API \{#api-resources} + + + +### Configurar provedor Logto \{#configure-logto-provider} - + -### Ponto de verificação \{#checkpoint} +### Buscar token de acesso para o recurso de API \{#fetch-access-token-for-the-api-resource} -Agora, você pode testar seu aplicativo para ver se a autenticação funciona como esperado. + -## Escopos e reivindicações \{#scopes-and-claims} +### Buscar tokens de organização \{#fetch-organization-tokens} - + ## Leituras adicionais \{#further-readings} - Migrando a integração Logto do NextAuth.js v4 para v5 + Migrando a integração do Logto do NextAuth.js v4 para v5 diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..e56c3a60726 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### Exibir informações do usuário \{#display-user-information} + +Quando o usuário está autenticado, o valor de retorno de `auth()` será um objeto contendo as informações do usuário. Você pode exibir essas informações em seu aplicativo: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

Reivindicações (Claims):

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
NomeValor
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### Solicitar reivindicações adicionais \{#request-additional-claims} + + + + + +Para solicitar escopos adicionais, você pode configurar os parâmetros do provedor Logto: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### Reivindicações que precisam de solicitações de rede \{#claims-that-need-network-requests} + +Para evitar sobrecarregar o Token de ID, algumas reivindicações requerem solicitações de rede para serem buscadas. Por exemplo, a reivindicação `custom_data` não está incluída no objeto do usuário, mesmo que seja solicitada nos escopos. Para acessar essas reivindicações, você precisa fazer uma solicitação de rede para buscar as informações do usuário. + +#### Obter token de acesso \{#get-access-token} + +Atualize a configuração do `NextAuth` para que possamos obter o token de acesso: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // Injeta o token de acesso no objeto da sessão + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### Buscar informações do usuário \{#fetch-user-info} + +Agora acesse o endpoint de informações do usuário OIDC com o token de acesso: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // Substitua a URL pelo seu endpoint Logto, deve terminar com `/oidc/me` + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +Acima está um exemplo simples. Lembre-se de lidar com os casos de erro. + +#### Atualização do token de acesso \{#access-token-refresh} + +Um token de acesso é válido por um curto período de tempo. Por padrão, o Next.js buscará apenas um quando a sessão for criada. Para implementar a atualização automática do token de acesso, veja [Rotação de token de atualização](https://next-auth.js.org/v3/tutorials/refresh-token-rotation). + +### Escopos e reivindicações \{#scopes-and-claims} + + diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..e5476d2c6c2 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instale Auth.js através do seu gerenciador de pacotes favorito: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +Veja a [documentação do Auth.js](https://authjs.dev/getting-started/installation) para mais detalhes. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..ff9e96c55e0 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,182 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### Configurar o provedor Auth.js \{#set-up-authjs-provider} + + + +Modifique sua configuração de rota de API do Auth.js, adicione Logto como um provedor OIDC: + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // Você pode obter o valor do emissor na página de Detalhes do Aplicativo Logto, + // no campo "Endpoint do emissor" + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // Você pode personalizar o mapeamento do perfil do usuário aqui + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. Substitua a URL do `issuer` pelo "Endpoint do emissor" do seu aplicativo Logto. +2. Substitua o `clientId` e o `clientSecret` pelo ID e segredo do seu aplicativo Logto. +3. Personalize a função `profile` para mapear o perfil do usuário para o objeto de usuário do Next Auth, o mapeamento padrão é mostrado no exemplo. + +Então, você também pode adicionar um Middleware opcional para manter a sessão ativa: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // Você pode obter a URL bem conhecida na página de Detalhes do Aplicativo Logto, + // no campo "Endpoint de configuração do provedor OpenID" + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // Você pode personalizar o mapeamento do perfil do usuário aqui + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. Substitua a URL do `wellKnown` pelo "Endpoint de configuração do provedor OpenID" do seu aplicativo Logto. +2. Substitua o `clientId` e o `clientSecret` pelo ID e segredo do seu aplicativo Logto. +3. Personalize a função `profile` para mapear o perfil do usuário para o objeto de usuário do Next Auth, o mapeamento padrão é mostrado no exemplo. +4. Lembre-se de definir o `id_token_signed_response_alg` como `ES384`. + + + + + +Você pode encontrar mais detalhes na [documentação do Auth.js](https://authjs.dev/getting-started/installation). + +### Configurar URI de redirecionamento de login \{#configure-sign-in-redirect-uri} + + + + + + + +### Implementar login e logout \{#implement-sign-in-and-sign-out} + +#### Implementar botão de login e logout \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### Mostrar botão de login e logout na página \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +Acima está um exemplo simples, você pode verificar a [documentação do Auth.js](https://authjs.dev/getting-started/session-management/login) para mais detalhes. + +### Ponto de verificação \{#checkpoint} + +Agora, você pode testar seu aplicativo para ver se a autenticação funciona como esperado. diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..eea4f23cbb5 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..3571cc617d7 --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js buscará o token de acesso apenas uma vez sem o parâmetro de recurso. Precisamos implementar a busca do token de acesso por conta própria. + +#### Obter token de atualização \{#get-refresh-token} + +Atualize a configuração do provedor Logto, adicione o parâmetro "prompt" e defina-o como `consent`, e certifique-se de que o escopo `offline_access` esteja incluído: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +Em seguida, adicione um callback para salvar o `refresh_token` na sessão: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### Buscar token de acesso \{#fetch-access-token} + +Com o `refresh_token`, podemos buscar o token de acesso do endpoint de token OIDC do Logto. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Substitua o ID e o segredo do aplicativo pelo seu próprio, você pode verificar a seção "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Substitua a URL pelo seu endpoint Logto, deve terminar com `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..fb5d891c30c --- /dev/null +++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +Similar ao token de acesso para recursos de API, podemos usar o token de atualização para buscar o token de acesso da organização. + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // Substitua o ID e o segredo do aplicativo pelos seus próprios, você pode verificar a seção "Integration". + const basicAuth = Buffer.from(':').toString('base64'); + + // Substitua a URL pelo seu endpoint Logto, deve terminar com `/oidc/token` + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx new file mode 100644 index 00000000000..e961a9b535c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/fragments/_scopes-claims-introduction.mdx @@ -0,0 +1,37 @@ +默认情况下,返回的声明 (Claims) 是有限的。如果你需要更多信息,可以请求额外的权限 (Scopes) 以访问更多的声明 (Claims)。 + +:::info +“声明 (Claim)”是关于主体的断言;“权限 (Scope)”是一组声明 (Claims)。在当前情况下,声明 (Claim) 是关于用户的一条信息。 +::: + +以下是权限 (Scope) - 声明 (Claim) 关系的一个非规范性示例: + +```mermaid +classDiagram + class openid { + +sub + } + + class profile { + +name + +username + +picture + +... + } + + class email { + +email + +email_verified + } + + class phone { + +phone_number + +phone_number_verified + } +``` + +:::tip +“sub”声明 (Claim) 意味着“主体”,即用户的唯一标识符(即用户 ID)。 +::: + +Logto SDK 将始终请求三个权限 (Scopes):`openid`、`profile` 和 `offline_access`。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx index 9c209750bb2..3cb2d347ea7 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/README.mdx @@ -1,20 +1,25 @@ --- slug: /quick-starts/next-auth -sidebar_label: Next Auth +sidebar_label: Auth.js (Next Auth) sidebar_custom_props: logoFilename: 'next-auth.svg' - description: 为 Next.js 提供认证 (Authentication)。 + description: Next.js 的认证 (Authentication)。 --- +import ApiResourcesDescription from '../../fragments/_api-resources-description.md'; import FurtherReadings from '../../fragments/_further-readings.md'; -import ConfigProvider from './_config-provider.mdx'; +import GetUserInformation from './_get-user-information.mdx'; import GuideTip from './_guide-tip.mdx'; -import ScopesAndClaims from './_scopes-and-claims.mdx'; +import Installation from './_installation.mdx'; +import Integration from './_integration.mdx'; +import ConfigApiResources from './api-resources/_config-api-resources.mdx'; +import FetchAccessTokenForApiResources from './api-resources/_fetch-access-token-for-api-resources.mdx'; +import FetchOrganizationTokenForUser from './api-resources/_fetch-organization-token-for-user.mdx'; -# 为你的 Next Auth 应用添加认证 (Authentication) +# 为你的 Auth.js (Next Auth) 应用添加认证 (Authentication) -本指南将向你展示如何将 Logto 集成到你的 Next.js 应用中,使用 [Next Auth](https://next-auth.js.org/)。 +本指南将向你展示如何将 Logto 集成到你的使用 [Auth.js](https://authjs.dev/)(以前称为 Next Auth)的 Next.js 应用中。 @@ -22,21 +27,35 @@ import ScopesAndClaims from './_scopes-and-claims.mdx'; - 一个 [Logto Cloud](https://cloud.logto.io) 账户或一个 [自托管 Logto](/introduction/set-up-logto-oss)。 - 一个已创建的 Logto 传统应用。 -- 一个带有 Next Auth 的 Next.js 项目,查看 [Next Auth 文档](https://next-auth.js.org/getting-started/introduction)。 +- 一个带有 Auth.js 的 Next.js 项目,查看 [Auth.js 文档](https://authjs.dev/getting-started/installation)。 + +## 安装 \{#installation} + + ## 集成 \{#integration} -### 配置 Next Auth 提供商 \{#config-next-auth-provider} + + +## 获取用户信息 \{#fetch-user-information} + + + +## API 资源 \{#api-resources} + + + +### 配置 Logto 提供商 \{#configure-logto-provider} - + -### 检查点 \{#checkpoint} +### 获取 API 资源的访问令牌 \{#fetch-access-token-for-the-api-resource} -现在,你可以测试你的应用,看看认证 (Authentication) 是否按预期工作。 + -## 权限 (Scopes) 和声明 (Claims) \{#scopes-and-claims} +### 获取组织令牌 \{#fetch-organization-tokens} - + ## 延伸阅读 \{#further-readings} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx new file mode 100644 index 00000000000..8dc7bd85ad0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_get-user-information.mdx @@ -0,0 +1,128 @@ +import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx'; +import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx'; +import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md'; + +### 显示用户信息 \{#display-user-information} + +当用户登录时,`auth()` 的返回值将是一个包含用户信息的对象。你可以在你的应用中显示这些信息: + +```tsx title="app/page.tsx" +import { auth } from '@/auth'; + +export default async function Home() { + const session = await auth(); + + return ( +
+ {session?.user && ( +
+

声明 (Claims):

+ + + + + + + + + {Object.entries(session.user).map(([key, value]) => ( + + + + + ))} + +
名称
{key}{String(value)}
+
+ )} +
+ ); +} +``` + +### 请求额外的声明 (Claims) \{#request-additional-claims} + + + + + +要请求额外的权限 (Scopes),你可以配置 Logto provider 的参数: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email', + }, + }, + // ... + }, + ], +}); +``` + +### 需要网络请求的声明 (Claims) \{#claims-that-need-network-requests} + +为了防止 ID 令牌 (ID token) 过大,某些声明 (Claims) 需要通过网络请求获取。例如,即使在权限 (Scopes) 中请求了 `custom_data` 声明 (Claim),它也不会包含在用户对象中。要访问这些声明 (Claims),你需要进行网络请求以获取用户信息。 + +#### 获取访问令牌 (Access token) \{#get-access-token} + +更新 `NextAuth` 配置,以便我们可以获取访问令牌 (Access token): + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + token.accessToken = account.access_token; + } + return token; + }, + async session({ session, token }) { + // 将访问令牌 (Access token) 注入到会话对象中 + session.accessToken = token.accessToken; + return session; + }, + }, +}); +``` + +#### 获取用户信息 \{#fetch-user-info} + +现在使用访问令牌 (Access token) 访问 OIDC 用户信息端点: + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + // 将 URL 替换为你的 Logto 端点,应该以 `/oidc/me` 结尾 + const response = await fetch('https://xxx.logto.app/oidc/me', { + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const user = await response.json(); + console.log(user); + + // ... +} +``` + +以上是一个简单的示例。记得处理错误情况。 + +#### 访问令牌 (Access token) 刷新 \{#access-token-refresh} + +访问令牌 (Access token) 的有效期很短。默认情况下,Next.js 只会在会话创建时获取一次。要实现自动访问令牌 (Access token) 刷新,请参阅 [刷新令牌轮换](https://next-auth.js.org/v3/tutorials/refresh-token-rotation)。 + +### 权限 (Scopes) 和声明 (Claims) \{#scopes-and-claims} + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx new file mode 100644 index 00000000000..054bf292dd1 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_installation.mdx @@ -0,0 +1,32 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +通过你喜欢的包管理器安装 Auth.js: + + + + + +
+  npm i next-auth@beta
+
+ +
+ + +
+  pnpm add next-auth@beta
+
+ +
+ + +
+  yarn add next-auth@beta
+
+ +
+ +
+ +查看 [Auth.js 文档](https://authjs.dev/getting-started/installation) 以获取更多详细信息。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx new file mode 100644 index 00000000000..f7065f07640 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/_integration.mdx @@ -0,0 +1,180 @@ +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +import redirectUriFigure from '../../assets/next-auth-redirect-uri.png'; +import ConfigureRedirectUri from '../../fragments/_configure-redirect-uri.mdx'; +import GetAppSecret from '../../fragments/_get-app-secret.mdx'; +import AssumingUrl from '../../fragments/_web-assuming-url.mdx'; +import SignInFlowSummary from '../../fragments/_web-sign-in-flow-summary.mdx'; + +### 设置 Auth.js 提供商 \{#set-up-authjs-provider} + + + +修改 Auth.js 的 API 路由配置,添加 Logto 作为 OIDC 提供商: + + + + + +```ts title="./app/api/auth/[...nextauth]/route.ts" +import { handlers } from '@/auth'; +export const { GET, POST } = handlers; +``` + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oidc', + // 你可以从 Logto 应用详情页面的“发行者 (Issuer) 端点”字段获取发行者 (Issuer) 值 + issuer: 'https://xxxx.logto.app/oidc', + clientId: '', + clientSecret: '', + authorization: { + params: { scope: 'openid offline_access profile email' }, + }, + profile(profile) { + // 你可以在这里自定义用户资料映射 + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); +``` + +1. 将 `issuer` URL 替换为你的 Logto 应用的“发行者 (Issuer) 端点”。 +2. 将 `clientId` 和 `clientSecret` 替换为你的 Logto 应用的 ID 和密钥。 +3. 自定义 `profile` 函数以将用户资料映射到 Next Auth 用户对象,示例中显示了默认映射。 + +然后你还可以添加一个可选的中间件以保持会话活跃: + +```ts title="./middleware.ts" +export { auth as middleware } from '@/auth'; +``` + + + + + +```ts title="app/api/auth/[...nextauth]/route.ts" +import NextAuth from 'next-auth'; + +const handler = NextAuth({ + providers: [ + { + id: 'logto', + name: 'Logto', + type: 'oauth', + // 你可以从 Logto 应用详情页面的“OpenID 提供商配置端点”字段获取 well-known URL + wellKnown: 'https://xxxx.logto.app/oidc/.well-known/openid-configuration', + authorization: { params: { scope: 'openid offline_access profile email' } }, + clientId: '', + clientSecret: '', + client: { + id_token_signed_response_alg: 'ES384', + }, + profile(profile) { + // 你可以在这里自定义用户资料映射 + return { + id: profile.sub, + name: profile.name ?? profile.username, + email: profile.email, + image: profile.picture, + }; + }, + }, + ], +}); + +export { handler as GET, handler as POST }; +``` + +1. 将 `wellKnown` URL 替换为你的 Logto 应用的“OpenID 提供商配置端点”。 +2. 将 `clientId` 和 `clientSecret` 替换为你的 Logto 应用的 ID 和密钥。 +3. 自定义 `profile` 函数以将用户资料映射到 Next Auth 用户对象,示例中显示了默认映射。 +4. 记得将 `id_token_signed_response_alg` 设置为 `ES384`。 + + + + + +你可以在 [Auth.js 文档](https://authjs.dev/getting-started/installation) 中找到更多详细信息。 + +### 配置登录重定向 URI \{#configure-sign-in-redirect-uri} + + + + + + + +### 实现登录和登出 \{#implement-sign-in-and-sign-out} + +#### 实现登录和登出按钮 \{#implement-sign-in-and-sign-out-button} + +```tsx title="app/components/sign-in.tsx" +import { signIn } from '@/auth'; + +export default function SignIn() { + return ( +
{ + 'use server'; + await signIn('logto'); + }} + > + +
+ ); +} +``` + +```tsx title="app/components/sign-out.tsx" +import { signOut } from '@/auth'; + +export function SignOut() { + return ( +
{ + 'use server'; + await signOut(); + }} + > + +
+ ); +} +``` + +#### 在页面中显示登录和登出按钮 \{#show-sign-in-and-sign-out-button-in-the-page} + +```tsx title="app/page.tsx" +import SignIn from './components/sign-in'; +import SignOut from './components/sign-out'; +import { auth } from '@/auth'; + +export default function Home() { + const session = await auth(); + + return
{session?.user ? : }
; +} +``` + +以上是一个简单的示例,你可以查看 [Auth.js 文档](https://authjs.dev/getting-started/session-management/login) 以获取更多详细信息。 + +### 检查点 \{#checkpoint} + +现在,你可以测试你的应用程序以查看认证 (Authentication) 是否按预期工作。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx new file mode 100644 index 00000000000..9591c7c1c66 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_config-api-resources.mdx @@ -0,0 +1,11 @@ +import ConfigApiResources from '../../../fragments/_config-api-resources.mdx'; + +import ConfigResourcesCode from './code/_config-resources-code.md'; +import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md'; +import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md'; + +} + configResourcesWithScopesCode={} + configResourcesWithSharedScopesCode={} +/> diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx new file mode 100644 index 00000000000..6423448a2ee --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-access-token-for-api-resources.mdx @@ -0,0 +1,3 @@ +import GetAccessTokenCode from './code/_get-access-token-code.mdx'; + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx new file mode 100644 index 00000000000..651c813f14b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/_fetch-organization-token-for-user.mdx @@ -0,0 +1,10 @@ +import FetchOrganizationTokenForUser from '../../../fragments/_fetch-organization-token-for-user.mdx'; + +import ConfigOrganizationCode from './code/_config-organization-code.md'; +import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.mdx'; + +} + getOrganizationAccessTokenCode={} +/> diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md new file mode 100644 index 00000000000..c62993a44d4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-organization-code.md @@ -0,0 +1,19 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access urn:logto:scope:organizations', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md new file mode 100644 index 00000000000..ddde5aecbb0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + scope: 'openid offline_access profile email', + // highlight-next-line + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md new file mode 100644 index 00000000000..81fa1a08452 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile email shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md new file mode 100644 index 00000000000..c9c349eea02 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_config-resources-with-shared-scopes-code.md @@ -0,0 +1,20 @@ +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + providers: [ + { + id: 'logto',, + // ... + authorization: { + params: { + // highlight-next-line + scope: 'openid offline_access profile read write', + resource: 'https://shopping.your-app.com/api', + }, + }, + // ... + }, + ], +}); +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx new file mode 100644 index 00000000000..fd90ef0d3a5 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-access-token-code.mdx @@ -0,0 +1,83 @@ +Auth.js 只会在没有资源参数的情况下获取一次访问令牌。我们需要自己实现访问令牌的获取。 + +#### 获取刷新令牌 \{#get-refresh-token} + +更新 Logto 提供者配置,添加 "prompt" 参数并将其设置为 `consent`,并确保包含 `offline_access` 权限: + +```ts title="./auth.ts" +import NextAuth from 'next-auth'; + +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + authorization: { + params: { + // highlight-next-line + prompt: 'consent', + scope: 'openid offline_access shopping:read shopping:write', + resource: 'https://shopping.your-app.com/api', + // ... + }, + }, + // ... +}); +``` + +然后添加一个回调,将 `refresh_token` 保存到会话中: + +```ts title="./auth.ts" +export const { handlers, signIn, signOut, auth } = NextAuth({ + // ... + callbacks: { + async jwt({ token, account }) { + if (account) { + // ... + // highlight-next-line + token.refreshToken = account.refresh_token; + } + return token; + }, + async session({ session, token }) { + // ... + // highlight-next-line + session.refreshToken = token.refreshToken; + return session; + }, + }, +}); +``` + +#### 获取访问令牌 \{#fetch-access-token} + +使用 `refresh_token`,我们可以从 Logto 的 OIDC 令牌端点获取访问令牌。 + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // 用你自己的应用 ID 和密钥替换,可以查看“集成”部分。 + const basicAuth = Buffer.from(':').toString('base64'); + + // 用你的 Logto 端点替换 URL,应该以 `/oidc/token` 结尾 + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + resource: 'https://shopping.your-app.com/api', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx new file mode 100644 index 00000000000..0a645ae1617 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/next-auth/api-resources/code/_get-organization-access-token-code.mdx @@ -0,0 +1,36 @@ +类似于 API 资源的访问令牌 (Access token),我们可以使用刷新令牌 (Refresh token) 来获取组织访问令牌 (Organization token)。 + +```ts title="./app/page.tsx" +// ... + +export default async function Home() { + const session = await auth(); + + if (session?.refreshToken) { + // 将应用程序 ID 和密钥替换为你自己的,你可以查看“Integration”部分。 + const basicAuth = Buffer.from(':').toString('base64'); + + // 将 URL 替换为你的 Logto 端点,应该以 `/oidc/token` 结尾 + const response = await fetch('https://xxx.logto.app/oidc/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${basicAuth}`, + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: session.refreshToken, + // highlight-next-line + resource: 'urn:logto:scope:organizations', + // highlight-next-line + organization_id: 'organization-id', + }).toString(), + }); + + const data = await response.json(); + console.log(data.access_token); + } + + // ... +} +```