Connecting to the Apple Music API from a Ruby (on Rails) application

At work we often need information about songs, artists, albums etc. Before long we used to get this information from the iTunes API, but more and more Apple is moving services away from there over to the Apple Music API. So we decided to do the legwork and migrate our iTunes calls to Apple Music.

Getting access to the API

What you need from that process is:

  • the private key (it gets saved as AuthKey_<kid>.p8
  • your Music ID you just generated
  • your Developer Team ID (found on the Membership tab of your dev account)

Once you have all that you’re ready to go!

Generating a JSON Web Token

gem 'jwt' # Generate JSON Web Tokens

Generating the token requires a payload and a header.

authentication_payload = {
iss: 'ABCDEFG', # This is your Developer Team ID
iat: Time.now.to_i, # Issue date
exp: Time.now.to_i + 3600 # Expiry of this token.
}
# The file we got from Apple
apple_music_secret = File.read('AuthKey_MusicID.p8')
private_key = OpenSSL::PKey::EC.new(apple_music_secret)
authentication_token = JWT.encode(
authentication_payload,
private_key,
'ES256',
kid: 'YourMusicID'
)

After this you can use authentication_token in your web request headers.

req.headers["Authorization"] = "Bearer #{authentication_token}"

My AppleMusic::Client

class AppleMusic::Client
delegate :get, to: :client
def initialize(secret_key_path:, team_id:, music_id:, token_expire_time: 1.day)
@secret_key_path = secret_key_path
@team_id = team_id
@music_id = music_id
@token_expire_time = token_expire_time
end
private
def client
@faraday ||= QApi::Faraday.without_cache_fallback(:url => 'https://api.music.apple.com/v1/') do |builder|
builder.use FaradayMiddleware::ParseJson
builder.authorization(:bearer, authentication_token)
end
end

def authentication_payload
{
iss: @team_id,
iat: Time.now.to_i,
exp: @token_expire_time.from_now.to_i
}
end
def authentication_token
private_key = OpenSSL::PKey::EC.new(apple_music_secret_key)
JWT.encode authentication_payload, private_key, 'ES256', kid: @music_id
end
def apple_music_secret_key
@apple_music_secret_key ||= File.read(@secret_key_path)
end
end

Which I can then simple use

client = AppleMusic::Client.new(...)
client.get("catalog/be/charts", types: 'songs', limit: 100)

And with that, you’re talking to Apple Music!

I build things on the internet. Scalable, easy-to-use, fun things.

I build things on the internet. Scalable, easy-to-use, fun things.