Im trying to create a developer token that is a ES256 JWT to use for Apple Music authentication. (Here)
Im using ruby and the JWT gem but after creating the token I get a 401 error when authenticating with Apple Music
require 'jwt'
payload = {:iss => 'CapExdTeam', :iat => '1497335982', :exp => '1513112982'}
priv = "-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgU208KCg/doqiSzsVF5sknVtYSgt8/3oiYGbvryIRrzSgCgYIKoZIzj0DAQehRANCAAQfrvDWizEnWAzB2Hx2r/NyvIBO6KGBDL7wkZoKnz4Sm4+1P1dhD9fVEhbsdoq9RKEf8dvzTOZMaC/iLqZFKSN6
-----END PRIVATE KEY-----"
ecdsa_key = OpenSSL::PKey::EC.new(priv)
token = JWT.encode payload, ecdsa_key, 'ES256', { :kid => "CapExedKid", :alg => "ES256" }
puts token
`curl -v -H 'Authorization: Bearer #{token}' "https://api.music.apple.com/v1/catalog/us/songs/203709340"
Im using the sample private key to simulate 429 error just for illustration purposes
To generate the user token (a MusicKit private key in a *. p8 file, a 10-digit key identifier in your Apple Developer account and your 10-digit Apple Developer Account Team ID), you can visit Apple member centre. If you have a member account, you can proceed with the generating the stuffs.
Use Apple Music API to access information about media in the Apple Music Catalog and a user's personal iCloud Music Library. Apple Music Catalog includes all resources available in Apple Music. iCloud Music Library contains only those resources the user adds to their personal library.
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
I used this script and it works perfectly https://github.com/pelauimagineering/apple-music-token-generator
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With