Skip to content

[LiveComponent] Form submit fails because of invalid CSRF token #2505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
momocode-de opened this issue Jan 14, 2025 · 18 comments
Closed

[LiveComponent] Form submit fails because of invalid CSRF token #2505

momocode-de opened this issue Jan 14, 2025 · 18 comments
Labels
Bug Bug Fix LiveComponent Status: Reviewed Has been reviewed by a maintainer

Comments

@momocode-de
Copy link

I have updated my composer packages and since then my forms within LiveComponents no longer work. When I submit a form (via LiveAction), I get an error that the CSRF token is invalid. According to the documentation, you don't have to do anything special regarding CSRF tokens in live components. So why am I getting this error now?

@momocode-de momocode-de added the Bug Bug Fix label Jan 14, 2025
@Kocal
Copy link
Member

Kocal commented Jan 14, 2025

Hi, what packages did you upgrade?

@momocode-de
Copy link
Author

momocode-de commented Jan 14, 2025

Hi, what packages did you upgrade?

All symfony packages from 7.1 to 7.2 and the symfony/ux packages to their newest version. I have also updated all the flex recipes to their newest version.

@Kocal
Copy link
Member

Kocal commented Jan 14, 2025

Idk if it's related, but do you also have this file https://github.com/symfony/recipes/blob/main/symfony/stimulus-bundle/2.20/assets/controllers/csrf_protection_controller.js?

Can you try to update your packages one by one (or at least Symfony and UX packages separatly)? Or create a reproducer? It would help us to understand what's happening, and to fix it.

Thanks!

@Kocal Kocal added Status: Waiting Feedback Needs feedback from the author and removed Status: Needs Review Needs to be reviewed labels Jan 14, 2025
@momocode-de
Copy link
Author

Idk if it's related, but do you also have this file https://github.com/symfony/recipes/blob/main/symfony/stimulus-bundle/2.20/assets/controllers/csrf_protection_controller.js?

Yes, I have that file.

Can you try to update your packages one by one (or at least Symfony and UX packages separatly)? Or create a reproducer? It would help us to understand what's happening, and to fix it.

Unfortunately, I have not yet been able to reproduce it in a clean installation. However, I have found out where the validation fails, namely here: https://github.com/symfony/security-csrf/blob/7.2/SameOriginCsrfTokenManager.php#L166

With this information, do you have any idea what the problem might be?

@nicolas-grekas
Copy link
Member

A previous form (one not managed by a livecomponent?) was submitted successfully with a double-submit cookie (which was added by the js snippet).
And later on, another form managed by the livecomponent is submitted, but this time the double-submit cookie wasn't submitted with the form payload. The JS snippet didn't do its job. Maybe because of some bad interference with the JS for livecomponents?
We'd need a reproducer to understand precisely.

@momocode-de
Copy link
Author

I was able to reproduce it. Here is my reproducer: https://github.com/momocode-de/symfony-ux-issue-2505

I have made 5 commits, here is the explanation of the test process:

composer create-project symfony/skeleton symfony-ux-issue-2505

# Commit "First commit after creating project"

composer require webapp
composer require symfony/apache-pack
composer require symfony/ux-live-component
composer require symfony/form
composer require symfony/security-bundle
bin/console make:controller HomeController
bin/console make:form TestType
bin/console make:user
bin/console make:migration
bin/console doctrine:migrations:migrate
bin/console make:registration-form
bin/console make:security:form-login

# Commit "Add required packages, HomeController, TestType, User, Registration Form, Login Form"

Now I have tested the registration and login once and I already had a problem with the CSRF token:

  • Go to /register and finish the registration
  • Go to /login, type in your data and submit
  • A CSRF error message appears
  • I was then able to fix this error with the “Fix CSRF error on login” commit (I think the template for the “make:security:form-login” command has to be adapted here?)
  • After that, the registration and subsequent login worked

I then added the live component for the form in the “Add live component for test form” commit. I then tested whether the form could be submitted:

  • Go to /home (when you are logged in) and submit the form
  • It was working

Then I rebuilt the live component in the commit “Submitting the Form via a LiveAction” so that the form is submitted via a LiveAction. Then I tested again:

  • Go to /home (when you are logged in) and submit the form
  • It was not working ("422 Unprocessable content" because of invalid CSRF token)

I had first tested the whole thing without login and registration and it worked there. However, due to the previous login there now seems to be a problem with the double-submit.

I hope this helps you.

@nicolas-grekas
Copy link
Member

Can you try this change to the csrf field?
https://github.com/symfony/maker-bundle/pull/1592/files

Then you can lobby for this PR to be merged if that's the source of the issue ;)

@momocode-de
Copy link
Author

momocode-de commented Jan 15, 2025

Can you try this change to the csrf field? https://github.com/symfony/maker-bundle/pull/1592/files

Then you can lobby for this PR to be merged if that's the source of the issue ;)

That is the fix that I had also made: momocode-de/symfony-ux-issue-2505@4bb01a9

After that, the login worked, but not the submit of the test form.

@smnandre
Copy link
Member

I think i've figured this out... as we did say we had no need for csrf in live component, we simply forgot to handle the ones security does insert automatically..

Could you just check this @momocode-de ? Add the following line in our csrf-controller.js file (probably line 18)

    if (!csrfCookie && nameCheck.test(csrfToken)) {
        csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
        csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
+        csrfField.dispatchEvent(new Event('change', { bubbles: true }));
    }

(without the + generated for the diff)

        csrfField.dispatchEvent(new Event('change', { bubbles: true }));

I think this could be it, and would allow us to fix any similar problem in one line :)

cc @nicolas-grekas

@momocode-de
Copy link
Author

@smnandre Yes, it works with the line, thank you very much!

smnandre added a commit to smnandre/recipes that referenced this issue Jan 19, 2025
This allow support / compatibility with LiveComponent when action are done between form first render and submit 

(ex: another form submit with Turbo and double header check)

See symfony/ux#2505
@smnandre
Copy link
Member

Thank you @momocode-de I opened a PR on symfony/recipes.. but you can update your own file already and enjoy the fix :)

@smnandre smnandre added Status: Reviewed Has been reviewed by a maintainer and removed Status: Waiting Feedback Needs feedback from the author labels Jan 19, 2025
nicolas-grekas pushed a commit to symfony/recipes that referenced this issue Jan 20, 2025
This allow support / compatibility with LiveComponent when action are done between form first render and submit 

(ex: another form submit with Turbo and double header check)

See symfony/ux#2505
@momocode-de
Copy link
Author

@smnandre I have noticed another problem. This is when you submit the form twice without reloading the page.

I have pushed two new commits into my reproducer. The first one contains your fix and the second one includes a “resetForm” call in my LiveAction.

If I submit the form once now, it will work. If I then submit the form again without reloading the page first, a CSRF error appears again. Due to the “resetForm” I would actually assume that a new submit would work. Can you check this again?

@smnandre
Copy link
Member

I had no problem while trying.. do you have a precise scenario to reproduce the problem ?

To answer your question, resetForm in LiveComponent does something similar to the input reset HTML element: it does not set all field to null, but in fact it set the values initially in the form.

After submitting a form via an action, you might want to "reset" the form back to its initial state so you can use it again. Do that by calling resetForm() in your action instead of redirectin
https://symfony.com/bundles/ux-live-component/current/index.html#resetting-the-form

@momocode-de
Copy link
Author

@smnandre Have you tested it with my reproducer?

In my real app I have the case that I have a form for account settings. If I then change a setting and save it, it works. If I then change something again and want to save it, the CSRF error appears. So the error also occurs if the form is not reset.

In another case, I have a form where you can change the password. When I fill in the fields and save them, I reset the form afterwards. If I then fill it out again and save it, the CSRF error also occurs.

@momocode-de
Copy link
Author

@smnandre It also happens if you submit the form and then the validation fails and you then correct the value and resubmit the form. Then I also get a CSRF error (request ends in 422 Unprocessable Content).

@momocode-de
Copy link
Author

@smnandre Have you been able to reproduce it yet? Do you want to reopen the issue, or should I create a new one?

@smnandre
Copy link
Member

Hello @momocode-de! I've reproduced it just minutes ago!

Thanks it'll help to understand the problem.

@momocode-de
Copy link
Author

Hi @smnandre. Is there any news about a fix here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Bug Fix LiveComponent Status: Reviewed Has been reviewed by a maintainer
Projects
None yet
Development

No branches or pull requests

5 participants