HttpCookie not sent to API
geoffroyp opened this issue · 4 comments
Hi guys,
I'm trying to implement this bundle in my symfony project in order to get a way to refresh my JWT token. It seems to work well (minus some other minor problems) if I'm using the token and not the HttpOnly cookie.
However, I want to use the HttpOnly option since it's way more secure this way (cannot be read by JS + I'm not storing JWT and refresh token at the same place)
Here's my config for the bundle:
gesdinet_jwt_refresh_token:
# ...
ttl: 62000
return_expiration: true
cookie:
enabled: true
same_site: lax
path: /
domain: mysite.com
http_only: true
secure: true
remove_token_from_body: true
When I log in from my frontend (angular 13), I get my JWT token (from lexik/LexikJWTAuthenticationBundle
) , as well as set-cookie
header like this:
Request URL: https://api.mysite.com/api/login_check
Request Method: POST
Status Code: 200 OK
Remote Address: 192.168.1.43:443
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://front.mysite.com:4200
Access-Control-Expose-Headers: link
Cache-Control: no-cache, private
Connection: Keep-Alive
Content-Type: application/json
Date: Mon, 25 Apr 2022 15:54:30 GMT
Keep-Alive: timeout=5, max=99
Server: Apache/2.4.41 (Ubuntu)
Set-Cookie: refresh_token=a2615d6dd2986680fd79807c61d050424b4e290090a4beaf1f1063c0c8f1807681d86c1c07216630a629667e711897dbae7a6083884d3f19b028aa72f9bbca84; expires=Tue, 26-Apr-2022 09:07:50 GMT; Max-Age=62000; path=/; domain=mysite.com; secure; httponly; samesite=lax
Transfer-Encoding: chunked
X-Debug-Token: e31102
X-Debug-Token-Link: https://api.mysite.com/_profiler/e31102
X-Robots-Tag: noindex
Of course, I cannot check if the cookie has been created or not, since it's HttpOnly
Then in my angular, I have a test button with the following simple code:
onCallRefreshToken() {
this.http.post('https://api.mysite.com/api/token/refresh', {site:2}, {withCredentials: true}).subscribe((datas) =>{
console.log('datas', datas);
});
}
and when I run it, I get the following error: [401] Missing JWT Refresh Token
If dump the request inside sympfony, I see that $request->cookies->parameters
is empty. And when I look at the sent request from Chrome inspector, I see the following:
Request URL: https://api.mysite.com/api/token/refresh
Request Method: POST
Status Code: 401 Unauthorized
Remote Address: 192.168.1.43:443
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://front.mysite.com:4200
Access-Control-Expose-Headers: link
Cache-Control: no-cache, private
Connection: Keep-Alive
Content-Type: application/json
Date: Mon, 25 Apr 2022 16:00:44 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.41 (Ubuntu)
Transfer-Encoding: chunked
Vary: Authorization
X-Debug-Token: 54c0bb
X-Debug-Token-Link: https://api.mysite.com/_profiler/54c0bb
X-Robots-Tag: noindex
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
Authorization: Bearer AVeryLongAndValidTokenHere
Connection: keep-alive
Content-Length: 10
Content-Type: application/json
Host: api.mysite.com
Origin: https://front.mysite.com:4200
Referer: https://front.mysite.com:4200/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
(JWT token removed on purprose)
So as you can see, th cookie doesn't seem to be passed in the request, which would obviously explain why I don't get it in my symfony API.
So from what I read, the way to "configure" the angular http call in order to pass the HttpOnly cookie was by setting options to "withCredentials" to true, which I did, but as you can see nothing seems to be sent.
Note that I don't seem to have any CORS issue (same domain, secure, allow-credential to true
) and HTTPS is working fine
Is there something I am doing wrong? Do you have any idea? Am I not calling the API the right way? Could it be a "wrong error", and the real error is somewhere else?
Thanks!
https://front.mysite.com:4200
is a different origin than https://api.mysite.com/
.
You're setting the cookie's domain to mysite.com
but your JavaScript runs in the context of front.mysite.com:4200
. You could try messing with document.domain = "mysite.com"
, but it's probably easier to configure your dev environment to use same_site: none
. You shouldn't have this issue in production, as you likely won't run the frontend on a non-standard port.
For reference, my configuration is as follows:
- (React) front-end on
http://localhost:3000
- API on
https://localhost/api/
# config/packages/gesdinet_jwt_refresh_token.yaml
gesdinet_jwt_refresh_token:
refresh_token_class: App\Entity\RefreshToken
ttl: 7200
single_use: true
cookie:
enabled: true
path: /api/token/
# config/packages/dev/gesdinet_jwt_refresh_token.yaml
gesdinet_jwt_refresh_token:
cookie:
same_site: none
Yes I thought about that and tried to put none
as well. Did not change anything, the error still remain the same,, [401] Missing JWT Refresh Token
I have tried many configuration otpion, and still end up with the same message. I always left path
to /
, though, So I tried to change it for /api/token
(like you), and /api/token/refresh
(like my endpoint for refresh), and still the same problem...
At this point, I'm not even sure if it's a bundle problem or angular problem. But from what I read there was not a million ways to pass the cookie with angular...
You could rule it out by hitting the API directly. For example using postman to authenticate, receive the cookie, and then hit the refresh endpoint.
Also keep in mind that the intial authentication request must also set withCredentials: true
in order to store the cookie in the first place.
Also keep in mind that the intial authentication request must also set
withCredentials: true
in order to store the cookie in the first place.
Wow! thank you so, SO much! I didn't know that and this was indeed the problem here. Now it works perfectly! :)
I know that somehow it's not related to the bundle itself, but maybe it would be a nice addition to the documentation (as a reminder, or something like that)
Anyway: thanks again! You made my day!