This is a tiny Ruby service for supporting Authorization Code Flow on Spotify integrations with:
- iOS Apps
- Android Apps
- Static Web Apps
When should I use Authorization Code Flow instead of Implicit Grant Flow?
- You don't want users to have to re-authenticate every 60 minutes.
- You don't want to insecurely expose your client secret to third parties.
Read more about token swapping on Spotify for Developers.
Just click that button below. Fill in the form and it'll work like magic. ✨
Install the project locally:
$ git clone https://github.com/bih/spotify-token-swap-service.git
$ cd spotify-token-swap-service/
$ bundle install
Then to run the server:
$ cp .sample.env .env
$ vim .env
$ rackup
When authenticating users with your Spotify application, you can authenticate them through two ways: Implicit Grant Flow and Authorization Code Flow.
You don't need to setup this service, and you can close your window.
The Implicit Grant Flow returns an access_token
directly back to your application once the user has authorized your application. It expires in 60 minutes, after which the user has to re-authorize your application.
Recommended
The Authorization Code Flow returns a code
directly back to your application once the user has authorized your application. This code
can be exchanged for an access_token
through the Spotify Accounts API.
This could be performed directly inside of your iOS, Android, or static web apps and will work as intended - but it is extremely insecure as it exposes your client secret to the world. This should never be done for production apps, ever.
The right way is to handle the "exchange" on a server and have your application call that server. This would securely store your client secret away from developers who might reverse engineer your iOS, Android, or static web apps. This repository contains said simple exchange server.
There are several environment variables you'll need to set:
Environment Variable | Description | Required |
---|---|---|
SPOTIFY_CLIENT_ID |
A valid client ID from Spotify for Developers. | Required ✅ |
SPOTIFY_CLIENT_SECRET |
A valid client secret from Spotify for Developers. | Required ✅ |
SPOTIFY_CLIENT_CALLBACK_URL |
A registered callback from Spotify for Developers. | Required ✅ |
ENCRYPTION_SECRET |
A random "salt" for securing your refresh token. Grab one here. | Optional ╳ |
As mentioned in Manual Install, these are all outlined in .sample.env
which you can move over to .env
and modify with your respective credentials.
$ curl -X POST -d "code=[code]" https://yourapp.herokuapp.com/api/token
$ bin/token "[code]"
{
"access_token":
"BQDjrNCJ66N1utnFnpgcPZy8yD8KSsGN_zC1qP6jg1xeWfCl_slv8LGig_ia8bHynxFuSs-PvmHp-_6U13cBPR8469s66KmWxxdOsHCN00Gg5AgX3wyZYJLX0V-HqiXqCNdzDVShlzFaPEHJbKbm73TWJDHTG4c",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token":
"p7jJ+3agZ8m9aBMZdiTq85wqNIl16ctbMgCPFOlRBanVgB+kht2hDmrCDL5V\nvRFQS9s1vBsWkpBCC0kbA6srol8NrKaHzY1tNrvDRFoN7xumQId8agd6Tqs6\nM8ypEhvTDElFbt1cMxd+N3z0JG3gSmOPk2h8/idwVBub0cqyCSacf4GPpnwW\nCg==\n",
"scope": "user-read-private"
}
$ curl -X POST -d "refresh_token=[refresh token]" https://yourapp.herokuapp.com/api/refresh_token
$ bin/refresh_token "[refresh token]"
{
"access_token":
"BQCjHuWkG2pSAFaa7-zQJQWjylilINTpUbfRbRgJtAMJrBF9h3vg-N6bnaG9XCKYE8ceAsGgTGwbeO8MfbZKlYbyHG4B7EOeIUlTo0wn08PgkQZGjBzMYQwzNwr_pmel4pCgKOiEyH9Zc8L6iss3anLSSg6IWag",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "user-read-private"
}
We have two binaries included, which allows us to test our credentials easily. Before running these commands, make sure you have run the following:
$ git clone https://github.com/bih/spotify-token-swap-service.git
$ cd spotify-token-swap-service/
$ bundle install
$ cp .sample.env .env
$ vim .env
$ bin/token "[code]"
$ bin/refresh_token "[refresh token]"
// Swapping code for access_token
NSURL *swapServiceURL = [NSURL urlWithString:@"http://yourapp.herokuapp.com/api/token"];
[SPAuth handleAuthCallbackWithTriggeredAuthURL:url
tokenSwapServiceEndpointAtURL:swapServiceURL
callback:callback];
This is using the Alamofire Swift Framework.
import Alamofire
// Swapping code for access_token
Alamofire.request(.POST, "https://yourapp.herokuapp.com/api/token", ["code": "[code]"])
// Swapping refresh_token for access_token
Alamofire.request(.POST, "https://yourapp.herokuapp.com/api/refresh_token", ["refresh_token": "[refresh token]"])
This is using the HTTParty gem.
require "httparty"
# Swapping code for access_token
HTTParty.post("https://yourapp.herokuapp.com/api/token", body: {
code: "[code]"
}).parsed_response
# Swapping refresh_token for access_token
HTTParty.post("https://yourapp.herokuapp.com/api/refresh_token", body: {
refresh_token: "[refresh token]"
}).parsed_response
// Swapping code for access_token
fetch("https://yourapp.herokuapp.com/api/token", {
method: "POST",
body: JSON.stringify({
code: "[code]"
})
}).then(res => res.json());
// Swapping refresh_token for access_token
fetch("https://yourapp.herokuapp.com/api/refresh_token", {
method: "POST",
body: JSON.stringify({
refresh_token: "[refresh token]"
})
}).then(res => res.json());
The Token Swap Service will either return an error from our server, or a forwarded error from the Spotify Accounts API.
It returns a JSON response with an error
key, like as follows:
{ "error": "invalid refresh_token" }
See spotify_token_swap_service.rb for more information.
It will look something like this:
{
"error": "invalid_grant",
"error_description": "Invalid authorization code"
}
Read the Authorization Guide for more information.
This project adheres to the Open Code of Conduct. By participating, you are expected to honor this code.
Clone the repository and make a new branch:
$ git clone https://github.com/bih/spotify-token-swap-service.git
$ cd spotify-token-swap-service/
$ git checkout -b new-feature-branch
Access the console:
$ bin/console
Run tests:
$ bundle exec rake spec
All of the main code exists inside of spotify_token_swap_service.rb
.
This project was built from SpotifyTokenSwap by @simontaen in 2014, and the encryption of refresh tokens was taken from their work.