ramsayleung / rspotify

Spotify Web API SDK implemented on Rust
MIT License
639 stars 123 forks source link

PKCE Auth - refetch_token triggers status 400 bad request due to revoked refresh token #396

Closed NDoolan360 closed 1 year ago

NDoolan360 commented 1 year ago

Describe the bug The refetch_token method in the BaseClient of AuthCodePkceSpotify keeps the original refresh_token after refetching causing an error response with Status 400 (Bad Request)

To Reproduce Steps to reproduce the behavior:

  1. Create an AuthCodePkceSpotify client configured with token_cache
  2. Refresh the token a number of times
    • Notice that the initial tokens and the first refresh are successful and the access_token is updated, however, the refresh_token remains the same after refresh.
    • On subsequent attempts to refresh, the client errors with Status 400 Bad Request.

Expected behavior I expect the new refresh token returned by the request to be returned by refetch_token and stored in the cache by refresh_token.

Log/Output data log.txt From recreating the request in postman the body is:

{
    "error": "invalid_grant",
    "error_description": "Refresh token revoked"
}

Additional context This appears to occur because of auth_code_pkce.rs line 75


Spotify Community Discussion

A refresh token that has been obtained through PKCE can be exchanged for an access token only once, after which it becomes invalid.


Is this just to do with my use case? Do we know why it is that we need to keep the same refresh_token after the refetch?

ramsayleung commented 1 year ago

I think the refresh token logic the pkce just borrowed from auth_code.rs, we should replace the old refresh token with the new fresh token retuned by the request.

mlehmk commented 1 year ago

The new refresh token is overwritten by the retained refresh token in line 77 of auth_code_pkce.rs of https://github.com/ramsayleung/rspotify/blob/4360c096f2e1d827bd52b998dc3c1bfde18c456d/src/auth_code_pkce.rs Removing that line seems to fix this issue

The PKCE protocol invalidates the old refresh token, due to a protection against token extraction. The token refresh also gives a new refresh token and remembers the old refresh token, so in case a refresh is issued with the old refresh token the whole session is invalidated.

ramsayleung commented 1 year ago

This problem has been fixed, feel free to retry with the latest commit :)