exportconstcsrf = newCSRF({ cookie, // what key in FormData objects will be used for the token, defaults to `csrf` formDataKey:"csrf", // an optional secret used to sign the token, recommended for extra safety secret:"s3cr3t", });
You can customize the token size by passing the byte size, the default one is 32 bytes which will give you a string with a length of 43 after encoding.
You could do this on any route, but I recommend you to do it on the root loader.
Now that you returned the token and set it in a cookie, you can use the AuthenticityTokenProvider component to provide the token to your React components.
Note that the authenticity token is only really needed for a form that mutates the data somehow. If you have a search form making a GET request, you don't need to add the authenticity token there.
This AuthenticityTokenInput will get the authenticity token from the AuthenticityTokenProvider component and add it to the form as the value of a hidden input with the name csrf. You can customize the field name using the name prop.
<AuthenticityTokenInputname="customName"/>
You should only customize the name if you also changed it on createAuthenticityToken.
If you need to use useFetcher (or useSubmit) instead of Form you can also get the authenticity token with the useAuthenticityToken hook.
exportasyncfunctionaction({ request }: Route.ActionArgs) { try { awaitcsrf.validate(request); } catch (error) { if (errorinstanceofCSRFError) { // handle CSRF errors } // handle other possible errors }
// here you know the request is valid returnredirectBack(request, { fallback:"/fallback" }); }
If you need to parse the body as FormData yourself (e.g. to support file uploads) you can also call CSRF#validate with the FormData and Headers objects.
If you call CSRF#validate with the request instance, but you already read its body, it will throw an error.
In case the CSRF validation fails, it will throw a CSRFError which can be used to correctly identify it against other possible errors that may get thrown.
The list of possible error messages are:
missing_token_in_cookie: The request is missing the CSRF token in the cookie.
invalid_token_in_cookie: The CSRF token is not valid (is not a string).
tampered_token_in_cookie: The CSRF token doesn't match the signature.
missing_token_in_body: The request is missing the CSRF token in the body (FormData).
mismatched_token: The CSRF token in the cookie and the body don't match.
You can use error.code to check one of the error codes above, and error.message to get a human friendly description.
Warning
Don't send those error messages to the end-user, they are meant to be used for debugging purposes only.
Install using
bunx shadcn@latest add @remix-utils/csrf-serverandbunx shadcn@latest add @remix-utils/csrf-react.This depends on
react,@oslojs/crypto,@oslojs/encoding, and React Router.The CSRF related functions let you implement CSRF protection on your application.
This part of Remix Utils needs React and server-side code.
First create a new CSRF instance.
Then you can use
csrfto generate a new token.You can customize the token size by passing the byte size, the default one is 32 bytes which will give you a string with a length of 43 after encoding.
You will need to save this token in a cookie and also return it from the loader. For convenience, you can use the
CSRF#commitTokenhelper.You could do this on any route, but I recommend you to do it on the
rootloader.Now that you returned the token and set it in a cookie, you can use the
AuthenticityTokenProvidercomponent to provide the token to your React components.Render it in your
rootcomponent and wrap theOutletwith it.When you create a form in some route, you can use the
AuthenticityTokenInputcomponent to add the authenticity token to the form.Note that the authenticity token is only really needed for a form that mutates the data somehow. If you have a search form making a GET request, you don't need to add the authenticity token there.
This
AuthenticityTokenInputwill get the authenticity token from theAuthenticityTokenProvidercomponent and add it to the form as the value of a hidden input with the namecsrf. You can customize the field name using thenameprop.You should only customize the name if you also changed it on
createAuthenticityToken.If you need to use
useFetcher(oruseSubmit) instead ofFormyou can also get the authenticity token with theuseAuthenticityTokenhook.Finally, you need to validate the authenticity token in the action that received the request.
If you need to parse the body as FormData yourself (e.g. to support file uploads) you can also call
CSRF#validatewith the FormData and Headers objects.If you call
CSRF#validatewith the request instance, but you already read its body, it will throw an error.In case the CSRF validation fails, it will throw a
CSRFErrorwhich can be used to correctly identify it against other possible errors that may get thrown.The list of possible error messages are:
missing_token_in_cookie: The request is missing the CSRF token in the cookie.invalid_token_in_cookie: The CSRF token is not valid (is not a string).tampered_token_in_cookie: The CSRF token doesn't match the signature.missing_token_in_body: The request is missing the CSRF token in the body (FormData).mismatched_token: The CSRF token in the cookie and the body don't match.You can use
error.codeto check one of the error codes above, anderror.messageto get a human friendly description.Don't send those error messages to the end-user, they are meant to be used for debugging purposes only.
Author
Sergio XalambrÃ