Skip to content

[CSRF] CSRF Token always invalid #60206

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
JuGid opened this issue Apr 12, 2025 · 5 comments
Closed

[CSRF] CSRF Token always invalid #60206

JuGid opened this issue Apr 12, 2025 · 5 comments

Comments

@JuGid
Copy link

JuGid commented Apr 12, 2025

Symfony version(s) affected

7.2.*

Description

My CSRF token is always invalid. For pages that not require user connection, it's always wrong.

How to reproduce

Can't reproduce it as i'm using symfony as I should, but this is the code I use to make my forms :

CalendarType.php

class CalendarType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name')
            ->add('date_start', null, [
                'widget' => 'single_text',
            ])
            ->add('date_end', null, [
                'widget' => 'single_text',
            ])
            ->add('description')
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Calendar::class,
        ]);
    }
}

CalendarController.php

final class CalendarController extends AbstractController
{
    public function __construct(
        private OrganisationContext $organisationContext, //My class to get current organization from session, not really important but we never know...
    ){}

    #[Route('/add-calendar', name: 'app_add_calendar')]
    public function add_calendar(Request $request, EntityManagerInterface $em): Response
    {
        $organisation = $this->organisationContext->getOrganisation();
        $calendar = new Calendar();
        $form = $this->createForm(CalendarType::class, $calendar);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $organisation->addCalendar($calendar);

            $em->flush();
            $this->addFlash('success', 'Calendar created.');

            return $this->redirectToRoute('app_dashboard');
        }
        return $this->render('calendar/add_calendar.html.twig', [
            'form' => $form,
            'organization' => $organisation,
        ]);
    }
}

add_calendar.html.twig

<div class="flex flex-col w-full">
    {{ form_start(form) }}
        {{ form_row(form.name) }}
        {{ form_row(form.description) }}
        <div class="grid grid-cols-2 gap-4">
            {{ form_row(form.date_start) }}
            {{ form_row(form.date_end) }}
        </div>

        <div class="flex flex-row justify-end">
            <button type="submit" class="btn btn-success text-white rounded-lg transition transform hover:-translate-y-1 hover:shadow-lg duration-300"><twig:ux:icon name="ph:plus" class="h-6 w-6" /> Add calendar</button>
        </div>
    {{ form_end(form) }}
</div>

The form generated includes the csrf token as follow :

<input type="hidden" id="calendar__token" name="calendar[_token]" data-controller="csrf-protection" class="input input-bordered w-full" value="csrf-token">

Here is my csrf.yml config file

# Enable stateless CSRF protection for forms and logins/logouts
framework:
    form:
        csrf_protection:
            token_id: submit

    csrf_protection:
        stateless_token_ids:
            - submit
            - authenticate
            - logout

And the error message :

Message : The CSRF token is invalid. Please try to resubmit the form.
Origin : Unknown.
Cause : 
Caused by:
Symfony\Component\Security\Csrf\CsrfToken
{
  -value: "csrf-token"
  -id: "submit"
}

Possible Solution

Reload the page where the form is.

Additional Context

No response

@JuGid
Copy link
Author

JuGid commented Apr 14, 2025

For some reasons, my configuration into framework.yml was not modified by the recipe. I made the changes based on https://github.com/symfony/recipes/pull/1337/files and it works pretty well !

@JuGid
Copy link
Author

JuGid commented Apr 14, 2025

So, I said it works pretty well but it is not... I tested my fixes on another app in Symfony 7.2 and the problem still the same.

I read this issue : #59065 , but I don't have reverse proxy as I'm working on local with symfony server:start, so trusted proxies didn't help.

To put it all in a nutshell this is what I have :

In my assets/controllers folder, I have a file called csrf_protection_controller.js with the same code contained in https://github.com/symfony/recipes/pull/1337/files.

This is my framework.yml configuration :

# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
    secret: '%env(APP_SECRET)%'
    # Note that the session will be started ONLY if you read or write from it.
    session:
        enabled: true
    form:
        csrf_protection:
            enabled: true
            token_id: 'submit'
    csrf_protection:
        stateless_token_ids: ['submit','authenticate','logout' ]
    serializer:
        default_context: 
            circular_reference_limit: 1
    #esi: true
    #fragments: true

when@test:
    framework:
        test: true
        session:
            storage_factory_id: session.storage.factory.mock_file

I tried on a form that I printed with twig with {{ form(form) }} and it includes a hidden field _token like :

<input type="hidden" id="intervenant__token" name="intervenant[_token]" data-controller="csrf-protection" class="input input-bordered w-full" value="csrf-token">

And I use the commande php bin/console asset-map:compile for my assets to work (as I also use the TailwindBundle).

The only workaround I found is to set the following options on every form type. And it's really annoying.

public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => SequenceConstraintDeeds::class,
            'calendar' => null,
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            'csrf_token_id' => 'constraint',
        ]);
    }

But, as i was trying to debug with php bin/console debug:form I found out that the default values are :

csrf_protection : true
csrf_field_name : _token
csrf_token_id: submit

Can't find help on documentation or issues, so I assume that I'm the only one who's facing this issue ?
If you need more details, ask for it.

Thank you !

EDIT : It seems like, when I go to a page, the Javascript is not executed. I use a JS library to create Gantt graph and the library doesn't render the chart before F5 the page. May be I should look for this root cause ?
When I clear the console and go to the form page, the console is empty. When I reaload, I can see the csrf-protection controller lazy loaded.

EDIT 2 : It works when using <body data-turbo="false">

@JuGid JuGid reopened this Apr 14, 2025
@JuGid JuGid changed the title [Form] CSRF Token always invalid [CSRF] CSRF Token always invalid Apr 14, 2025
@nicolas-grekas
Copy link
Member

Can you please put a reproducer in a small app on GitHub? That'd really help.

@JuGid
Copy link
Author

JuGid commented Apr 15, 2025

I tried to make an example app but I'm not able to reproduce the problem. The CSRF Protection is lazy loaded as it should be.

On this example app, when I go to a page with a form for the first time I can see in the console :

stimulus.index-oUGxBTh.js:7 csrf-protection #lazy:loading
stimulus.index-oUGxBTh.js:7 application #starting
stimulus.index-oUGxBTh.js:7 application #start
stimulus.index-oUGxBTh.js:7 csrf-protection #lazy:loaded

But on my main app, this doesn't happen about CSRF Protection. Stimulus controllers are not loaded (there is nothing in console).

So I don't know what happen...

Typically, I start on a page where there is no form, the console tell me that the app loads what is needed . Here, everything is OK :

Image

Then, on the same page, there is a link to a page with a form. So I click and this is the console :

Image

Then, I reload this form page manually (cmd + shift + R) :

Image

As I'm not able to reproduce the issue on a small app, can I help in some other ways ?

@xabbuh
Copy link
Member

xabbuh commented Apr 23, 2025

I am afraid you will then have to debug this yourself for the time being. Let’s close here for now since there is nothing we can do.

@xabbuh xabbuh closed this as not planned Won't fix, can't repro, duplicate, stale Apr 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants