TYPO3-Headless / headless

TYPO3 Headless JSON API providing content for PWA application (e.g. javaScript apps like nuxt-typo3)
https://t3headless.io
GNU General Public License v2.0
160 stars 61 forks source link

Nonce Cookie Domain for CSRF-like login token #763

Closed yannkuesthardt closed 3 months ago

yannkuesthardt commented 3 months ago

Describe the bug I am having issues with the new Nonce cookies (regarding FE Login), because the domain is always set to the backend domain and SameSite is set to strict. Due to this setup, all frontend login requests from the frontend fail, as the __RequestToken cannot be verified with the matching Nonce cookie. See v12 breaking change 97305 to logins for more details.

I have setup the cookie domain in all variations with subdomains (e.g. ".example.com"). I have tried using a cookie domain for frontend and backend together (TYPO3 Docs for SYS Cookie Domain) and separately (TYPO3 Docs for BE Cookie Domain and TYPO3 Docs for FE Cookie Domain). In all cases the "normal" cookies, like typo3_be_user and typo3_fe_user get set correctly, but the Nonce cookie always uses the backend domain with SameSite set to strict.

To Reproduce The easiest way to reproduce this behavior without a actual frontend is to use Postman. Any other GET/POST Request tool should work too, as long as cookies can be either manually or automatically set/synced from browser.

Steps to reproduce the behavior:

  1. Setup new TYPO3 v12 project
  2. Install & Setup TYPO3 Headless
  3. Setup FE Login according to the documentation
  4. Create a new (blank) page with a login form
  5. Check YAML output for login page
  6. Setup a Postman request using the data from the login page
  7. Turn on cookie sync for the backend page in postman => success
  8. Turn off cookie sync for the backend page in postman (and delete any existing cookies) => failure

Expected behavior Some way of either setting the Nonce Cookie domain or some way to bypass the CSRF-like login (not the prefered option).

Screenshots Postman Example with cookie sync:

Postman Example with cookie sync

Postman Example without cookie sync:

Postman Example without cookie sync

TYPO3 version and TYPO3 Headless version TYPO3: v12.4.16 FE Login: v12.4.16 TYPO3 Headless: v4.3.1

Additional context TYPO3 Nonce Docs Headless FE Login Docs TYPO3 FE Login Docs

twoldanski commented 3 months ago

Hi @yannkuesthardt

Firstly, this is not a bug in ext:headless RequestToken is TYPO3 core feature. Domain is not set up because, nonce cookies are set for current request, this is by core team design.

What is your domain(s) setup? How are you calling headless API from frontend application?

yannkuesthardt commented 3 months ago

Hi @twoldanski

thanks for the fast response and sorry for the mislabel.

The actual domains, as defined in the site config, are as follows: backend.example.com frontend.example.com

However the the frontend is setup to proxy all requests from frontend.example.com/api/... to backend.example.com/...

While the cookie domain setup works for most cookies, as backend and frontend cookies are set to ".example.com", this does not work for the Nonce Cookies. Those are always set to backend.example.com

twoldanski commented 3 months ago

@yannkuesthardt Do no worry about it, I just wanted to clarify things.

Do yo use https://github.com/TYPO3-Headless/nuxt-typo3 as base for your frontend application?

From data, you provided I think is something with your setup of proxy /api/

TYPO3 do not set up domain for nonce cookies, so if you sent request to backend.example.com you will set cookie to backend.example.com but if you send request via /api it should setup cookie to frontend.example.com, and if you send request to login form via /api correctly it should receive all data & nonce cookie to verify request.

yannkuesthardt commented 3 months ago

@twoldanski Yes, we are using https://github.com/TYPO3-Headless/nuxt-typo3 for our frontend. It is setup as follows:

Nuxt Config

export default defineNuxtConfig({
  ...
  typo3: {
    api: {
      baseUrl: "https://frontend.example.com/api",
      headers: headers,
      endpoints: {
        initialData: "/",
        initialDataFallback: "/",
      },
    ...
  },
  runtimeConfig: {
    public: {
      baseUrlBackend: "https://backend.example.com",
    },
  },
  ...

Nginx Frontend

...
location /api {
    expires 0;
    proxy_set_header Host backend.example.com;
    proxy_pass https://backend.example.com/;
}
...

I noticed that the Nonce Cookie does get set to frontend.example.com if I navigate to the page from another page. However this does not fix the login, as it still fails. If I open the login page directly via link no cookie gets set. The only cookies I see are old ones.

EDIT The response shows that a cookie should be set, when navigating from another page to the login page, but when using third party tools or the "Application" Tab in Chrome I cannot see those cookies. For direct access I can't tell if a cookie should be set, as the initial response from NUXT doesn't pass on set cookies. Reponse Cookies Currently set cookies

twoldanski commented 3 months ago

@yannkuesthardt I think your issue lies in configuration of nuxt add those lines to the typo3.api

"proxyReqHeaders": ["cookie"],
"proxyHeaders": ["set-cookie"],
yannkuesthardt commented 3 months ago

@twoldanski that helped with the cookies, but the login is still failing from the frontend. Do you have any other ideas?

twoldanski commented 3 months ago

@yannkuesthardt did you tried clear all cookies (from previous attempts) ? Because with fixed config it should work just fine, I assume of course you have valid SSL certificates, correct?

yannkuesthardt commented 3 months ago

@twoldanski I have tried clearing all cookies and using Inkognitomode to test, but that doesn't help. SSL is setup up both for front and backend. What I did notice is that the behavior seems to have changed, where I had to navigate within the frontend for the cookie to be set correctly this morning, but now it only seems to be set when using a hard-reload in chrome. I'm not sure if this is a browser or TYPO3 cache issue. Never the less I can still recreate the problem where login via postman works but login via frontend fails (even with the cookie set in both cases).

twoldanski commented 3 months ago

@yannkuesthardt to the typo3.api add also credentials: 'include'

yannkuesthardt commented 3 months ago

@twoldanski That solved it. Thank you so much for all the help!