Recently, I wanted to implement a simple login form in my Vue.js application, using a JSON Login.
Normally, this is pretty easy and straightforward: Implement the login funtionality as described in the link above, send a POST
request to /login
with email and password and everything else (save the Session Cookie and send it on every following request) is handled automatically.
But this works only if your frontend (Vue) and your backend (Symfony) are on the exact same domain (local.dev
and api.local.dev
are NOT the same domain). Yes, the login may be successful, a session was created and even a Set-Cookie
header with PHPSESSID
was returned, but when you try to send a second request (maybe a GET /currentUser
), you will see, that you are not logged in anymore. But why?
You need to set withCredentials
to true in your XMLHttpRequest. The important part is:
XMLHttpRequest
from a different domain cannot set cookie values for their own domain unlesswithCredentials
is set totrue
before making the request.
So, even when there is a Set-Cookie
header in your response, your browser will not save the cookie. To fix this, you should add
{
// ...
withCredentials: true,
// ...
}
to your global axios configuration. If you are using NuxtJS, you have to create plugins/axiosCredentials.js
:
export default function ({ $axios }) {
$axios.onRequest((config) => {
config.withCredentials = true
return config
})
}
and add it to the plugins section of your nuxt.config.js
export default {
// ...
plugins: ['@/plugins/axiosCredentials.js'],
// ...
}
Then second, easy, part is a little modification in your Symfony configuration:
nelmio_cors:
defaults:
allow_credentials: true
Add allow_credentials: true
to your config/packages/nelmio_cors.yaml
. Leave everything else as it. Without this configuration, the answer to your login attempt will be
Access to XMLHttpRequest at 'http://local.dev:8000/login' from origin 'http://local.dev' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.