Token Swap
Token Swap provides an authenticatiow flow where client-side apps (like CLI/desktop/mobile apps) are still able to use long-living tokens and the opportunity to refresh them without exposing your application's secret. This however requires a server-side part to work.
It is based on the Authorization Code flow and is also documented by Spotify: Token Swap and Refresh .
Flow
The client uses the first part of the Authorization Code
flow and redirects the user to Spotify's login page. In this part, only the client id is required. Once the user logged in and confirmed the usage of your app, they will be redirect to a http://localhost
server which grabs the code
from the query parameters.
var request = new LoginRequest("http://localhost", "ClientId", LoginRequest.ResponseType.Code)
{
Scope = new List<string> { Scopes.UserReadEmail }
};
BrowserUtil.Open(uri);
Now, swapping out this code
for an access_token
would require the app's client secret. We don't have this on the client-side. Instead, we send a request to our server, which takes care of the code swap:
public Task GetCallback(string code)
{
var response = await new OAuthClient().RequestToken(
new TokenSwapTokenRequest("https://your-swap-server.com/swap", code)
);
var spotify = new SpotifyClient(response.AccessToken);
// Also important for later: response.RefreshToken
}
The server swapped out the code
for an access_token
and refresh_token
. Once we realize the access_token
expired, we can also ask the server to refresh it:
// if response.IsExpired is true
var newResponse = await new OAuthClient().RequestToken(
new TokenSwapTokenRequest("https://your-swap-server.com/refresh", response.RefreshToken)
);
var spotify = new SpotifyClient(newResponse.AccessToken);
Server Implementation
The server needs to support two endpoints, /swap
and /refresh
(endpoints can be named differently of course).
Swap
The client sends a body via application/x-www-form-urlencoded
where the received code
is included. In cURL:
curl -X POST "https://example.com/v1/swap"\
-H "Content-Type: application/x-www-form-urlencoded"\
--data "code=AQDy8...xMhKNA"
The server needs to respond with content-type application/json
and the following body:
{
"access_token" : "NgAagA...Um_SHo",
"expires_in" : "3600",
"refresh_token" : "NgCXRK...MzYjw"
}
Refresh
The client sends a body via application/x-www-form-urlencoded
where the received refresh_token
is included. In cURL:
curl -X POST "https://example.com/v1/refresh"\
-H "Content-Type: application/x-www-form-urlencoded"\
--data "refresh_token=NgCXRK...MzYjw"
The server needs to respond with content-type application/json
and the following body:
{
"access_token" : "NgAagA...Um_SHo",
"expires_in" : "3600"
}
Example
An example server has been implemented in Node.JS with a .NET CLI client, located at Example.TokenSwap.