Skip to content

Commit

Permalink
verified works with next 14, added next14 to peer deps, refactored ex…
Browse files Browse the repository at this point in the history
…amples, bumped version number
  • Loading branch information
amorey committed Nov 6, 2023
1 parent a2da8e3 commit c220c45
Show file tree
Hide file tree
Showing 148 changed files with 18,570 additions and 3,844 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ This library uses the cookie strategy from [expressjs/csurf](https://github.com/

# Features

- Supports Next.js 13
- Supports app-router and pages-router Next.js 13 and Next.js 14
- Runs in edge runtime
- Implements cookie strategy from [expressjs/csurf](https://github.com/expressjs/csurf) and the crypto logic from [pillarjs/csrf](https://github.com/pillarjs/csrf)
- Gets token from HTTP request header (`X-CSRF-Token`) or from request body field (`csrf_token`)
- Handles form-urlencoded, multipart/form-data or json-encoded HTTP request bodies
- Customizable cookie options
- TypeScript definitions included

**Note: There's an issue with Next.js middleware in v13.3.X and v13.4.X that prevents edge-csrf from working properly with the pages-router in a dev environment (https://github.com/vercel/next.js/issues/48083, https://github.com/vercel/next.js/issues/48546)**

# Quickstart

To use Edge-CSRF, first add it as a dependency to your app:
Expand Down Expand Up @@ -57,8 +59,6 @@ export async function middleware(request: NextRequest) {
}
```

:boom: Note: the example above sends a response directly from middleware. This feature is enabled by default in Next.js 13.1+. To enable this in Next.js 13.0.X you must set the `allowMiddlewareResponseBody` flag in the Next.js config file. Alternatively, you can use `NextResponse.rewrite()` to handle the response.

Now, all HTTP submission requests (e.g. POST, PUT, DELETE, PATCH) will be rejected if they do not include a valid CSRF token. To add the CSRF token to your forms, you can fetch it from the `X-CSRF-Token` HTTP response header server-side or client-side. For example:

```typescript
Expand Down Expand Up @@ -104,6 +104,10 @@ export default function handler(req: NextApiRequest, res: NextApiResponse<Data>)
}
```

# Examples

See more examples in the [/examples](examples) directory in this repository.

# Configuration

To configure the CSRF middleware function just pass an object containing your options to the initialization method:
Expand Down
17 changes: 0 additions & 17 deletions example-ts-appdir/app/page.tsx

This file was deleted.

23 changes: 0 additions & 23 deletions example-ts-appdir/package.json

This file was deleted.

23 changes: 0 additions & 23 deletions example-ts/package.json

This file was deleted.

19 changes: 0 additions & 19 deletions example/package.json

This file was deleted.

7 changes: 0 additions & 7 deletions example/pages/_app.js

This file was deleted.

3 changes: 0 additions & 3 deletions example/pages/api/form-handler.js

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions examples/next13-approuter-html-submission/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Metadata } from 'next';

export const metadata: Metadata = {
title: 'edge-csrf html form submission example'
};

export default function Layout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}
53 changes: 53 additions & 0 deletions examples/next13-approuter-html-submission/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { headers } from 'next/headers';

import '../styles/globals.css';

export default function Page() {
const csrfToken = headers().get('X-CSRF-Token') || 'missing';

return (
<>
<p>CSRF token value: {csrfToken}</p>
<h2>HTML Form Submission Example:</h2>
<form action="/form-handler" method="post">
<legend>Form without CSRF (should fail):</legend>
<input type="text" name="input1" />
<button type="submit">Submit</button>
</form>
<br />
<form action="/form-handler" method="post">
<legend>Form with incorrect CSRF (should fail):</legend>
<input type="hidden" name="csrf_token" value="notvalid" />
<input type="text" name="input1" />
<button type="submit">Submit</button>
</form>
<br />
<form action="/form-handler" method="post">
<legend>Form with CSRF (should succeed):</legend>
<input type="hidden" name="csrf_token" value={csrfToken} />
<input type="text" name="input1" />
<button type="submit">Submit</button>
</form>
<h2>HTML File Upload Example:</h2>
<form action="/form-handler" method="post" encType="multipart/form-data">
<legend>Form without CSRF (should fail):</legend>
<input type="file" name="file1" />
<button type="submit">Submit</button>
</form>
<br />
<form action="/form-handler" method="post" encType="multipart/form-data">
<legend>Form with incorrect CSRF (should fail):</legend>
<input type="hidden" name="csrf_token" value="notvalid" />
<input type="file" name="file1" />
<button type="submit">Submit</button>
</form>
<br />
<form action="/form-handler" method="post" encType="multipart/form-data">
<legend>Form with CSRF (should succeed):</legend>
<input type="hidden" name="csrf_token" value={csrfToken} />
<input type="file" name="file1" />
<button type="submit">Submit</button>
</form>
</>
);
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
experimental: {
appDir: true,
serverActions: true
}
}

module.exports = nextConfig;
23 changes: 23 additions & 0 deletions examples/next13-approuter-html-submission/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "edge-csrf-example",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "^20.8.9",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"edge-csrf": "1.0.6-rc1",
"eslint": "^8.52.0",
"eslint-config-next": "^13.5.6",
"next": "^13.5.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.2.2"
}
}
Loading

0 comments on commit c220c45

Please sign in to comment.