Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] 'jwt.refresh-token.revoke' event not send out when using '/api/logout' #1522

Closed
sneakylenny opened this issue Dec 15, 2021 · 9 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@sneakylenny
Copy link

sneakylenny commented Dec 15, 2021

'jwt.refresh-token.revoke' event not send out when using '/api/logout'

Description

When I use /api/logout to logout it does not end out an jwt.refresh-token.revoke event. But it does revoke the token.

Affects versions

I am running version 1.31.0

Steps to reproduce

Steps to reproduce the behavior:

  1. Setup JWT auth with refresh-token in front-end app
  2. Enable webhook in Fusionauth and enable all events
  3. Setup webhook listener in API app
  4. Login
  5. Logout using /api/logout and make sure refresh_token cookie is send too
  6. Receive no event

Expected behavior

I expect the event to be sent, but it only gets sent if I globally log out or when I manually remove it in the GUI.

Screenshots

When logging out:

FusionAuthRevokeEvent1

When deleting token manually:

FusionAuthRevokeEvent2
Event is also present when request is made to /logout?global=true

Platform

(Please complete the following information)

  • Device: Desktop
  • OS: Windows 10 Pro
  • Browser + version: FireFox 95.0 (64-bit)
  • Database: MySQL version 8.0.23

Additional context

Is this by design? Do I need to make an additional request to DELETE /api/jwt/refresh?token=xxx?
Or is it a bug?

Also:

Feature request: Check if jwt's refresh token is revoked on GET /api/jwt/validate
Could be done by sending an extra param like ?refreshvalid=true

@robotdan
Copy link
Member

Thanks for the excellent write up @TimVanHerwijnen much appreciated. We'll take a look.

@robotdan
Copy link
Member

This should work.

Can you captcha a HAR file for the HTTP request to /api/logout if you're doing it in the browser, or otherwise capture the full HTTP request and response to that API?

@robotdan robotdan added the bug Something isn't working label Dec 17, 2021
@sneakylenny
Copy link
Author

sneakylenny commented Dec 20, 2021

I generated a HAR file containing only a request to /api/logout
This file was created using FireFox dev tools

localhost_Archive [21-12-20 12-20-47].har
{
  "log": {
    "version": "1.2",
    "creator": {
      "name": "Firefox",
      "version": "95.0.1"
    },
    "browser": {
      "name": "Firefox",
      "version": "95.0.1"
    },
    "pages": [
      {
        "startedDateTime": "2021-12-20T12:20:32.172+01:00",
        "id": "page_1",
        "title": "fusionauth-test",
        "pageTimings": {
          "onContentLoad": -1,
          "onLoad": -1
        }
      }
    ],
    "entries": [
      {
        "pageref": "page_1",
        "startedDateTime": "2021-12-20T12:20:32.172+01:00",
        "request": {
          "bodySize": 0,
          "method": "POST",
          "url": "http://localhost:8080/auth/api/logout",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Host",
              "value": "localhost:8080"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0"
            },
            {
              "name": "Accept",
              "value": "application/json, text/plain, */*"
            },
            {
              "name": "Accept-Language",
              "value": "en-US,en;q=0.5"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate"
            },
            {
              "name": "Authorization",
              "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZhOTA1MWJiZDQifQ.eyJhdWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJleHAiOjE2Mzk5OTkyODMsImlhdCI6MTYzOTk5OTIyMywiaXNzIjoiaHR0cHM6Ly9hdXRoLmhhYmRlc2submwvIiwic3ViIjoiOGE1YzJkMzUtNjJhOS00NGQyLTkxYjYtM2MzY2Q4N2ZhMTIyIiwianRpIjoiMmMzNzRkZWMtNjNlMi00ZGM0LWIxZWItNGU1ODVjZTFlZmQ2IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0dXplciIsImFwcGxpY2F0aW9uSWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJyb2xlcyI6W119.j1PHwh3mDcQVzCex6bhoikJUoda086fRckM1KT10AAo"
            },
            {
              "name": "Origin",
              "value": "http://localhost:8080"
            },
            {
              "name": "DNT",
              "value": "1"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Referer",
              "value": "http://localhost:8080/profile"
            },
            {
              "name": "Cookie",
              "value": "fusionauth.locale=en_US; fusionauth.sso=AoQugTR1zcIbOOTxd4Z_ghfRi_-oKHGtocPQi_TH00sL; fusionauth.known-device.UOqL73mIrTbvuuosjOSHf6c2ZQ2cOLmOm0pJ-7JzVx4=a4C7fwQRdjKKbEPQYffpTkJAYA-DZ7y9DYsR7XsTcpBUWj16V7rXpHRYhwdvmWJk; fusionauth.remember-device=O3GEKSsnjEfF4kLy2EbjcVSlVL8LHHaSYe2YHgD6q_M=; fusionauth.session=lU69fVN_x_nbHnCxewNi8iOQdUKsqdQf3gnOYdGQH-BiltpmSYOe-g; auth.strategy=local; auth._token.local=Bearer%20eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZhOTA1MWJiZDQifQ.eyJhdWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJleHAiOjE2Mzk5OTkyODMsImlhdCI6MTYzOTk5OTIyMywiaXNzIjoiaHR0cHM6Ly9hdXRoLmhhYmRlc2submwvIiwic3ViIjoiOGE1YzJkMzUtNjJhOS00NGQyLTkxYjYtM2MzY2Q4N2ZhMTIyIiwianRpIjoiMmMzNzRkZWMtNjNlMi00ZGM0LWIxZWItNGU1ODVjZTFlZmQ2IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0dXplciIsImFwcGxpY2F0aW9uSWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJyb2xlcyI6W119.j1PHwh3mDcQVzCex6bhoikJUoda086fRckM1KT10AAo; auth._token_expiration.local=1639999283000; auth._refresh_token.local=TSPizlQVBYjsf0zY7omOYHO94mNjvc3UxRZKIMBKoqoIbf_Pq97qSw; auth._refresh_token_expiration.local=1642591224011; io.fusionauth.app.action.admin.webhook.TestAction$eventType=MeVc6p-AVrSExzjtxyAbxarJ2wr2XexnCWmYtCbaWGHneQTyRq5Oi2YjV4SCFkk3; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZhOTA1MWJiZDQifQ.eyJhdWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJleHAiOjE2Mzk5OTkyODMsImlhdCI6MTYzOTk5OTIyMywiaXNzIjoiaHR0cHM6Ly9hdXRoLmhhYmRlc2submwvIiwic3ViIjoiOGE1YzJkMzUtNjJhOS00NGQyLTkxYjYtM2MzY2Q4N2ZhMTIyIiwianRpIjoiMmMzNzRkZWMtNjNlMi00ZGM0LWIxZWItNGU1ODVjZTFlZmQ2IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0dXplciIsImFwcGxpY2F0aW9uSWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJyb2xlcyI6W119.j1PHwh3mDcQVzCex6bhoikJUoda086fRckM1KT10AAo; refresh_token=TSPizlQVBYjsf0zY7omOYHO94mNjvc3UxRZKIMBKoqoIbf_Pq97qSw"
            },
            {
              "name": "Sec-Fetch-Dest",
              "value": "empty"
            },
            {
              "name": "Sec-Fetch-Mode",
              "value": "cors"
            },
            {
              "name": "Sec-Fetch-Site",
              "value": "same-origin"
            },
            {
              "name": "Sec-GPC",
              "value": "1"
            },
            {
              "name": "Content-Length",
              "value": "0"
            }
          ],
          "cookies": [
            {
              "name": "fusionauth.locale",
              "value": "en_US"
            },
            {
              "name": "fusionauth.sso",
              "value": "AoQugTR1zcIbOOTxd4Z_ghfRi_-oKHGtocPQi_TH00sL"
            },
            {
              "name": "fusionauth.known-device.UOqL73mIrTbvuuosjOSHf6c2ZQ2cOLmOm0pJ-7JzVx4",
              "value": "a4C7fwQRdjKKbEPQYffpTkJAYA-DZ7y9DYsR7XsTcpBUWj16V7rXpHRYhwdvmWJk"
            },
            {
              "name": "fusionauth.remember-device",
              "value": "O3GEKSsnjEfF4kLy2EbjcVSlVL8LHHaSYe2YHgD6q_M="
            },
            {
              "name": "fusionauth.session",
              "value": "lU69fVN_x_nbHnCxewNi8iOQdUKsqdQf3gnOYdGQH-BiltpmSYOe-g"
            },
            {
              "name": "auth.strategy",
              "value": "local"
            },
            {
              "name": "auth._token.local",
              "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZhOTA1MWJiZDQifQ.eyJhdWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJleHAiOjE2Mzk5OTkyODMsImlhdCI6MTYzOTk5OTIyMywiaXNzIjoiaHR0cHM6Ly9hdXRoLmhhYmRlc2submwvIiwic3ViIjoiOGE1YzJkMzUtNjJhOS00NGQyLTkxYjYtM2MzY2Q4N2ZhMTIyIiwianRpIjoiMmMzNzRkZWMtNjNlMi00ZGM0LWIxZWItNGU1ODVjZTFlZmQ2IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0dXplciIsImFwcGxpY2F0aW9uSWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJyb2xlcyI6W119.j1PHwh3mDcQVzCex6bhoikJUoda086fRckM1KT10AAo"
            },
            {
              "name": "auth._token_expiration.local",
              "value": "1639999283000"
            },
            {
              "name": "auth._refresh_token.local",
              "value": "TSPizlQVBYjsf0zY7omOYHO94mNjvc3UxRZKIMBKoqoIbf_Pq97qSw"
            },
            {
              "name": "auth._refresh_token_expiration.local",
              "value": "1642591224011"
            },
            {
              "name": "io.fusionauth.app.action.admin.webhook.TestAction$eventType",
              "value": "MeVc6p-AVrSExzjtxyAbxarJ2wr2XexnCWmYtCbaWGHneQTyRq5Oi2YjV4SCFkk3"
            },
            {
              "name": "access_token",
              "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZhOTA1MWJiZDQifQ.eyJhdWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJleHAiOjE2Mzk5OTkyODMsImlhdCI6MTYzOTk5OTIyMywiaXNzIjoiaHR0cHM6Ly9hdXRoLmhhYmRlc2submwvIiwic3ViIjoiOGE1YzJkMzUtNjJhOS00NGQyLTkxYjYtM2MzY2Q4N2ZhMTIyIiwianRpIjoiMmMzNzRkZWMtNjNlMi00ZGM0LWIxZWItNGU1ODVjZTFlZmQ2IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0dXplciIsImFwcGxpY2F0aW9uSWQiOiJhZGYyMzAzMi1lMTMzLTQ4OTAtYTAwOS1jNzA3NTFhYmJkMTgiLCJyb2xlcyI6W119.j1PHwh3mDcQVzCex6bhoikJUoda086fRckM1KT10AAo"
            },
            {
              "name": "refresh_token",
              "value": "TSPizlQVBYjsf0zY7omOYHO94mNjvc3UxRZKIMBKoqoIbf_Pq97qSw"
            }
          ],
          "queryString": [],
          "headersSize": 2956
        },
        "response": {
          "status": 200,
          "statusText": "OK",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "set-cookie",
              "value": "access_token=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; SameSite=Lax"
            },
            {
              "name": "set-cookie",
              "value": "refresh_token=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; SameSite=Lax"
            },
            {
              "name": "set-cookie",
              "value": "access_token=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; SameSite=Lax"
            },
            {
              "name": "cache-control",
              "value": "no-cache"
            },
            {
              "name": "content-length",
              "value": "0"
            },
            {
              "name": "date",
              "value": "Mon, 20 Dec 2021 11:20:32 GMT"
            },
            {
              "name": "connection",
              "value": "close"
            }
          ],
          "cookies": [
            {
              "name": "access_token",
              "value": ""
            },
            {
              "name": "refresh_token",
              "value": ""
            },
            {
              "name": "access_token",
              "value": ""
            }
          ],
          "content": {
            "mimeType": "text/xml",
            "size": 0,
            "text": ""
          },
          "redirectURL": "",
          "headersSize": 391,
          "bodySize": 391
        },
        "cache": {},
        "timings": {
          "blocked": 0,
          "dns": 0,
          "connect": 1,
          "ssl": 0,
          "send": 0,
          "wait": 127,
          "receive": 0
        },
        "time": 128,
        "_securityState": "insecure",
        "serverIPAddress": "127.0.0.1",
        "connection": "8080"
      }
    ]
  }
}

Edit
To give more context to this request and to clear things up:
I'm using Nuxt where I proxy all requests on http://localhost:8080/ with ^/auth/ to http://localhost:9011/ removing auth/
So http://localhost:8080/auth/api/logout is proxied to http://localhost:9011/api/logout
This way cookies get sent over without having to worry about CORS.

@robotdan
Copy link
Member

Thanks for the .har file.

The fact that the response contains a Set-Cookie response header for refresh_token means we recognized you sent it to the Logout endpoint and that we subsequently revoked it.

I think you mentioned you can confirm the refresh token is deleted/revoked, but you are just not seeing the webhook get fired?

The proxy changing the path seems like it could be factor, although the request and response look correct. So all signs seem to indicate that the proxy is behaving and ensuring the correct cookies get picked up and returned.

So nothing is jumping out at me why we wouldn't be sending the event. What is a little strange is that the response contains a duplicate Set-Cookie header for access_token, that doesn't make any sense to me. Perhaps that is a side effect of the proxy?

@sneakylenny
Copy link
Author

sneakylenny commented Dec 21, 2021

I think you mentioned you can confirm the refresh token is deleted/revoked, but you are just not seeing the webhook get fired?

Correct

I don't think the setup matters all that much since the user is logged out and the session/refresh token is revoked. This issue also happens using postman when directly contacting the Fusionauth server. It must be something in the Fusionauth server not recognizing the cookie and thus not firing the event. Since it does fire when manually deleting/revoking sessions/refresh tokens.


Re-install

To make sure nothing is configured wrong I re-installed Fusionauth.
After that I ran the setup, filling in database credentials etc.
I created a tenant "TestTenant", only changed token Issuer to http://subdom.domain.nl/
I created an application where I changed the following settings:

# Name: test
# Tenant: TestTenant
------------------------------
// Security > Login API settings
Require an API key: false
Generate Refresh Tokens: true
Enable JWT refresh: true

Enabled webhook on all events and set to http://localhost:8000/webhook
-- This points to a laravel app with a controller that logs everything it receives and creates blacklist entries when jwt.refresh-token.revoke is received.

Revoking tokens

Requests tested with Nuxt app and Postman

Event does fire:

  • Manually deleting all or single tokens
  • Sending request POST /api/logout?global=true
  • Sending request DELETE /api/jwt/refresh?token={refresh_token}

Event does not fire:

  • Sending request to POST /api/logout with cookie refresh_token
  • Sending request to POST /api/logout?refreshToken={refresh_token}

Conclusion

I think it's a bug of some sort, but I think I will resort to using DELETE /api/jwt/refresh?token={refresh_token} as a way of "logging out" until we know more on what causes this bug.

@robotdan
Copy link
Member

Thanks for the additional information.

Regarding the scenarios that do not work, are you using the Set-Cookie header, or letting Postman send the cookie for you? As a control, can you try using cURL or something less sophisticated than Postman?

We can also see if we can try to simulate your config and see if we can get a recreate.

@robotdan
Copy link
Member

I think I recreated the issue.. fix forthcoming.

@sneakylenny
Copy link
Author

sneakylenny commented Dec 24, 2021

You're amazing, I've got to say I've never seen anyone as fast and helpful on GH like you. Keep up the good work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants