How to create a JWT for use with Apple Music
I used this script and it works perfectly https://github.com/pelauimagineering/apple-music-token-generator
Here's a working Ruby implementation. Call with your keyId and teamId, provide access to your private key file and go.
class AppleMusic
@auth_token
@validity_start
@validity_end
def initialize(keyId, teamId, options ={})
appleKeyId = keyId
appleTeamId = teamId
@validity_start = Time.now.to_i
@validity_end = Time.now.to_i + 43200 # 12 hours in seconds...
# Build up the headers
header = {
'typ' => 'JWT', # MUST BE SPECIFIED... Apple doesn't tell you this!
'alg' => 'ES256',
'kid' => appleKeyId
}
# Build up the payload
body = {
'iss' => appleTeamId,
'iat' => @validity_start,
'exp' => @validity_end
}
# This should be installed manually on the server somewhere
# TODO: Add some protection around the file's existance, set the name & location
# as some type of configuration key.
file = File.read('lib/assets/AuthKey_xxxxxxx.p8')
key = OpenSSL::PKey::EC.new(file)
key.check_key
@auth_token = JWT.encode(body, key, 'ES256', header)
@auth_token
end
def auth_token
@auth_token
end
def auth_header
"Bearer #{@auth_token}"
end
def validity_start
@validity_start
end
def validity_end
@validity_end
end
end
Based on @DanDevine's answer, here's a more Ruby/OO approach:
require "openssl"
# Example:
#
# token = AppleMusic::Token.new(key_id: "...", team_id: "...", keyfile: File.new("lib/assets/AuthKey_xxxxxxx.p8"))
# token.auth_token
# token.auth_header
#
module AppleMusic
class Token
attr_reader :key_id, :team_id, :keyfile
# Keyfile should be an IO type that responds to `read`
def initialize(key_id:, team_id:, keyfile:)
@key_id = key_id
@team_id = team_id
@keyfile = keyfile
end
def auth_token
@auth_token ||= fetch_auth_token
end
def auth_header
"Bearer #{auth_token}"
end
protected
def fetch_auth_token
header = {
typ: "JWT", # Must be specified; not in documentation
alg: "ES256",
kid: key_id
}
body = {
iss: team_id,
iat: Time.now.to_i,
exp: Time.now.to_i + 43_200 # 12hrs
}
JWT.encode(body, auth_key, 'ES256', header)
end
def auth_key
key = OpenSSL::PKey::EC.new(keyfile.read)
key.check_key
key
end
end
end
It's now also possible in pure Swift!
You first have to create a MusicKit identifier and a private key using this guide from Apple. Then a token can be easily created using Swift-JWT from IBM in pure Swift.
It's more or less just an invocation of the SwiftJWT API:
let teamId = "yourTeamID"
let keyId = "yourKeyID"
let keyFileUrl = URL(fileURLWithPath:"/pathToYour/key.p8")
struct MyClaims: Claims {
let iss: String
let iat: Date?
let exp: Date?
}
let myHeader = Header(kid: keyId)
let myClaims = MyClaims(iss: teamId, iat: Date(), exp: Date() + 24 * 60 * 60)
var myJWT = SwiftJWT.JWT(header: myHeader, claims: myClaims)
let token = try! myJWT.sign(using: .es256(privateKey: try! String(contentsOf: keyFileUrl).data(using: .utf8)!))
I created a simple example and a command line tool using the Swift Package Manager: SwiftJWTSample