Skip to content

Commit 8230215

Browse files
committed
feat: Receive the auth.js instance from the payload using getAuthjsInstance
1 parent 50aa494 commit 8230215

File tree

23 files changed

+310
-225
lines changed

23 files changed

+310
-225
lines changed

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default [
3030
"perfectionist/sort-object-types": "off",
3131
"perfectionist/sort-imports": "off",
3232
"perfectionist/sort-jsx-props": "off",
33+
"perfectionist/sort-named-exports": "off",
3334
},
3435
},
3536
{

examples/basic/src/auth.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import payloadConfig from "@payload-config";
2-
import NextAuth from "next-auth";
3-
import { withPayload } from "payload-authjs";
4-
import { authConfig } from "./auth.config";
2+
import { getPayload } from "payload";
3+
import { getAuthjsInstance } from "payload-authjs";
54

6-
export const { handlers, signIn, signOut, auth } = NextAuth(
7-
withPayload(authConfig, {
8-
payloadConfig,
9-
}),
10-
);
5+
const payload = await getPayload({ config: payloadConfig });
6+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload);
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import payloadConfig from "@payload-config";
2-
import NextAuth from "next-auth";
3-
import { withPayload } from "payload-authjs";
4-
import { adminsAuthConfig } from "./auth.admins.config";
2+
import { getPayload } from "payload";
3+
import { getAuthjsInstance } from "payload-authjs";
54

6-
export const { handlers, signIn, signOut, auth } = NextAuth(
7-
withPayload(adminsAuthConfig, {
8-
userCollectionSlug: "admins",
9-
payloadConfig,
10-
}),
11-
);
5+
const payload = await getPayload({ config: payloadConfig });
6+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload, "admins");
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import payloadConfig from "@payload-config";
2-
import NextAuth from "next-auth";
3-
import { withPayload } from "payload-authjs";
4-
import { customersAuthConfig } from "./auth.customers.config";
2+
import { getPayload } from "payload";
3+
import { getAuthjsInstance } from "payload-authjs";
54

6-
export const { handlers, signIn, signOut, auth } = NextAuth(
7-
withPayload(customersAuthConfig, {
8-
userCollectionSlug: "customers",
9-
payloadConfig,
10-
}),
11-
);
5+
const payload = await getPayload({ config: payloadConfig });
6+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload, "customers");
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import payloadConfig from "@payload-config";
2-
import NextAuth from "next-auth";
3-
import { withPayload } from "payload-authjs";
4-
import { authConfig } from "./auth.config";
2+
import { getPayload } from "payload";
3+
import { getAuthjsInstance } from "payload-authjs";
54

6-
export const { handlers, signIn, signOut, auth } = NextAuth(
7-
withPayload(authConfig, {
8-
payloadConfig,
9-
}),
10-
);
5+
const payload = await getPayload({ config: payloadConfig });
6+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload);

packages/dev/src/app/(app)/_components/ExampleList.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import config from "@payload-config";
22
import { getPayload } from "payload";
33
import { getPayloadSession } from "payload-authjs";
44

5-
const payload = await getPayload({ config });
6-
75
const ExampleList = async () => {
6+
const payload = await getPayload({ config });
87
const session = await getPayloadSession();
98

109
if (!session) {

packages/dev/src/auth/base.config.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import jwt from "jsonwebtoken";
22
import type { NextAuthConfig, Session } from "next-auth";
3+
import type { DiscordProfile } from "next-auth/providers/discord";
4+
import type { GitHubProfile } from "next-auth/providers/github";
5+
import type { EnrichedAuthConfig } from "payload-authjs";
36

47
export const SESSION_STRATEGY: NonNullable<NonNullable<NextAuthConfig["session"]>["strategy"]> =
58
"jwt";
69

7-
export const authConfig: NextAuthConfig = {
10+
export const authConfig: EnrichedAuthConfig<NextAuthConfig> = {
811
theme: { logo: "https://authjs.dev/img/logo-sm.png" },
912
providers: [],
1013
session: {
@@ -164,6 +167,33 @@ export const authConfig: NextAuthConfig = {
164167
return true;
165168
},
166169
},
170+
events: {
171+
signIn: async ({ adapter, user, account, profile }) => {
172+
if (!user.id || !profile) {
173+
return;
174+
}
175+
await adapter?.updateUser?.({
176+
id: user.id,
177+
...(account?.provider === "github" && {
178+
name:
179+
(profile as unknown as GitHubProfile).name ??
180+
(profile as unknown as GitHubProfile).login,
181+
email: profile.email ?? undefined,
182+
image: (profile as unknown as GitHubProfile).avatar_url,
183+
}),
184+
...(account?.provider === "keycloak" && {
185+
name: profile.name,
186+
email: profile.email ?? undefined,
187+
}),
188+
...(account?.provider === "discord" && {
189+
name: (profile as unknown as DiscordProfile).global_name,
190+
email: profile.email ?? undefined,
191+
image: (profile as unknown as DiscordProfile).image_url,
192+
}),
193+
additionalUserDatabaseField: `Create by signIn event at ${new Date().toISOString()}`,
194+
} as any);
195+
},
196+
},
167197
experimental: {
168198
enableWebAuthn: true,
169199
},

packages/dev/src/auth/index.ts

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,15 @@
11
import payloadConfig from "@payload-config";
2-
import NextAuth from "next-auth";
3-
import type { DiscordProfile } from "next-auth/providers/discord";
4-
import type { GitHubProfile } from "next-auth/providers/github";
52
import { getPayload } from "payload";
6-
import { withPayload } from "payload-authjs";
7-
import { nodeAuthConfig } from "./node.config";
3+
import { getAuthjsInstance } from "payload-authjs";
84

9-
export const { handlers, signIn, signOut, auth } = NextAuth(
10-
withPayload(nodeAuthConfig, {
11-
payload: getPayload({ config: payloadConfig }),
12-
events: {
13-
/**
14-
* Update user on every sign in
15-
*/
16-
signIn: async ({ adapter, user, account, profile }) => {
17-
if (!user.id || !profile) {
18-
return;
19-
}
20-
await adapter.updateUser!({
21-
id: user.id,
22-
...(account?.provider === "github" && {
23-
name:
24-
(profile as unknown as GitHubProfile).name ??
25-
(profile as unknown as GitHubProfile).login,
26-
email: profile.email ?? undefined,
27-
image: (profile as unknown as GitHubProfile).avatar_url,
28-
}),
29-
...(account?.provider === "keycloak" && {
30-
name: profile.name,
31-
email: profile.email ?? undefined,
32-
}),
33-
...(account?.provider === "discord" && {
34-
name: (profile as unknown as DiscordProfile).global_name,
35-
email: profile.email ?? undefined,
36-
image: (profile as unknown as DiscordProfile).image_url,
37-
}),
38-
additionalUserDatabaseField: `Create by signIn event at ${new Date().toISOString()}`,
39-
});
40-
},
41-
},
5+
const payload = await getPayload({ config: payloadConfig });
6+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload);
7+
8+
/* // Lazy initialization of the Auth.js instance (@see https://github.com/CrawlerCode/payload-authjs/issues/35)
9+
export const { handlers, signIn, signOut, auth } = NextAuth(async () =>
10+
withPayloadAuthjs({
11+
payload: await getPayload({ config: payloadConfig }),
12+
config: nodeAuthConfig,
13+
collectionSlug: "users",
4214
}),
43-
);
15+
); */

packages/dev/src/auth/node.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { NextAuthConfig } from "next-auth";
2+
import type { EnrichedAuthConfig } from "payload-authjs";
23
import { authConfig } from "./base.config";
34
import { discordProvider } from "./providers/discord";
45
import { githubProvider } from "./providers/github";
56
import { keycloakProvider } from "./providers/keycloak";
67
import { nodemailerProvider } from "./providers/nodemailer";
78
import { passkeysProvider } from "./providers/passkeys";
89

9-
export const nodeAuthConfig: NextAuthConfig = {
10+
export const nodeAuthConfig: EnrichedAuthConfig<NextAuthConfig> = {
1011
...authConfig,
1112
providers: [
1213
githubProvider,

packages/payload-authjs/README.md

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pnpm i payload-authjs
2929

3030
### 1. Setup Auth.js
3131

32-
First of all, this plugin only integrates Auth.js into Payload CMS by getting the user session from Auth.js. It doesn't handle the Auth.js stuff. You need to setup Auth.js before you can use this plugin.
32+
This plugin integrates Auth.js into Payload CMS by getting the user session from Auth.js. You need to setup Auth.js before you can use this plugin.
3333

3434
#### 1.1. Create your Auth.js configuration
3535

@@ -49,23 +49,19 @@ export const authConfig: NextAuthConfig = {
4949

5050
#### 1.2. Create your Auth.js instance
5151

52-
Next, create your Auth.js instance in a file (e.g. `auth.ts`). But before creating the Auth.js instance, you need to wrap your Auth.js configuration with the `withPayload` function:
52+
Next, create your Auth.js instance in a file (e.g. `auth.ts`).
53+
54+
> ⚠ But unlike what you would normally do in Auth.js, you need to create the Payload instance first and using the `getAuthjsInstance` function to retrieve the Auth.js instance.
5355
5456
```ts
5557
// auth.ts
5658
import payloadConfig from "@payload-config";
57-
import NextAuth from "next-auth";
58-
import { withPayload } from "payload-authjs";
59-
import { authConfig } from "./auth.config"; // ⚠ Import the config from a separate file
60-
61-
export const { handlers, signIn, signOut, auth } = NextAuth(
62-
withPayload(authConfig, {
63-
payloadConfig,
64-
}),
65-
);
66-
```
59+
import { getPayload } from "payload";
60+
import { getAuthjsInstance } from "payload-authjs";
6761

68-
> ⚠ Make sure you define your config in a separate file than where you create the NextAuth instance to avoid circular dependencies.
62+
const payload = await getPayload({ config: payloadConfig });
63+
export const { handlers, signIn, signOut, auth } = getAuthjsInstance(payload);
64+
```
6965

7066
#### 1.3. Add Auth.js route handler
7167

@@ -82,7 +78,7 @@ export const { GET, POST } = handlers;
8278

8379
Add optional `middleware.ts` to keep the session alive, this will update the session expiry each time it's called.
8480

85-
> ⚠ Unlike what you would normally do in Auth.js, you cannot use the `middleware` of `@/auth` directly. You have to create a new Auth.js instance without the `withPayload` wrapper to be [edge-compatible](https://authjs.dev/guides/edge-compatibility).
81+
> ⚠ Unlike what you would normally do in Auth.js, you cannot use the `middleware` of `@/auth` directly. You have to create a new Auth.js instance to be [edge-compatible](https://authjs.dev/guides/edge-compatibility).
8682
8783
```ts
8884
// middleware.ts
@@ -460,48 +456,38 @@ _More information about typescript can be found in the [Auth.js documentation](h
460456

461457
## 🎉 Events
462458

463-
Auth.js emits some [events](https://authjs.dev/reference/nextjs#events) that you can listen to. This plugin extends the events with additional parameters such as the `adapter` and `payload` instance.
459+
Auth.js emits some [events](https://authjs.dev/reference/nextjs#events) that you can listen to. This plugin extends the events with additional parameters such as the database `adapter` and the `payload` instance.
464460

465461
_More information about the events can be found in the [Auth.js documentation](https://authjs.dev/reference/nextjs#events)._
466462

467-
The following events are available:
468-
469-
- signIn
470-
- signOut
471-
- createUser
472-
- updateUser
473-
- linkAccount
474-
- session
475-
476-
### `signIn` Event
463+
### Example: `signIn` Event
477464

478465
The `signIn` event is fired when a user successfully signs in. For example, you could use this event to update the user's name on every sign-in:
479466

480467
```ts
481-
// auth.ts
482-
export const { handlers, signIn, signOut, auth } = NextAuth(
483-
withPayload(authConfig, {
484-
payloadConfig,
485-
events: {
486-
/**
487-
* Update user 'name' on every sign in
488-
*/
489-
signIn: async ({ adapter, user, profile }) => {
490-
if (!user.id || !profile) {
491-
return;
492-
}
493-
await adapter.updateUser!({
494-
id: user.id,
495-
name:
496-
(profile as unknown as GitHubProfile).name ??
497-
(profile as unknown as GitHubProfile).login,
498-
email: profile.email ?? undefined,
499-
image: (profile as unknown as GitHubProfile).avatar_url,
500-
});
501-
},
468+
// auth.config.ts
469+
import { EnrichedAuthConfig } from "payload-authjs";
470+
471+
export const authConfig: EnrichedAuthConfig = {
472+
providers: [github],
473+
events: {
474+
/**
475+
* Update user 'name', 'email' and 'image' on every sign in
476+
*/
477+
signIn: async ({ adapter, user, profile }) => {
478+
if (!user.id || !profile) {
479+
return;
480+
}
481+
await adapter?.updateUser?.({
482+
id: user.id,
483+
name:
484+
(profile as unknown as GitHubProfile).name ?? (profile as unknown as GitHubProfile).login,
485+
email: profile.email ?? undefined,
486+
image: (profile as unknown as GitHubProfile).avatar_url,
487+
});
502488
},
503-
}),
504-
);
489+
},
490+
};
505491
```
506492

507493
# 📓 Examples

0 commit comments

Comments
 (0)