Skip to content

Commit 8e110e3

Browse files
authored
feat: add next-auth sample (#947)
1 parent dd89939 commit 8e110e3

File tree

15 files changed

+505
-1
lines changed

15 files changed

+505
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vercel
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Auth.js (next-auth) Sample
2+
3+
This is a sample project for integrating Auth.js (next-auth) with Logto.
4+
5+
## Configuration
6+
7+
You can configure the sample project by setting the following environment variables:
8+
9+
| key | description | example |
10+
| ----------------- | ------------------------------------------- | ------------------------------------ |
11+
| AUTH_SECRET | The secret for cookie encryption | `my-cookie-secret` |
12+
| AUTH_LOGTO_ISSUER | The issuer of your Logto server | `https://[tenant-id].logto.app/oidc` |
13+
| AUTH_LOGTO_ID | The client ID of your Logto application | `my-app` |
14+
| AUTH_LOGTO_SECRET | The client secret of your Logto application | `my-secret` |
15+
16+
## Run the sample
17+
18+
```bash
19+
pnpm dev
20+
```
21+
22+
## Resources
23+
24+
- [Logto Auth.js Documentation](https://docs.logto.io/quick-starts/next-auth)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { handlers } from '../../../../auth';
2+
3+
export const { GET, POST } = handlers;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { signIn } from '../../auth';
2+
3+
export default function SignIn() {
4+
return (
5+
<form
6+
action={async () => {
7+
'use server';
8+
await signIn('logto');
9+
}}
10+
>
11+
<button type="submit">Sign In</button>
12+
</form>
13+
);
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { signOut } from '../../auth';
2+
import { redirect } from 'next/navigation';
3+
4+
const generateSignOutUri = (postLogoutRedirectUri: string) => {
5+
if (!process.env.AUTH_LOGTO_ID) {
6+
throw new Error('AUTH_LOGTO_ID is not set');
7+
}
8+
9+
const urlSearchParameters = new URLSearchParams({ 'client_id': process.env.AUTH_LOGTO_ID, 'post_logout_redirect_uri': postLogoutRedirectUri });
10+
11+
return `${process.env.AUTH_LOGTO_ISSUER}/session/end?${urlSearchParameters.toString()}`;
12+
};
13+
14+
export default function SignOut() {
15+
return (
16+
<form
17+
action={async () => {
18+
'use server';
19+
// Visit post-sign-out URL to implement federated sign-out,
20+
// @see https://authjs.dev/reference/core/adapters#federated-logout
21+
const { redirect: signOutRedirect } = await signOut({ redirect: false });
22+
redirect(generateSignOutUri(signOutRedirect));
23+
// If you don't need to implement federated sign-out, you can use the following code instead:
24+
// await signOut();
25+
}}
26+
>
27+
<button type="submit">
28+
Sign Out
29+
</button>
30+
</form>
31+
);
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { auth } from '../../auth';
2+
3+
// This is a sample page to fetch user info from Logto
4+
export default async function FetchUserInfo() {
5+
const session = await auth();
6+
const response = await fetch(`${process.env.AUTH_LOGTO_ISSUER}/me`, {
7+
headers: {
8+
// @ts-expect-error
9+
Authorization: `Bearer ${session?.accessToken}`,
10+
},
11+
});
12+
const user = await response.json();
13+
14+
return <div>{JSON.stringify(user)}</div>;
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const metadata = {
2+
title: 'Next.js',
3+
description: 'Generated by Next.js',
4+
}
5+
6+
export default function RootLayout({
7+
children,
8+
}: {
9+
children: React.ReactNode
10+
}) {
11+
return (
12+
<html lang="en">
13+
<body>{children}</body>
14+
</html>
15+
)
16+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { auth } from '../auth';
2+
import SignIn from './components/sign-in';
3+
import SignOut from './components/sign-out';
4+
5+
export default async function Home() {
6+
const session = await auth();
7+
8+
return (
9+
<main>
10+
{session?.user ? <SignOut /> : <SignIn />}
11+
{session?.user && (
12+
<div>
13+
<h2>Claims:</h2>
14+
<table>
15+
<thead>
16+
<tr>
17+
<th>Name</th>
18+
<th>Value</th>
19+
</tr>
20+
</thead>
21+
<tbody>
22+
{Object.entries(session.user).map(([key, value]) => (
23+
<tr key={key}>
24+
<td>{key}</td>
25+
<td>{String(value)}</td>
26+
</tr>
27+
))}
28+
</tbody>
29+
</table>
30+
</div>
31+
)}
32+
</main>
33+
);
34+
}

packages/next-auth-sample/auth.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import NextAuth, { NextAuthResult } from 'next-auth';
2+
import Logto from 'next-auth/providers/logto';
3+
4+
const result = NextAuth({
5+
providers: [
6+
Logto({
7+
authorization: {
8+
params: {
9+
// If you don't need to customize the scope, you can use the default scope by leaving the config empty.
10+
scope: 'openid offline_access profile email',
11+
},
12+
},
13+
}),
14+
],
15+
callbacks: {
16+
async jwt({ token, account }) {
17+
if (account) {
18+
token.accessToken = account.access_token;
19+
}
20+
return token;
21+
},
22+
async session({ session, token }) {
23+
// Inject the access token into the session object
24+
// @ts-expect-error
25+
session.accessToken = token.accessToken;
26+
return session;
27+
},
28+
},
29+
});
30+
31+
// A workaround to make the types work
32+
// @see https://github.com/nextauthjs/next-auth/discussions/9950
33+
export const handlers: NextAuthResult['handlers'] = result.handlers;
34+
export const auth: NextAuthResult['auth'] = result.auth;
35+
export const signIn: NextAuthResult['signIn'] = result.signIn;
36+
export const signOut: NextAuthResult['signOut'] = result.signOut;

0 commit comments

Comments
 (0)