Skip to content

Commit 47911bf

Browse files
committed
fix(middleware): Middleware implementation
- Fix middleware import outside the project - Add the ability to use as a wrapper for custom middleware or next-auth middleware - fix nodemailer / exclude from config to be edge compatible
1 parent 9845c48 commit 47911bf

File tree

8 files changed

+153
-37
lines changed

8 files changed

+153
-37
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,32 @@ export const { handlers, signIn, signOut, auth } = NextAuth(
5454

5555
> ⚠ Make sure you define your `authConfig` in a separate file than where you use the `withPayload` function to avoid circular dependencies.
5656
57+
Create a new `middleware` or wrap your existing middleware, e.g. the [Auth.js middleware](https://authjs.dev/getting-started/session-management/protecting):
58+
59+
##### Create a new middleware
60+
61+
```ts
62+
// middleware.ts
63+
export { default } from "payload-authjs/middleware";
64+
```
65+
66+
##### Wrap your existing middleware
67+
68+
```ts
69+
// middleware.ts
70+
import NextAuth from "next-auth";
71+
import middleware from "payload-authjs/middleware";
72+
import { authConfig } from "./auth.config";
73+
74+
const { auth } = NextAuth(authConfig);
75+
76+
export default middleware(auth);
77+
```
78+
5779
**And that's it! Now you can sign-in via Auth.js and you are automatically authenticated in Payload CMS. Nice 🎉**
5880

81+
---
82+
5983
## Customizing
6084

6185
You don't need to create a collection for users. This plugin automatically creates a collection with the slug `users`.

dev/src/auth.config.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { NextAuthConfig, Profile } from "next-auth";
33
import { JWT } from "next-auth/jwt";
44
import github from "next-auth/providers/github";
55
import keycloak from "next-auth/providers/keycloak";
6-
import nodemailer from "next-auth/providers/nodemailer";
76

87
declare module "next-auth/jwt" {
98
interface JWT extends Pick<Profile, "roles"> {
@@ -53,10 +52,6 @@ export const authConfig: NextAuthConfig = {
5352
};
5453
},
5554
}),
56-
nodemailer({
57-
server: process.env.EMAIL_SERVER,
58-
from: process.env.EMAIL_FROM,
59-
}),
6055
],
6156
/* session: {
6257
strategy: "jwt",

dev/src/auth.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
import payloadConfig from "@payload-config";
22
import NextAuth from "next-auth";
3+
import nodemailer from "next-auth/providers/nodemailer";
34
import { withPayload } from "../../src";
45
import { authConfig } from "./auth.config";
56

67
export const { handlers, signIn, signOut, auth } = NextAuth(
7-
withPayload(authConfig, {
8-
payloadConfig,
9-
updateUserOnSignIn: true,
10-
}),
8+
withPayload(
9+
{
10+
...authConfig,
11+
providers: [
12+
...authConfig.providers,
13+
/**
14+
* Add nodemailer provider
15+
* ! Exclude this provider in the auth.config.ts file to be edge compatible
16+
* @see https://authjs.dev/guides/edge-compatibility
17+
*/
18+
nodemailer({
19+
server: process.env.EMAIL_SERVER,
20+
from: process.env.EMAIL_FROM,
21+
}),
22+
],
23+
},
24+
{
25+
payloadConfig,
26+
updateUserOnSignIn: true,
27+
},
28+
),
1129
);

dev/src/middleware.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1+
import NextAuth from "next-auth";
2+
import middleware from "./../../src/middleware";
3+
import { authConfig } from "./auth.config";
4+
15
export const config = {
26
matcher: ["/((?!api|admin/login|_next/static|_next/image|favicon.ico).*)"],
37
};
48

5-
export { logoutMiddleware as default } from "../../src/logoutMiddleware";
9+
/* export default middleware; */
10+
11+
const { auth } = NextAuth(authConfig);
12+
13+
export default middleware(auth);
14+
15+
/* export default middleware(
16+
auth(req => {
17+
// My custom logic
18+
}),
19+
);
20+
*/
21+
22+
/* export default middleware((req: NextRequest) => {
23+
// My custom logic
24+
return NextResponse.next();
25+
}); */

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
"description": "A Payload CMS 3 plugin for Auth.js 5",
77
"main": "dist/index.js",
88
"types": "dist/index.d.ts",
9+
"exports": {
10+
".": {
11+
"types": "./dist/index.d.ts",
12+
"import": "./dist/index.js",
13+
"default": "./dist/index.js"
14+
},
15+
"./middleware": {
16+
"types": "./dist/middleware.d.ts",
17+
"import": "./dist/middleware.js",
18+
"default": "./dist/middleware.js"
19+
}
20+
},
921
"files": [
1022
"dist"
1123
],

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export { getPayloadUser } from "./getPayloadUser";
2-
export { logoutMiddleware } from "./logoutMiddleware";
32
export { PayloadAdapter } from "./PayloadAdapter";
43
export { authjsPlugin } from "./plugin";
54
export type { AuthjsPluginConfig } from "./types";

src/logoutMiddleware.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/middleware.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import type { NextAuthResult } from "next-auth";
2+
import { NextRequest, NextResponse } from "next/server";
3+
4+
type Middleware = (req: NextRequest) => NextResponse;
5+
type AuthjsMiddleware = NextAuthResult["auth"] | ReturnType<NextAuthResult["auth"]>;
6+
7+
/**
8+
* Middleware of payload-authjs
9+
*
10+
* Inline middleware
11+
* @example
12+
* // middleware.ts
13+
* export { default } from "payload-authjs/middleware";
14+
*
15+
* Middleware wrapper
16+
* @example
17+
* // middleware.ts
18+
* const { auth } = NextAuth(authConfig);
19+
* export default middleware(auth);
20+
*
21+
* Middleware wrapper with custom logic
22+
* @example
23+
* // middleware.ts
24+
* const { auth } = NextAuth(authConfig);
25+
*
26+
* export default middleware(
27+
* auth((req) => {
28+
* // My custom logic
29+
* }),
30+
* );
31+
*/
32+
export default function middleware(
33+
arg: NextRequest | Middleware | AuthjsMiddleware | any,
34+
): Middleware | NextResponse {
35+
// Inline middleware
36+
if (arg instanceof NextRequest) {
37+
return logoutMiddleware(arg) ?? NextResponse.next();
38+
}
39+
40+
// Middleware wrapper
41+
if (typeof arg === "function") {
42+
return (req: NextRequest) => {
43+
const response = logoutMiddleware(req);
44+
if (response) return response;
45+
46+
return (arg(req) as NextResponse | undefined) ?? NextResponse.next();
47+
};
48+
}
49+
50+
throw new Error("Invalid argument for middleware");
51+
}
52+
53+
/**
54+
* Middleware to log out the user if they log out in the admin ui
55+
*/
56+
const logoutMiddleware = (req: NextRequest): NextResponse | undefined => {
57+
if (req.nextUrl.pathname !== "/admin/logout") return undefined;
58+
59+
const response = NextResponse.redirect(new URL("/", req.url));
60+
response.cookies.set("__Secure-authjs.session-token", "", {
61+
path: "/",
62+
expires: new Date(0),
63+
httpOnly: true,
64+
secure: true,
65+
});
66+
response.cookies.set("authjs.session-token", "", {
67+
path: "/",
68+
expires: new Date(0),
69+
httpOnly: true,
70+
secure: false,
71+
});
72+
73+
return response;
74+
};

0 commit comments

Comments
 (0)