8 Replies
      Latest reply on Dec 3, 2019 8:08 PM by _jeremy
      mpoiriert Level 1 Level 1 (0 points)

        is I am trying to do this https://developer.apple.com/documentation/storekit/in-app_purchase/generating_a_signature_for_subscription_offers in PHP.

        I don't have any error on the generation of the signature but on the client side we get a "SKErrorInvalidSignature" error.

        I am wondering if I did the signature generation properly. It's really specific to PHP but maybe someone can help:


        public function generateSubscriptionOfferSignature($productIdentifier, $offerIdentifier)
          $nonce = strtolower(Uuid::uuid1()->toString());
          $timestamp = time() * 1000;
          $applicationUsername = '';
          $separator = json_decode('"\u2063"');
          $unsignedSignature = implode(
          $signature = null;
          openssl_get_privatekey('file://' . $this->itunesPrivateKeyPath),
          return new Signature(


        All the variable have been triple check and durint the implementation I got error on the openssl_sign and the openssl_get_privatekey now they do work.

        The only 2 things I can spot that could be a problem is:
        $separator = json_decode('"\u2063"'); Does not return the expected character.



        openssl_sign OPENSSL_ALGO_SHA256 does not qualify for (from the documentation):

        Sign the Combined String

        Sign the combined UTF-8 string with the following key and algorithm:

        • The PKCS#8 private key (downloaded from App Store Connect) that corresponds to the keyIdentifier in the UTF-8 string.
        • The Elliptic Curve Digital Signature Algorithm (ECDSA) with a SHA-256 hash.


        But maybe I miss something else ?

        • Re: Subscription Offer generate signature in PHP
          KMT Level 9 Level 9 (15,305 points)

          Sorry if I missed it (A&B maybe?) - pls. show the full/exact sig related error(s), thanks.

          • Re: Subscription Offer generate signature in PHP
            Russ Level 1 Level 1 (0 points)

            And here is simplified client code:


            struct SubscriptionOfferSignature: Codable {
                let encodedSignature: String
                let nonce: String
                let timestamp: Int
                let keyIdentifier: String
            func prepareOffer(for product: SKProduct, completion: @escaping (Result) -> ()) {
                guard let discountIdentifier = product.discounts.first?.identifier else {
                service.generateOfferSignatureFor(productIdentifier: product.productIdentifier, offerIdentifier: discountIdentifier) { [weak self] result in
                    guard let strongSelf = self else { return }
                    switch result {
                    case .success(let subscriptionOfferSignature):
                        let nonceUUID = UUID(uuidString: subcriptionOfferSignature.nonce)!
                        let discountOffer = SKPaymentDiscount(identifier: discountIdentifier, keyIdentifier: subcriptionOfferSignature.keyIdentifier, nonce: nonceUUID, signature: subcriptionOfferSignature.encodedSignature, timestamp: NSNumber(value: subcriptionOfferSignature.timestamp))
                    case .failure(let error):
            func purchase(_ product: SKProduct, with discountOffer: SKPaymentDiscount) {
                let payment = SKMutablePayment(product: product)
                payment.applicationUsername = ""
                payment.paymentDiscount = discountOffer


            And when I get notified by

            func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])

            transaction's state is failed with "Error Domain=SKErrorDomain Code=12 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store}"

            I can see that paymentDiscount object on transaction's payment property has all the values I've set before (identifier, keyIdentifier, nonce, signature, timestamp). So not sure where else to look at.