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-csrfWith npm:
npm i next-csrf --saveSetup:
// 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 MyAppUsage 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);