How to do cross-domain POST request with valid CSRF?

What is the proper way to POST a form from another domain via AJAX to kirby with the csrf helper?

I’m currently using mzur’s uniform plugin to handle it in a route, but Kirby keeps failing about “invalid CSRF token”?

When I disable the Kirby native csrf() check in the plugin, it does the job, but I assume that’s not the proper way to handle this right?

Is it actually making any sense to figure out how to do CSRF tokens via an AJAX submitted form from another domain to Kirby? The more I think about it, the more it seems impossible to exchange tokens via a session or similar from the server to the client as it’s on another domain.

pinging @mzur here as well, as he’s very knowledgeable about this topic and I’m having issues setting this up via his plugin.
Would it be an option to have a uniform helper method ->withoutCSRF() that doesn’t perform this check then? I can PR if you want…

Session based authentication is supposed to be executed on the same domain, see the docs:

Although it doesn’t explicitly say it is impossible to do…

It is a security measure after all

Maybe you can replace it with some other form of token that also works cross-domain.


Since I would like to use uniform; I’ld like to be able to not check for CSRF tokens there then (which is currently not the case)? But that’s more of a uniform issue then a Kirby issue then, right?

Yes, because the csrf() check is built-in without an option to disable it, I think.

Yes, you’re right: kirby-form/Form.php at d60ed61482a14c80649e23f9ddf74c00f04ee470 · mzur/kirby-form · GitHub

Waiting for @mzur’s insights

I’m not sure if it’s a good idea to POST form data in a cross-domain request. The CSRF token is intended explicitly to prevent this. If you implement some method or disable some check to allow such a request, you automatically open up your website to all the CSRF attacks there are.

An alternative implementation could use the webhook action and a secret authentication token to post the data from the backend of you original domain to the backend running at the “cross”-domain. Something like this: Form on site A → AJAX POST request protected by CSRF token → Backend of site A → Webhook POST request protected by secret authentication token → Backend of site B. You could possibly use an iframe, too, but I have no experience with that.

Hey! Thanks for your answer @mzur!

I know about this. My case is that the form is rendered via Kirby and included in another website via ESI (via Varnish). So I don’t have any access to that server, nor backend. It’s also different then an iframe I believe; since an iframe actually has some “hot” connection to the webserver, as in my setup it does not.

It’s also not really for sensitive data; it’s for submitting a few fields that then get emailed and are pushed through to another system.

I have a PoC working with your plugin where CSRF can become optional via config. Than it works. Is this something you’ld add to your plugin? It can be helpful for others, and then I don’t always have to patch your plugin upon each update :wink:.

I guess it’s ok to implement this as a third argument to the Form class, with the default of CSRF protection turned on.