Skip to content

Commit

Permalink
Adds Express integration (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
amorey authored Jun 9, 2024
1 parent e6c2a29 commit e9b73a7
Show file tree
Hide file tree
Showing 14 changed files with 1,554 additions and 6 deletions.
84 changes: 82 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ We hope you enjoy using this software. Contributions and suggestions are welcome
## Features

- Runs on both node and edge runtimes
- Includes a Next.js integration ([see here](packages/nextjs))
- Includes a SvelteKit integration ([see here](packages/sveltekit))
- Includes integrations for [Next.js](packages/nextjs), [Sveltekit](packages/sveltekit) and [Express](packages/express)
- Includes a low-level API for custom integrations ([see here](packages/core))
- Handles form-urlencoded, multipart/form-data or json-encoded HTTP request bodies
- Gets token from HTTP request header or from request body
Expand All @@ -21,6 +20,7 @@ We hope you enjoy using this software. Contributions and suggestions are welcome

* [Next.js](packages/nextjs)
* [SvelteKit](packages/sveltekit)
* [Express](packages/express)
* [Core API](packages/core)

## Quickstart (Next.js)
Expand Down Expand Up @@ -167,6 +167,86 @@ declare global {
export {};
```

## Quickstart (Express)

First, install Edge-CSRF's Express integration library:

```console
npm install @edge-csrf/express
# or
pnpm add @edge-edge-csrf/express
# or
yarn add @edge-csrf/express
```

Next, add the Edge-CSRF middleware to your app:

```javascript
// app.js

import { createCsrfMiddleware } from '@edge-csrf/express';
import express from 'express';

// initalize csrf protection middleware
const csrfMiddleware = createCsrfMiddleware({
cookie: {
secure: process.env.NODE_ENV === 'production',
},
});

// init app
const app = express();
const port = 3000;

// add body parsing middleware
app.use(express.urlencoded({ extended: false }));

// add csrf middleware
app.use(csrfMiddleware);

// define handlers
app.get('/', (_, res) => {
res.status(200).json({ success: true });
});

// start server
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
});
```

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:

```javascript
// app.js
...

// define handlers
app.get('/my-form', (req, res) => {
const csrfToken = res.getHeader('X-CSRF-Token') || 'missing';
res.send(`
<!doctype html>
<html>
<body>
<p>CSRF token value: ${csrfToken}</p>
<form action="/my-form" 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>
</body>
</html>
`);
});

app.post('/my-form', (req, res) => {
res.send('success');
});

...
```

## Development

### Get the code
Expand Down
21 changes: 21 additions & 0 deletions examples/express/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
This is an [Express](https://expressjs.com) example app.

## Getting Started

First, install dependencies:

```bash
npm install
# or
pnpm install
# or
yarn install
```

Next, run the server:

```bash
node app.js
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
61 changes: 61 additions & 0 deletions examples/express/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { createCsrfMiddleware } from '@edge-csrf/express';
import express from 'express';

// initalize csrf protection middleware
const csrfMiddleware = createCsrfMiddleware({
cookie: {
secure: process.env.NODE_ENV === 'production',
},
});

// init app
const app = express();
const port = 3000;

// add body parsing middleware
app.use(express.urlencoded({ extended: false }));

// add csrf middleware
app.use(csrfMiddleware);

// define handlers
app.get('/', (req, res) => {
const csrfToken = res.getHeader('X-CSRF-Token') || 'missing';
res.send(`
<!doctype html>
<html>
<body>
<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>
</body>
</html>
`);
});

app.post('/form-handler', (req, res) => {
res.send('success');
});

// start server
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
});
10 changes: 10 additions & 0 deletions examples/express/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "edge-csrf-example",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"@edge-csrf/express": "^2.1.0",
"express": "^4.19.2"
}
}
2 changes: 1 addition & 1 deletion examples/next14-approuter-html-submission/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@edge-csrf/nextjs": "^2.0.0-rc9",
"@edge-csrf/nextjs": "^2.0.0",
"@types/node": "^20.8.9",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@
"vite": "^5.2.8",
"vitest": "^1.4.0",
"vitest-environment-miniflare": "^2.14.2"
}
},
"packageManager": "[email protected]+sha512.98a80fd11c2e7096747762304106432b3ddc67dcf54b5a8c01c93f68a2cd5e05e6821849522a06fb76284d41a2660d5e334f2ee3bbf29183bf2e739b1dafa771"
}
Loading

0 comments on commit e9b73a7

Please sign in to comment.