angularsymfonyjwthttponlycookie-httponly

HttpOnly cookie does not get passed in request


I'm trying to implement markitosgv/JWTRefreshTokenBundle in my symfony project in order to get a way to refresh my JWT token. For this, I want to generate an HttpOnly cookie, which is something supported by the bundle.

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. But it doesn't seem to work.

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?

EDIT: Here's my bundle config concerning the cookie:

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

Solution

  • Ok so the reason why my refresh token wasn't passed when requesting /api/token/refresh was because you need to use withCredentials: true in the "refresh" request itself, but also when calling the initial "login" route!

    Using this option only on the "refresh" route is not enough to make it works