Skip to content

Commit

Permalink
refactor: rewrite next-auth quick start (#961)
Browse files Browse the repository at this point in the history
  • Loading branch information
wangsijie authored Jan 8, 2025
1 parent c6441e5 commit 2de5fb9
Show file tree
Hide file tree
Showing 98 changed files with 4,192 additions and 138 deletions.
43 changes: 31 additions & 12 deletions docs/quick-starts/framework/next-auth/README.mdx
Original file line number Diff line number Diff line change
@@ -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: 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.

<GuideTip />

## Prerequisites \{#prerequisites}

- 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}

<Installation />

## Integration \{#integration}

### Config Next Auth provider \{#config-next-auth-provider}
<Integration />

## Fetch user information \{#fetch-user-information}

<GetUserInformation />

## API resources \{#api-resources}

<ApiResourcesDescription />

### Configure Logto provider \{#configure-logto-provider}

<ConfigProvider />
<ConfigApiResources />

### 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.
<FetchAccessTokenForApiResources />

## Scopes and claims \{#scopes-and-claims}
### Fetch organization tokens \{#fetch-organization-tokens}

<ScopesAndClaims />
<FetchOrganizationTokenForUser />

## Further readings \{#further-readings}

Expand Down
128 changes: 128 additions & 0 deletions docs/quick-starts/framework/next-auth/_get-user-information.mdx
Original file line number Diff line number Diff line change
@@ -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 (
<main>
{session?.user && (
<div>
<h2>Claims:</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{Object.entries(session.user).map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
<td>{String(value)}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</main>
);
}
```

### Request additional claims \{#request-additional-claims}

<FindUserInfoMissing method="auth()" />

<ScopesAndClaimsIntroduction hideDefaultScopes />

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}

<ScopesAndClaims />
32 changes: 32 additions & 0 deletions docs/quick-starts/framework/next-auth/_installation.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

Install Auth.js via your favorite package manager:

<Tabs>

<TabItem value="npm" label="npm">

<pre>
<code className="language-bash">npm i next-auth@beta</code>
</pre>

</TabItem>
<TabItem value="pnpm" label="pnpm">

<pre>
<code className="language-bash">pnpm add next-auth@beta</code>
</pre>

</TabItem>
<TabItem value="yarn" label="yarn">

<pre>
<code className="language-bash">yarn add next-auth@beta</code>
</pre>

</TabItem>

</Tabs>

See [Auth.js documentation](https://authjs.dev/getting-started/installation) for more details.
Original file line number Diff line number Diff line change
Expand Up @@ -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';

<SignInFlowSummary />

<AssumingUrl />

#### Configure sign-in redirect URI \{#configure-sign-in-redirect-uri}

<ConfigureRedirectUri
figureSrc={redirectUriFigure}
redirectUri="http://localhost:3000/api/auth/callback/logto"
/>

#### Set up Next Auth provider \{#set-up-next-auth-provider}
### Set up Auth.js provider \{#set-up-authjs-provider}

<GetAppSecret />

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:

<Tabs>

<TabItem value="v5" label="Next Auth v5">
<TabItem value="v5" label="Auth.js v5">

```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',
Expand Down Expand Up @@ -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';
```

</TabItem>

<TabItem value="v4" label="Next Auth v4">

```ts
```ts title="app/api/auth/[...nextauth]/route.ts"
import NextAuth from 'next-auth';

const handler = NextAuth({
Expand Down Expand Up @@ -116,3 +109,74 @@ export { handler as GET, handler as POST };
</TabItem>

</Tabs>

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}

<SignInFlowSummary />

<AssumingUrl />

<ConfigureRedirectUri
figureSrc={redirectUriFigure}
redirectUri="http://localhost:3000/api/auth/callback/logto"
/>

### 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 (
<form
action={async () => {
'use server';
await signIn('logto');
}}
>
<button type="submit">Sign In</button>
</form>
);
}
```

```tsx title="app/components/sign-out.tsx"
import { signOut } from '@/auth';

export function SignOut() {
return (
<form
action={async () => {
'use server';
await signOut();
}}
>
<button type="submit">Sign Out</button>
</form>
);
}
```

#### 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 <div>{session?.user ? <SignOut /> : <SignIn />}</div>;
}
```

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.
13 changes: 0 additions & 13 deletions docs/quick-starts/framework/next-auth/_scopes-and-claims-code.md

This file was deleted.

5 changes: 0 additions & 5 deletions docs/quick-starts/framework/next-auth/_scopes-and-claims.mdx

This file was deleted.

Loading

0 comments on commit 2de5fb9

Please sign in to comment.