I am building a Vue.js web app and a Node.js/Express REST API.
When sending cookies after login, they are received, but not send back with the next request.
Node.js/Express REST API (running locally over HTTP (not HTTPS) on http://localhost:3000
)
CORS is enabled using middleware with the following options:
app.use(require('cors')({
origin: ['http://127.0.0.1:8080', 'http://localhost:8080'],
methods: 'GET,POST,PUT,DELETE',
credentials: true
}))
After a successful login (which required a successful OPTIONS/preflight request), the response looks as follows:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8080
Content-Type: application/json; charset=utf-8
Vary: Origin
Set-Cookie: session=XXX; Max-Age=604800; Path=/api/v0; Expires=Thu, 02 Apr 2020 15:36:42 GMT; HttpOnly; SameSite=Lax
Set-Cookie: token=XXX; Max-Age=1800; Path=/api/v0; Expires=Thu, 26 Mar 2020 16:06:42 GMT; HttpOnly; SameSite=Lax
X-XSS-Protection: 1; mode=block
Date: Thu, 26 Mar 2020 15:36:42 GMT
Access-Control-Allow-Credentials: true
Content-Length: 203
Connection: keep-alive
X-Content-Type-Options: nosniff
ETag: W/"cb-dRDu0E2yjk3BHs7J/aXoYLLzsGM"
X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
X-Download-Options: noopen
Strict-Transport-Security: max-age=15552000; includeSubDomains
So to reiterate: cookies are set including Max-Age
, Path
, Expires
, HttpOnly
, and SameSite=Lax
parameters after a successful CORS OPTIONS preflight request.
Vue.js web app using Axios (running locally over HTTP (not HTTPS) on http://localhost:8080
)
Requests are sent using Axios with the withCredentials: true
option. With Firefox, the token and session cookies are automatically included as a Cookie: session=XXX; token=XXX
header, but on Safari they are not.
import Axios, { AxiosResponse } from 'axios'
const API = Axios.create({
baseURL: 'http://127.0.0.1:3000/api/v0',
timeout: 5000,
withCredentials: true
})
...
async login(email: string, password: string): Promise<AuthenticationResponse> {
return handleResponse(API.post('/auth/login', { email, password }))
}
...
async getUserById(id: string): Promise<UserResponse> {
return handleResponse(API.get('/users/' + id))
}
How can I solve this? Is Safari safer in some way that it is not willing to send the cookies? What settings do I change on the frontend or backend?
I figured it out and it's ridiculous...
Navigate to the web app using 127.0.0.1:8080
instead of localhost:8080
and everything works as intended.