Vue.js and Symfony forms
How to handle Vue.js request within Symfony as normal form submission
Symfony provides us the symfony/form
package which makes handling of rendering and submitting forms easier than ever. Soon this will become even easier with new “Form handler helper”, but that’s not the point here.
What annoyed me when I first started working with Vue.js was the fact that I pretty much like need to say “goodbye” to the forms rendering directly in the Twig (which is very handy).
I’ve started searching for some “form generators” packages for Vue.js. There are few, but so far I didn’t liked any of them. In worst case, I could just render the form in some kind of API method like /get-form-view
but this is so against the Vue.js workflow/concept.
So... I started to ask myself and think:
“How can I render forms in Vue.js and handle them in Symfony? While I can quit rendering the forms like Twig handles it — I definitely want to keep the Form validations / handling provided by Symfony”
There are few problems that need to be solved here:
- handling of csrf token,
- rebuilding the request “it’s structure must be the same of that provided upon Symfony standard form submission”,
CSRF token
Backend
By default each Form created with symfony/form
packages has the CSRF Token validation turned on. Meaning further that each request provided to the form handler must contain the CSRF Token. There are few solutions here, I will go with the 2 that I found for my case.
The bad one (unless it’s just Your private project) — disabling the CSR Token validation
Each form class (meaning that it extends from Symfony\Component\Form\AbstractType
) allows us to turn the CSRF validation off.
While this is ok for small private projects or internal ones, it’s one big no when it comes to publicly accessible project.
Sending and handling the csrf token with Vue.js call — the good solution
- First thing to do is… disabling the
csrf_protection
like above.
2. Now we need CsrfTokenValidatorService
3. Now the check for token must be done in 2 places
- as I wrote in other article (here), each request goes through
Authenticator
— so the request must be validate inside of it as this is called before theKernelRequestEvent
gets triggered KernelRequest::REQUEST
KernelRequestListener
Authenticator
4. We also need route which will deliver the CSRF token
Frontend
Now instead of adding getCsrf
over and over again in each Axios call i wrote my own plugin to handle the post call with csrf token call alongside.
The plugin
Simply the plugin does 2 things:
- calls backend: “Hey — give me CSRF token- for this UUID”,
- then makes second call “Hey — i got this CSRF for UUID, please check it and let me through”
Naturally nobody says that the token must be fetched on the moment that ajax call is done, it can as well be fetched in the beforeMount
and then supplied in form, I just see no reason for that, as we must communicate backed for token anyway.
So.. does it actually work correctly if we would provide fake csrf token? Yes — i did a test with hardcoded token in code and the request was rejected.
Not a perfect solution
While this is doesn’t sound perfect it works pretty much the way that Symfony handles the CSRF tokens:
- it uses the
form_name
instead ofUUID
, - it generates new token on each request,
Rebuilding the Request
Now once the CSRF token validation is working, here comes the easiest part actually. We simply need a logic which will “take the Axios request — json” and transform it into proper Request data used normally in Symfony.
And just use it like this:
My thoughts to this solution
The only main concern that I got here is that getCsrf
route should be hidden behind authentication, and only the login
should be allowed to pass it without authentication, otherwise upon “fake form” and copied front logic anyone can easily fetch the CSRF token.
Other nice “in-case” protection would be just checking where does the request comes from — if outside of our domain then — block it, thus nobody will ever get the token.
Other than this, is just that it took a bit to understand how to generate the CSRF token, validate it, handle the request and so on — so it’s time consuming when doing it for first time, but other than that it can be copied and reapplied.
And hey… the Symfony Form Validation is working as it should!