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

Tags:

Ruby

Jwt