Blog Logo

12 Jan 2024 ~ 2 min read

Create App Store Sever API Key Using Golang


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 ID
  • privateKey: 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.

Extension Screenshot


Headshot of John

Hi, I'm John. Editor at ToolboxForWeb. Trying to make the internet a useful and friendly place for every person.