CSRF mitigation for Next.js.
Mitigation patterns that next-csrf
implements:
- Synchronizer Token Pattern using
csrf
(Also read Understanding CSRF) - Double-submit cookie pattern
- Custom request headers
With yarn:
yarn add next-csrf
With npm:
npm i next-csrf --save
Setup:
// file: lib/csrf.js
import { nextCsrf } from "next-csrf";
const options = {
secret: process.env.CSRF_SECRET // Long, randomly-generated, unique, and unpredictable value
}
export const { csrf, csrfToken } = nextCsrf(options);
When you initialize nextCsrf
it will return the middleware, and a valid signed CSRF token. You can send it along with a custom header on your first request to a protected API route. Is not required, but recommended.
If you don't send the given CSRF token on the first request one is set up on any first request you send to a protected API route.
You can pass the token down as a prop on a custom _app.js
and then use it on your first request.
Keep in mind that the token is valid only on the first request, since we create a new one on each request.
Custom App:
// file: pages/_app.js
import App from 'next/app'
import { csrfToken } from '../lib/csrf';
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} csrfToken={csrfToken} />
}
export default MyApp
Usage with fetch
:
function Login({ csrfToken }) {
const sendRequest = async (e) => {
e.preventDefault();
const response = await fetch('/api/protected', {
'headers': {
'XSRF-TOKEN': csrfToken,
}
});
// ...
};
return (
<Form onSubmit={sendRequest}>
// ...
</Form>
);
}
export default Login;
Protect an API endpoint:
// file: pages/api/protected.js
import { csrf } from '../lib/csrf';
const handler = (req, res) => {
return res.status(200).json({ message: "This API route is protected."})
}
export default csrf(handler);