Recently, one new API Look Up Order ID was added into app store server API. And the JWSTransaction of this API response signed by the App Store, in JSON Web Signature format. We want to verify it with go.
What we have tried
- The jwt-go is used and we try to extract public key from pem file per this question. Also per this link, the response should be decoded by extracting a public key from private key
type JWSTransaction struct {
BundleID string `json:"bundleId"`
InAppOwnershipType string `json:"inAppOwnershipType"`
TransactionID string `json:"transactionId"`
ProductID string `json:"productId"`
PurchaseDate int64 `json:"purchaseDate"`
Type string `json:"type"`
OriginalPurchaseDate int64 `json:"originalPurchaseDate"`
}
func (ac *JWSTransaction) Valid() error {
return nil
}
func (a *AppStore) readPrivateKeyFromFile(keyFile string) (*ecdsa.PrivateKey, error) {
bytes, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
block, _ := pem.Decode(bytes)
if block == nil {
return nil, errors.New("appstore private key must be a valid .p8 PEM file")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
switch pk := key.(type) {
case *ecdsa.PrivateKey:
return pk, nil
default:
return nil, errors.New("appstore private key must be of type ecdsa.PrivateKey")
}
}
func (a *AppStore) ExtractClaims(tokenStr string) (*JWSTransaction, error) {
privateKey, err := a.readPrivateKeyFromFile()
if err != nil {
return nil, err
}
publicKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
if err != nil {
return nil, err
}
fmt.Println(publicKey)
tran := JWSTransaction{}
token, err := jwt.ParseWithClaims(tokenStr, &tran, func(token *jwt.Token) (interface{}, error) {
fmt.Println(token.Claims)
fmt.Println(token.Method.Alg())
return publicKey, nil
})
if err != nil {
fmt.Println(err)
}
However, the error key is of invalid type
comes up from jwt.ParseWithClaims
.
- Another way to verify it through the jwt-go and jwk packages per this link
token, err := jwt.ParseWithClaims(tokenStr, &tran, func(token *jwt.Token) (interface{}, error) {
fmt.Println(token.Claims)
fmt.Println(token.Method.Alg())
kid, ok := token.Header["kid"].(string)
if !ok {
return nil, errors.New("failed to find kid from headers")
}
key, found := keySet.LookupKeyID(kid)
if !found {
return nil, errors.New("failed to find kid from key set")
}
return publicKey, nil
})
However, we failed to find the public key URL in app store server API doc. Also, there is no kid
from the headers of JWSTransaction.
We want to know how to verify JWS transaction of app store server api in Go? Is there anything am I missing?