Token Swap Service for Spotify π β
This is a tiny Ruby service for supporting Authorization Code Flow on Spotify integrations with:
- iOS Apps
- Android Apps
- Static Web Apps
Contents π
Intro
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.
Install
One-click with Heroku
Just click that button below. Fill in the form and it'll work like magic. β¨
Manual Install
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
How It Works
When authenticating users with your Spotify application, you can authenticate them through two ways: Implicit Grant Flow and Authorization Code Flow.
Implicit Grant 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.
Authorization Code Flow
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.
Configuration
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.
API
POST /api/token
Request (cURL)
$ curl -X POST -d "code=[code]" https://yourapp.herokuapp.com/api/token
Request (CLI)
$ bin/token "[code]"
JSON Response
{
"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"
}
POST /api/refresh_token
Request (cURL)
$ curl -X POST -d "refresh_token=[refresh token]" https://yourapp.herokuapp.com/api/refresh_token
Request (CLI)
$ bin/refresh_token "[refresh token]"
JSON Response
{
"access_token":
"BQCjHuWkG2pSAFaa7-zQJQWjylilINTpUbfRbRgJtAMJrBF9h3vg-N6bnaG9XCKYE8ceAsGgTGwbeO8MfbZKlYbyHG4B7EOeIUlTo0wn08PgkQZGjBzMYQwzNwr_pmel4pCgKOiEyH9Zc8L6iss3anLSSg6IWag",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "user-read-private"
}
CLI
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
$ bin/token "[code]"
bin/refresh_token
$ bin/refresh_token "[refresh token]"
Code Samples
Objective-C with Spotify iOS SDK
// Swapping code for access_token
NSURL *swapServiceURL = [NSURL urlWithString:@"http://yourapp.herokuapp.com/api/token"];
[SPAuth handleAuthCallbackWithTriggeredAuthURL:url
tokenSwapServiceEndpointAtURL:swapServiceURL
callback:callback];
Swift
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]"])
Ruby
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
JavaScript
// 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());
Error Handling
The Token Swap Service will either return an error from our server, or a forwarded error from the Spotify Accounts API.
Token Swap Service
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.
Spotify Accounts API
It will look something like this:
{
"error": "invalid_grant",
"error_description": "Invalid authorization code"
}
Read the Authorization Guide for more information.
Contributing
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
.
Credits
This project was built from SpotifyTokenSwap by @simontaen in 2014, and the encryption of refresh tokens was taken from their work.