Intro
App Store Connect requires you to create API Key by signing a JWT API Token with mixed credentials and identities. This tutorial will guide you through the process of creating one.
Make sure you have all the required data
keyId
: Key ID will be displayed when you generate new private key in Users And Access / Keys section.issuerID
: ID associated with you in the Users And Access / Keys section.bundleId
: Your app bundle IDprivateKey
: The private key file you download from App Store Connect.
Code Sample
We’ll need to use a third-party library for JWT token generation since Go’s standard library does not include JWT functionality. We will use jwt.
First, ensure you have installed the required package:
go get github.com/golang-jwt/jwt/v4
Now the real implementation:
package main
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"time"
"github.com/golang-jwt/jwt/v4"
)
func generateJWT(header jwt.MapClaims, payload jwt.MapClaims, privateKey string) (string, error) {
// Decode the private key from the string
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return "", jwt.ErrECPrivateKeyFormat
}
privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// Create a new JWT token and sign it with the private key
token := jwt.NewWithClaims(jwt.SigningMethodES256, payload)
token.Header["alg"] = header["alg"]
token.Header["kid"] = header["kid"]
token.Header["typ"] = header["typ"]
signedToken, err := token.SignedString(privKey.(*ecdsa.PrivateKey))
if err != nil {
return "", err
}
return signedToken, nil
}
func genToken(kid, iss, bundleID, privateKey string) (string, error) {
header := jwt.MapClaims{
"alg": "ES256",
"kid": kid,
"typ": "JWT",
}
payload := jwt.MapClaims{
"iss": iss,
"iat": time.Now().Unix(),
"exp": time.Now().Add(30 * time.Minute).Unix(),
"aud": "appstoreconnect-v1",
"bid": bundleID,
}
token, err := generateJWT(header, payload, privateKey)
if err != nil {
return "", err
}
return token, nil
}
func main() {
// Substitute these variables with actual values.
keyID := "REPLACE_WITH_KEY_ID"
issuerID := "REPLACE_WITH_ISSUER_ID"
bundleID := "REPLACE_WITH_BUNDLE_ID"
privateKey := `REPLACE_WITH_PRIVATE_KEY`
// Generate the token
tkn, err := genToken(keyID, issuerID, bundleID, privateKey)
if err != nil {
panic(err)
}
println(tkn)
}
Alternative tool
Or if you just want to play around with the API, use our complete free Chrome Extension to generate key “locally” with complete privacy.