title: JAVA Generating a Signature for Apple Promotional Offers
body: <p>I'm trying to generate a signature to be returned to the mobile application in order to validate a promotional offer with the App Store.</p>
  <p>Apple documentation :<a href="https://developer.apple.com/documentation/storekit/original_api_for_in-app_purchase/subscriptions_and_offers/generating_a_signature_for_promotional_offers" rel="nofollow noreferrer">doc</a></p>
  <p>However, the validation failed in  the mobile application with invalid signature error.</p>
  <p>Below, the method that aims to generate the signature</p>
  <pre><code>    public static final String BEGIN_PRIVATE_KEY = &quot;-----BEGIN PRIVATE KEY-----&quot;;
      public static final String END_PRIVATE_KEY = &quot;-----END PRIVATE KEY-----&quot;;
      public static final String EC = &quot;EC&quot;;
      public static final String SHA_256_WITH_ECDSA = &quot;SHA256withECDSA&quot;;
      public static final String SEPARATOR = &quot;\\u2063&quot;;
      public static final String P8_KEY_PATH = &quot;classpath:keys/AuthKey.p8&quot;;
      
           private void setSignature(SubscriptionDto subscription , String username) {
      
      
                          String productId = subscription.getAppleIdentifier();
      
                          UUID nonce = UUID.randomUUID();
                          Instant instant = Instant.now();
                          long timestamp = instant.toEpochMilli();
                          String offerId = getOfferId(subscription);
                          String payload = buildPayload(productId, nonce, timestamp, offerId, username);
                         
                          Signature ecdsaSign = Signature.getInstance(SHA_256_WITH_ECDSA);
                          ecdsaSign.initSign(getPrivateKey());
                          ecdsaSign.update(payload.getBytes(StandardCharsets.UTF_8));
                          byte[] signature = ecdsaSign.sign();
                          
                          String sig = Base64.getEncoder().encodeToString(signature); // returned signature
                          verify(sig, payload);
  
                                          
          }
      
        
          private String buildPayload(String productId, UUID nonce, long timestamp, String offerId, String username) {
              return String.join(SEPARATOR, bundleId,
                      keyId,
                      productId,
                      offerId,
                      username!=null?username:&quot;&quot;,
                      nonce.toString().toLowerCase(),
                      Long.toString(timestamp));
          }
      
        
          public PrivateKey getPrivateKey() throws Exception {
              String key = FileUtils.readFileToString(ResourceUtils.getFile(P8_KEY_PATH),
                      Charset.defaultCharset());
      
              String privateKeyPEM = key
                      .replace(BEGIN_PRIVATE_KEY, &quot;&quot;)
                      .replaceAll(System.lineSeparator(), &quot;&quot;)
                      .replace(END_PRIVATE_KEY, &quot;&quot;);
      
              byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
              KeyFactory keyFactory = KeyFactory.getInstance(EC);
              PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
              return keyFactory.generatePrivate(keySpec);
          }
  </code></pre>
  <p>Any idea please ?</p>