Evidently I'm not generating API tokens right.

I'm trying (in Swift) to use CryptoKit to generate the required JWT for the Apple Music Web API, as documented (sort of) here.

But I'm getting 401s no matter what I try. I found some examples of generating JWTs online, but something isn't working here. I've set up my identifiers and gotten an API secret through my account in the dev portal. It's associated with an identifier requesting Music API access (I requested all three available Music-related capabilities).

For the secret, I'm using the long key string from the .p8 file I generated and downloaded from the dev portal.

Here's what I've tried:

struct APIToken
{
	struct Header: Encodable
	{
		let alg = "HS256"
		let kid: String
	}

	struct Payload: Encodable
	{
		let iss: String
		let iat: String
		let exp: String
	}

	static func tokenize(keyID: String, issuerID: String, secret: String) -> String
	{
		let privateKey = SymmetricKey(data: Data(secret.utf8))
		let headerJSONData = try! JSONEncoder().encode(Header(kid: keyID))
		let headerBase64String = headerJSONData.base64EncodedString()

		let currUnixTime = Int(Date().timeIntervalSince1970)
		let expUnixTime = currUnixTime + 5 * 2628288	// five months of seconds

		let payloadJSONData = try! JSONEncoder().encode(Payload(iss: issuerID, iat: "\(currUnixTime)", exp: "\(expUnixTime)"))
		let payloadBase64String = payloadJSONData.base64EncodedString()

		let toSign = Data((headerBase64String + "." + payloadBase64String).utf8)
		let signature = HMAC<SHA256>.authenticationCode(for: toSign, using: privateKey)
		let signatureBase64String = Data(signature).base64EncodedString()

		let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
		print(token)
		return token
	}
}

I also tried making sure the base64 strings are URL-safe with this extension:

extension Data
{
	func URLSafeBase64EncodedString() -> String
	{
		return base64EncodedString()
			.replacingOccurrences(of: "+", with: "-")
			.replacingOccurrences(of: "/", with: "_")
			.replacingOccurrences(of: "=", with: "")
	}
}

but that made no difference.

All the documentation says is

A decoded developer token has the following format.

{
     "alg": "ES256",
     "kid": "ABC123DEFG"
}
{
     "iss": "DEF123GHIJ",
     "iat": 1437179036,
     "exp": 1493298100
}

After you create the token, sign it with your MusicKit private key using the ES256 algorithm.

Am I not doing that? Any insight appreciated.

Evidently I'm not generating API tokens right.
 
 
Q