Generating JWS to sign App Store requests
Create signed JSON Web Signature (JWS) strings on your server to authorize your API requests in your app.
Overview
JWS is an open standard (RFC 7515) that defines a way to securely transmit information. You create the JWS header and payload using information specific to the App Store feature. You sign the JWS on your server using a private API key that you download from App Store Connect.
The following App Store features require a JWS Compact Serialization to authorize calls in StoreKit:
Advanced Commerce API in-app requests
Promotional offer signatures
Introductory offer eligibility
The data you sign when generating the JWS is a JSON Web Token (JWT). The JWT contains name-value pairs called claims, including claims specific to the feature you’re using. Your server returns the JWS Compact Serialization to your app. Your app uses the JWS in the relevant StoreKit API call.
To get started, you need your key ID and issuer ID from App Store Connect. Then, to generate a signed JWS, you perform these steps on your server:
Create the JWS header.
Create the JWS payload. The payload includes the base payload claims, and may also require feature-specific claims.
Sign the JWS.
Get your key ID and issuer ID from App Store Connect
First you need your key ID for the JWS header and your issuer ID for the JWS payload. Sign in to App Store Connect to get these values.
To get the key ID:
Select Users and Access, then select the Keys tab.
Hover the cursor next to a key ID to display the Copy Key ID link. The key IDs appear in a column under the Active heading.
Click Copy Key ID.
If you have more than one API key, copy the key ID of the private key that you use to sign the JWS. For information about creating keys, see Creating API keys to authorize API requests.
To get the issuer ID:
Select Users and Access, then select the Keys tab.
To copy the issuer ID that appears near the top of the page, click Copy next to the ID.
Create the JWS header
The App Store features all use the same JWS header.
To create a JWS to communicate with the App Store, use the following fields and values in the header:
Header field | Value |
|---|---|
|
|
| Your private key ID from App Store Connect (example: |
|
|
Here’s an example of a JWS header:
{
"alg": "ES256",
"kid": "2X9R4HXF34",
"typ": "JWT"
}Create the JWS payload
The JWS payload contains base claims specific to the App Store, such as an issuer ID and issuance time. It also includes custom claims that are specific to App Store features. The following table shows the base claims. The next sections shows the feature-specific claims that you also include in the JWS payload.
Include the following base claims in the JWS payload:
Payload field | Value |
|---|---|
| Your issuer ID from the Keys page in App Store Connect (example: “ |
| The UNIX time, in seconds, that you issue the token, which the App Store server uses to calculate an expiration time (example: |
| A value that depends on the feature you’re using (see the table below) |
| Your app’s bundle ID (example: |
| A one-time-use UUID that identifies this request (example: “ |
Don’t include an exp field in your payload, because including it makes the request fail. The App Store server enforces an expiration time based on your iat value.
Choose the aud value to match the feature you’re using:
Feature |
|
|---|---|
Advanced Commerce API in-app request | “ |
Promotional offer signature | “ |
Introductory offer eligibility | “ |
Here’s an example of the base payload, without any feature-specific fields:
{
"iss": "57246542-96fe-1a63e053-0824d011072a",
"iat": 1741043663,
"aud": "promotional-offer",
"bid": "com.example.testbundleid",
"nonce": "6584bedf-2ed0-4c01-93ed-c0c64a1670cc"
}Be sure to include feature-specific custom claims in the JWS payload as well.
Include custom claims for Advanced Commerce API in-app requests
For custom claims for Advanced Commerce in-app requests, use the following values:
Payload field | Value |
|---|---|
| Base64-encoded request data |
For more information on generating the base64-encoded request data, see Create the base64-encoded request data.
Here’s an example of a payload for an Advanced Commerce API in-app request:
{
"iss": "57246542-96fe-1a63e053-0824d011072a",
"iat": 1741043663,
"aud": "advanced-commerce-api",
"bid": "com.example.testbundleid",
"nonce": "df2b8374-95a1-425b-a6a5-77a4d7648333",
"request": "<base64-encoded request data>"
}For more information about making Advanced Commerce API requests in StoreKit, see Sending Advanced Commerce API requests from your app.
Include custom claims for promotional offer signatures
For promotional offer signature custom claims, use the following values:
Payload field | Value |
|---|---|
| The unique identifier of the product (for more information, see Id) |
| The promotional offer identifier that you set up in App Store Connect |
| The unique identifier of any transaction that belongs to the customer. You can use the customer’s Apptransactionid, even for customers who haven’t made any In-App Purchases in your app. This field is optional, but recommended. |
Here’s an example of a payload for a promotional offer signature:
{
"iss": "57246542-96fe-1a63e053-0824d011072a",
"iat": 1741043663,
"aud": "promotional-offer",
"bid": "com.example.testbundleid",
"nonce": "368f3088-dcd5-11ef-b3c8-325096b39f46",
"productId": "com.example.product",
"offerIdentifier": "com.example.product.offer",
"transactionId": "1000011859217"
}Include custom claims for introductory offer eligibility
For introductory offer eligibility custom claims, use the following values:
Payload field | Value |
|---|---|
| The unique identifier of the product (for more information, see Id) |
| A Boolean value, |
| The unique identifier of any transaction that belongs to the customer. You can use the customer’s Apptransactionid, even for customers who haven’t made any In-App Purchases in your app. |
Here’s an example of a payload for introductory offer eligibility:
{
"iss": "57246542-96fe-1a63e053-0824d011072a",
"iat": 1741043663,
"aud": "introductory-offer-eligibility",
"bid": "com.example.testbundleid",
"nonce": "cfb43594-4f92-4fe2-8b06-d947a848adaa",
"productId": "com.example.product",
"allowIntroductoryOffer": false,
"transactionId": "1000011859217"
}For more information about providing the introductory offer eligibility signed value in a purchase option, see Product.PurchaseOption.
Sign the JWS
On your server, use the private key associated with the key ID you specified in the header to generate the signature using ES256 encryption. The process of signing combines the JWS Header and JWS Payload into a single signed string.
There are a variety of open source libraries available online for creating and signing JWT tokens; see JWT.io for more information. Consider using the App Store Server Library to create the JWS. For more information, see Simplifying your implementation by using the App Store Server Library.
After signing, you should have a string in JWS compact serialization format. Send that string to your app.