--- title: JWT specification description: >- Learn how JWTs need to be structured in order to be used in post-purchase app extensions on the Shopify checkout. api_name: checkout-extensions source_url: html: >- https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification md: >- https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md --- ExpandOn this page * [Overview](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#overview) * [Encoding and decoding](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#encoding-and-decoding) * [Claims](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#claims) # JWT specification This document describes how [JWTs (JSON web token)](https://jwt.io/) need to be structured in order to be used in post-purchase app extensions on the Shopify checkout. It describes the claims that can be used, and whether they're optional. *** ## Overview The data passed from Shopify to the extension point is signed with a shared secret ([JWT](https://jwt.io/)). When you make a call to your backend server, you can use this secret to verify that the request came from Shopify. The following example displays how you can use a changeset token to request changes to an initial purchase: ```js extend('Checkout::PostPurchase::Render', async (root, input) => { const buyNowButton = root.createComponent(Button, { onPress() { const changeset = await fetchChangeset(input); input.applyChangeset(changeset.token); }, }); const pagePayload = input.storage.initialData; buyNowButton.appendChild(`Buy "${pagePayload.variantTitle}" now!`); root.appendChild(buyNowButton); root.mount(); }); // this call would ideally fetch all available changesets at once, instead // of one at a time const fetchChangeset = async (input) => { const request = await fetch('https://example.com/fetch-changeset', { method: 'POST', body: JSON.stringify({ initialPurchase: input.initialPurchase.token }), }); return request.json(); }; ``` If your app makes a return call to your extension point, then you must sign `applyChangeset` with the shared secret. Shopify will use the secret to verify that the request is coming from your app. *** ## Encoding and decoding JWTs can be encoded and decoded by using the client secret of an app as the token key, and by setting the hashing algorithm to HS256. **Ruby example:** ```ruby JWT.encode(payload, api_secret, 'HS256') ``` *** ## Claims ### JWT ID (JTI) Used to make sure each token is unique, and prevent potential replay attacks. * **Shopify issued token:** Not present. * **Partner issued token:** Required. It is strongly recommend to use UUIDs, to ensure each token is [unique](https://stackoverflow.com/questions/1155008/how-unique-is-uuid#answer-1155027). ### Issuer (ISS) Used to identify who issued the token. * **Shopify issued token:** Always present, and statically set to "shopify". * **Partner issued token:** Required. The `api_key` of the app issuing the token. ### Subject (SUB) The reference ID of the initial purchase the token was issued for. * **Shopify issued token:** Always present. * **Partner issued token:** Required. ### Issued at time (IAT) Used to identify when the token was generated. * **Shopify issued token:** Always present. * **Partner issued token:** Required. Note As a security measure, changesets signed before the initial purchase is completed aren't accepted. ### Expiration time (EXP) Used to prevent a token from being used after a certain time. * **Shopify issued token:** Not present. * **Partner issued token:** Optional. ### Not before time (NBF) Used to prevent a token from being used before a certain time. * **Shopify issued token:** Not present. * **Partner issued token:** Optional. ### Audience (AUD) Unused. *** * [Overview](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#overview) * [Encoding and decoding](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#encoding-and-decoding) * [Claims](https://shopify.dev/docs/api/checkout-extensions/post-purchase/jwt-specification.md#claims)