Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: custom jwt decode method for middleware #4210

Merged
merged 7 commits into from May 31, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 39 additions & 2 deletions docs/docs/configuration/nextjs.md
Expand Up @@ -16,16 +16,53 @@ You must set the [`NEXTAUTH_SECRET`](/configuration/options#nextauth_secret) env

**We strongly recommend** replacing the `secret` value completely with this `NEXTAUTH_SECRET` environment variable. This environment variable will be picked up by both the [NextAuth config](/configuration/options#options), as well as the middleware config.

---

### Basic usage
```js
import withAuth from "next-auth/middleware"
// or
import { withAuth } from "next-auth/middleware"
```

---
### Custom JWT decode method

If you have custom jwt decode method set in `[...nextauth].ts`, you must also pass the same `decode` method to `withAuth` in order to read the custom-signed JWT correctly. You may want to extract the encode/decode logic to a separate function for consistency.

`[...nextauth].ts`
```ts
import jwt from "jsonwebtoken";

export default NextAuth({
providers: [...],
jwt: {
// secret: PLEASE USE process.env.NEXTAUTH_SECRET
encode: async ({ secret, token }) => {
return jwt.sign(token as any, secret);
},
decode: async ({ secret, token }) => {
return jwt.verify(token as string, secret) as any;
},
},
})
```

Any `_middleware.ts`
```ts
import withAuth from "next-auth/middleware"
import jwt from "jsonwebtoken";

export default withAuth({
jwt: {
decode: async ({ secret, token }) => {
return jwt.verify(token, secret) as any;
},
},
callbacks: {
authorized: ({ token }) => !!token,
},
})
```
---
### `callbacks`

- **Required:** No
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/configuration/options.md
Expand Up @@ -482,6 +482,8 @@ Using a custom cookie policy may introduce security flaws into your application

NextAuth.js uses encrypted JSON Web Tokens ([JWE](https://datatracker.ietf.org/doc/html/rfc7516)) by default. Unless you have a good reason, we recommend keeping this behaviour. Although you can override this using the `encode` and `decode` methods. Both methods must be defined at the same time.

**IMPORTANT: If you middleware to protect routes, make sure the same method is also set in the [`_middleware.ts`](/configuration/nextjs#custom-jwt-decode-method)**
hinsxd marked this conversation as resolved.
Show resolved Hide resolved

```js
jwt: {
async encode(params: {
Expand Down
14 changes: 12 additions & 2 deletions packages/next-auth/src/next/middleware.ts
@@ -1,6 +1,6 @@
import type { NextMiddleware, NextFetchEvent } from "next/server"
import type { Awaitable, NextAuthOptions } from ".."
import type { JWT } from "../jwt"
import type { JWT, JWTOptions } from "../jwt"

import { NextResponse, NextRequest } from "next/server"

Expand All @@ -21,6 +21,16 @@ export interface NextAuthMiddlewareOptions {
* [Documentation](https://next-auth.js.org/configuration/pages)
*/
pages?: NextAuthOptions["pages"]

/**
* If a custom jwt `decode` method is set in `[...nextauth].ts`, the same method should be set here also.
*
* ---
* [Documentation](https://next-auth.js.org/configuration/nextjs#custom-jwt-decode-method)
*/
jwt?: Partial<Pick<JWTOptions, "decode">>


callbacks?: {
/**
* Callback that receives the user's JWT payload
Expand Down Expand Up @@ -81,7 +91,7 @@ async function handleMiddleware(
return NextResponse.redirect(errorUrl)
}

const token = await getToken({ req: req as any })
const token = await getToken({ req: req as any, decode: options?.jwt?.decode })

const isAuthorized =
(await options?.callbacks?.authorized?.({ req, token })) ?? !!token
Expand Down