0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

fix(console): remove outdated nextjs app router guide (#5862)

This commit is contained in:
wangsijie 2024-05-29 12:40:05 +08:00 committed by GitHub
parent c95755502d
commit a330310955
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 153 additions and 454 deletions

View file

@ -29,7 +29,6 @@ import webJavaSpringBoot from './web-java-spring-boot/index';
import webNext from './web-next/index';
import webNextAppRouter from './web-next-app-router/index';
import webNextAuth from './web-next-auth/index';
import webNextServerActions from './web-next-server-actions/index';
import webNuxt from './web-nuxt/index';
import webOutline from './web-outline/index';
import webPhp from './web-php/index';
@ -67,13 +66,6 @@ const guides: Readonly<Guide[]> = Object.freeze([
Component: lazy(async () => import('./web-next-app-router/README.mdx')),
metadata: webNextAppRouter,
},
{
order: 1.1,
id: 'web-next-server-actions',
Logo: lazy(async () => import('./web-next-server-actions/logo.svg')),
Component: lazy(async () => import('./web-next-server-actions/README.mdx')),
metadata: webNextServerActions,
},
{
order: 1.2,
id: 'm2m-general',

View file

@ -9,8 +9,8 @@ import Step from '@/mdx-components/Step';
<Steps>
<Step
title="Installation"
subtitle="Install Logto SDK for your project"
title="Add Logto SDK as a dependency"
subtitle="Please select your favorite package manager"
>
<Tabs>
<TabItem value="npm" label="npm">
@ -38,115 +38,54 @@ pnpm add @logto/next
</Step>
<Step
title="Init LogtoClient"
title="Prepare configs"
>
<InlineNotification>
In the following steps, we assume your app is running on <code>http://localhost:3000</code>.
</InlineNotification>
Import and initialize LogtoClient:
Prepare configuration for the Logto client. Create a new file `app/logto.ts` and add the following code:
<pre>
<code className="language-ts">
{`// libraries/logto.js
'use server';
import LogtoClient from '@logto/next/server-actions';
export const logtoClient = new LogtoClient({
{`export const logtoConfig = {
endpoint: '${props.endpoint}',
appId: '${props.app.id}',
appSecret: '${props.app.secret}',
baseUrl: 'http://localhost:3000', // Change to your own base URL
cookieSecret: '${generateStandardSecret()}', // Auto-generated 32 digit secret
cookieSecure: process.env.NODE_ENV === 'production',
});`}
};
`}
</code>
</pre>
</Step>
<Step
title="Implement sign-in"
title="Sign in"
>
### Configure Redirect URI
First, lets enter your redirect URI. E.g. `http://localhost:3000/api/logto/sign-in-callback`.
First, lets enter your redirect URI. E.g. `http://localhost:3000/callback`.
<UriInputField name="redirectUris" />
### Prepare helper functions
### Implement callback page
First, let's prepare helper functions to connect with Logto.
Add a callback page to your app:
Go back to your IDE/editor, add the following code to `/libraries/logto.ts`:
```ts
const cookieName = `logto:${config.appId}`;
const setCookies = (value?: string) => {
if (value === undefined) {
return;
}
cookies().set(cookieName, value, {
maxAge: 14 * 3600 * 24,
secure: config.cookieSecure,
});
};
const getCookie = () => {
return cookies().get(cookieName)?.value ?? '';
};
export const signIn = async () => {
const { url, newCookie } = await logtoClient.handleSignIn(
getCookie(),
`${config.baseUrl}/callback`
);
setCookies(newCookie);
return url;
};
export const handleSignIn = async (searchParams: URLSearchParams) => {
const search = searchParams.toString();
const newCookie = await logtoClient.handleSignInCallback(
getCookie(),
`${config.baseUrl}/callback?${search}`
);
setCookies(newCookie);
};
export const signOut = async () => {
const url = await logtoClient.handleSignOut(getCookie(), `${config.baseUrl}/callback`);
setCookies('');
return url;
};
export const getLogtoContext = async (config?: GetContextParameters) => {
return await logtoClient.getLogtoContext(getCookie(), config);
};
```
### Implement callback route
Create a "callback" route by adding the following code to `/app/callback/route.ts`:
```ts
```tsx
// pages/callback/page.tsx
import { handleSignIn } from '@logto/next/server-actions';
import { redirect } from 'next/navigation';
import { NextRequest } from 'next/server';
import { handleSignIn } from '../../libraries/logto';
import { logtoConfig } from '../logto';
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
await handleSignIn(searchParams);
await handleSignIn(logtoConfig, searchParams);
redirect('/');
}
@ -154,44 +93,128 @@ export async function GET(request: NextRequest) {
### Implement sign-in button
We're almost there! In the last step, we will create a sign-in button, which will navigate to Logto sign-in page when clicked.
This is a client component, so we will create it in `/app/sign-in.tsx`:
```ts
The sign-in button will call the method we just created, it is a client component:
```tsx
// app/sign-in.tsx
'use client';
import { useRouter } from 'next/navigation';
import { signIn } from '../libraries/logto';
type Props = {
onSignIn: () => Promise<void>;
};
const SignIn = () => {
const router = useRouter();
const handleClick = async () => {
const redirectUrl = await signIn();
router.push(redirectUrl);
};
return <button onClick={handleClick}>Sign In</button>;
const SignIn = ({ onSignIn }: Props) => {
return (
<button
onClick={() => {
onSignIn();
}}
>
Sign In
</button>
);
};
export default SignIn;
```
Now you will be navigated to Logto sign-in page when you click the button.
### Add sign in button to home page
Add this button to home page at `/app/page.tsx`:
We're almost there! Add this button to home page at `/app/page.tsx` and implement the `onSignIn` function:
```tsx
import { signIn } from '@logto/next/server-actions';
import SignIn from './sign-in';
import { logtoConfig } from './logto';
export default async function Home() {
return (
<main>
<h1>Hello Logto.</h1>
<div>
<SignIn />
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
</div>
</main>
);
}
```
Now you will be navigated to Logto sign-in page when you click the button.
</Step>
<Step
title="Sign out"
>
### Configure URI
After signing out, it'll be great to redirect user back to your website. Let's add `http://localhost:3000` as the Post Sign-out URI below.
<UriInputField name="postLogoutRedirectUris" />
### Implement a sign-out button
The sign-out button is also a client component, so we will create it in `/app/sign-out.tsx`:
```tsx
// app/sign-out.tsx
'use client';
type Props = {
onSignOut: () => Promise<void>;
};
const SignOut = ({ onSignOut }: Props) => {
return (
<button
onClick={() => {
onSignOut();
}}
>
Sign Out
</button>
);
};
export default SignOut;
```
### Add sign out button to home page
Then add the sign-out button to the home page in `/app/page.tsx`:
```tsx
import { signIn, signOut } from '@logto/next/server-actions';
import SignIn from './sign-in';
import SignOut from './sign-out';
import { logtoConfig } from './logto';
export default async function Home() {
return (
<main>
<h1>Hello Logto.</h1>
<div>
<SignOut
onSignOut={async () => {
'use server';
await signOut(logtoConfig);
}}
/>
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
</div>
</main>
);
@ -201,58 +224,42 @@ export default async function Home() {
</Step>
<Step
title="Implement sign-out"
title="Handle authentication state"
>
After signing out, it'll be great to redirect user back to your website. Let's add `http://localhost:3000` as the Post Sign-out URI first.
<UriInputField name="postLogoutRedirectUris" />
### Implement a sign-out button
This is also a client component, so we will create it in `/app/sign-out.tsx`:
We can call the function `getLogtoContext` to get context as the authentication state in pages, let's modify the home page:
```tsx
'use client';
import { useRouter } from 'next/navigation';
import { signOut } from '../libraries/logto';
const SignOut = () => {
const router = useRouter();
const handleClick = async () => {
const redirectUrl = await signOut();
router.push(redirectUrl);
};
return <button onClick={handleClick}>Sign Out</button>;
};
export default SignOut;
```
</Step>
<Step
title="Handle authentication status"
>
We can call the function `getLogtoContext` to get context as the authentication state, let's modify the home page:
```tsx
import { getLogtoContext } from '../libraries/logto';
import { getLogtoContext, signIn, signOut } from '@logto/next/server-actions';
import SignIn from './sign-in';
import SignOut from './sign-out';
import { logtoConfig } from './logto';
export default async function Home() {
const { isAuthenticated } = await getLogtoContext();
const { isAuthenticated } = await getLogtoContext(logtoConfig);
return (
<main>
<h1>Hello Logto.</h1>
<div>{isAuthenticated ? <SignOut /> : <SignIn />}</div>
<div>
{isAuthenticated ? (
<SignOut
onSignOut={async () => {
'use server';
await signOut(logtoConfig);
}}
/>
) : (
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
)}
</div>
</main>
);
}
@ -260,4 +267,4 @@ export default async function Home() {
</Step>
</Steps>
</Steps>

View file

@ -1,3 +1,3 @@
{
"order": 1.1
"order": 1
}

View file

@ -4,16 +4,16 @@ import { type GuideMetadata } from '../types';
const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'Next.js (App Router)',
description:
"Next.js App Router is a new paradigm for building applications using React's latest features.",
description: 'Next.js integration guide for App Router.',
target: ApplicationType.Traditional,
sample: {
repo: 'js',
path: 'packages/next-app-dir-sample',
path: 'packages/next-server-actions-sample',
},
isFeatured: true,
fullGuide: {
title: 'Full Next.js App Router SDK tutorial',
url: 'https://docs.logto.io/quick-starts/next-app-router',
title: 'Full Next.js SDK tutorial',
url: 'https://docs.logto.io/sdk/next-app-router/',
},
});

View file

@ -1,270 +0,0 @@
import UriInputField from '@/mdx-components/UriInputField';
import Tabs from '@mdx/components/Tabs';
import TabItem from '@mdx/components/TabItem';
import InlineNotification from '@/ds-components/InlineNotification';
import { generateStandardSecret } from '@logto/shared/universal';
import Steps from '@/mdx-components/Steps';
import Step from '@/mdx-components/Step';
<Steps>
<Step
title="Add Logto SDK as a dependency"
subtitle="Please select your favorite package manager"
>
<Tabs>
<TabItem value="npm" label="npm">
```bash
npm i @logto/next
```
</TabItem>
<TabItem value="yarn" label="Yarn">
```bash
yarn add @logto/next
```
</TabItem>
<TabItem value="pnpm" label="pnpm">
```bash
pnpm add @logto/next
```
</TabItem>
</Tabs>
</Step>
<Step
title="Prepare configs"
>
<InlineNotification>
In the following steps, we assume your app is running on <code>http://localhost:3000</code>.
</InlineNotification>
Prepare configuration for the Logto client. Create a new file `app/logto.ts` and add the following code:
<pre>
<code className="language-ts">
{`export const logtoConfig = {
endpoint: '${props.endpoint}',
appId: '${props.app.id}',
appSecret: '${props.app.secret}',
baseUrl: 'http://localhost:3000', // Change to your own base URL
cookieSecret: '${generateStandardSecret()}', // Auto-generated 32 digit secret
cookieSecure: process.env.NODE_ENV === 'production',
};
`}
</code>
</pre>
</Step>
<Step
title="Sign in"
>
### Configure Redirect URI
First, lets enter your redirect URI. E.g. `http://localhost:3000/callback`.
<UriInputField name="redirectUris" />
### Implement callback page
Add a callback page to your app:
```tsx
// pages/callback/page.tsx
import { handleSignIn } from '@logto/next/server-actions';
import { redirect } from 'next/navigation';
import { NextRequest } from 'next/server';
import { logtoConfig } from '../logto';
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
await handleSignIn(logtoConfig, searchParams);
redirect('/');
}
```
### Implement sign-in button
The sign-in button will call the method we just created, it is a client component:
```tsx
// app/sign-in.tsx
'use client';
type Props = {
onSignIn: () => Promise<void>;
};
const SignIn = ({ onSignIn }: Props) => {
return (
<button
onClick={() => {
onSignIn();
}}
>
Sign In
</button>
);
};
export default SignIn;
```
### Add sign in button to home page
We're almost there! Add this button to home page at `/app/page.tsx` and implement the `onSignIn` function:
```tsx
import { signIn } from '@logto/next/server-actions';
import SignIn from './sign-in';
import { logtoConfig } from './logto';
export default async function Home() {
return (
<main>
<h1>Hello Logto.</h1>
<div>
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
</div>
</main>
);
}
```
Now you will be navigated to Logto sign-in page when you click the button.
</Step>
<Step
title="Sign out"
>
### Configure URI
After signing out, it'll be great to redirect user back to your website. Let's add `http://localhost:3000` as the Post Sign-out URI below.
<UriInputField name="postLogoutRedirectUris" />
### Implement a sign-out button
The sign-out button is also a client component, so we will create it in `/app/sign-out.tsx`:
```tsx
// app/sign-out.tsx
'use client';
type Props = {
onSignOut: () => Promise<void>;
};
const SignOut = ({ onSignOut }: Props) => {
return (
<button
onClick={() => {
onSignOut();
}}
>
Sign Out
</button>
);
};
export default SignOut;
```
### Add sign out button to home page
Then add the sign-out button to the home page in `/app/page.tsx`:
```tsx
import { signIn, signOut } from '@logto/next/server-actions';
import SignIn from './sign-in';
import SignOut from './sign-out';
import { logtoConfig } from './logto';
export default async function Home() {
return (
<main>
<h1>Hello Logto.</h1>
<div>
<SignOut
onSignOut={async () => {
'use server';
await signOut(logtoConfig);
}}
/>
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
</div>
</main>
);
}
```
</Step>
<Step
title="Handle authentication state"
>
We can call the function `getLogtoContext` to get context as the authentication state in pages, let's modify the home page:
```tsx
import { getLogtoContext, signIn, signOut } from '@logto/next/server-actions';
import SignIn from './sign-in';
import SignOut from './sign-out';
import { logtoConfig } from './logto';
export default async function Home() {
const { isAuthenticated } = await getLogtoContext(logtoConfig);
return (
<main>
<h1>Hello Logto.</h1>
<div>
{isAuthenticated ? (
<SignOut
onSignOut={async () => {
'use server';
await signOut(logtoConfig);
}}
/>
) : (
<SignIn
onSignIn={async () => {
'use server';
await signIn(logtoConfig);
}}
/>
)}
</div>
</main>
);
}
```
</Step>
</Steps>

View file

@ -1,16 +0,0 @@
import { ApplicationType } from '@logto/schemas';
import { type GuideMetadata } from '../types';
const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'Next.js (Server Actions)',
description:
'Next.js with Server Actions, leverages async component from the latest features of React.',
target: ApplicationType.Traditional,
sample: {
repo: 'js',
path: 'packages/next-server-actions-sample',
},
});
export default metadata;

View file

@ -1,10 +0,0 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_134_42589)">
<path d="M31.7494 38.005C31.6304 38.068 31.6404 38.088 31.7544 38.03C31.7914 38.015 31.8224 37.994 31.8494 37.969C31.8494 37.948 31.8494 37.948 31.7494 38.005ZM31.9894 37.875C31.9324 37.922 31.9324 37.922 32.0004 37.891C32.0364 37.87 32.0684 37.85 32.0684 37.844C32.0684 37.817 32.0524 37.823 31.9894 37.875ZM32.1454 37.781C32.0884 37.828 32.0884 37.828 32.1564 37.797C32.1934 37.776 32.2244 37.754 32.2244 37.749C32.2244 37.724 32.2084 37.729 32.1454 37.781ZM32.3034 37.688C32.2464 37.735 32.2464 37.735 32.3124 37.703C32.3494 37.683 32.3804 37.662 32.3804 37.656C32.3804 37.631 32.3644 37.636 32.3034 37.688ZM32.5164 37.547C32.4074 37.62 32.3694 37.667 32.4694 37.615C32.5364 37.574 32.6504 37.484 32.6304 37.484C32.5874 37.5 32.5514 37.527 32.5154 37.547H32.5164ZM22.9534 8.01101C22.8804 8.01601 22.6614 8.03601 22.4694 8.05201C17.9213 8.46401 13.6663 10.912 10.9693 14.683C9.47826 16.75 8.51025 19.151 8.14525 21.672C8.01624 22.552 8.00024 22.812 8.00024 24.005C8.00024 25.197 8.01624 25.453 8.14525 26.333C9.01625 32.344 13.2923 37.39 19.0883 39.26C20.1313 39.593 21.2243 39.823 22.4694 39.964C22.9534 40.016 25.0464 40.016 25.5304 39.964C27.6824 39.724 29.4994 39.193 31.2974 38.276C31.5734 38.136 31.6254 38.099 31.5884 38.068C30.7084 36.907 29.8444 35.745 28.9794 34.573L26.4224 31.12L23.2194 26.375C22.1514 24.787 21.0793 23.203 19.9903 21.631C19.9793 21.631 19.9653 23.74 19.9593 26.312C19.9483 30.817 19.9483 31 19.8913 31.104C19.8343 31.229 19.7403 31.333 19.6153 31.391C19.5163 31.438 19.4273 31.448 18.9543 31.448H18.4133L18.2723 31.36C18.1843 31.303 18.1113 31.224 18.0643 31.131L17.9963 30.99L18.0013 24.719L18.0123 18.448L18.1113 18.323C18.1743 18.246 18.2523 18.183 18.3403 18.136C18.4713 18.073 18.5233 18.063 19.0643 18.063C19.6993 18.063 19.8043 18.088 19.9713 18.271C21.2673 20.203 22.5594 22.14 23.8304 24.083C25.9094 27.235 28.7474 31.536 30.1424 33.646L32.6794 37.485L32.8044 37.402C34.0234 36.589 35.1325 35.621 36.0895 34.517C38.1055 32.209 39.4135 29.37 39.8565 26.34C39.9855 25.46 40.0015 25.199 40.0015 24.007C40.0015 22.814 39.9855 22.559 39.8565 21.679C38.9855 15.668 34.7095 10.622 28.9134 8.75101C27.8294 8.40801 26.7144 8.17401 25.5854 8.05401C25.2824 8.02301 23.2144 7.98601 22.9544 8.01301L22.9534 8.01101ZM29.5004 17.688C29.6514 17.76 29.7654 17.896 29.8174 18.052C29.8444 18.136 29.8494 19.875 29.8444 23.792L29.8334 29.416L28.8444 27.896L27.8494 26.375V22.292C27.8494 19.645 27.8604 18.161 27.8744 18.088C27.9214 17.921 28.0354 17.781 28.1874 17.693C28.3114 17.63 28.3594 17.625 28.8544 17.625C29.3174 17.625 29.3954 17.63 29.4994 17.688H29.5004Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_134_42589">
<rect width="32.0003" height="32" fill="white" transform="translate(8.00024 8)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -11,7 +11,6 @@ const metadata: Readonly<GuideMetadata> = Object.freeze({
repo: 'js',
path: 'packages/next-sample',
},
isFeatured: true,
fullGuide: {
title: 'Full Next.js SDK tutorial',
url: 'https://docs.logto.io/quick-starts/next',

View file

@ -14,13 +14,13 @@ export type ApplicationCase = {
};
export const initialApp: ApplicationCase = {
framework: 'Next.js',
framework: 'Next.js (App Router)',
name: 'Next.js App',
description: 'This is a Next.js app',
guideFilename: 'web-next',
sample: {
repo: 'js',
path: 'packages/next-sample',
path: 'packages/next-server-actions-sample',
},
redirectUri: 'https://my.test.app/sign-in',
postSignOutRedirectUri: 'https://my.test.app/sign-out',