We will share a function that will allow us to verify the purchases we make on Apple with Apple Store Kit 2 and JWT using Python.

First, we will create a function utils that will allow us to validate the jwsRepresentation of the Apple purchase.
For that we will use these functions:
import base64import requestsimport jwtfrom cryptography.x509 import load_der_x509_certificatedef get_public_key_from_jws(jws_token): # Decode only the header (without verification) header_b64 = jws_token.split('.')[0] header_json = base64.urlsafe_b64decode(pad_base64(header_b64)) import json header = json.loads(header_json) # Extract x5c if "x5c" not in header: if "x5c" not in header: raise ValueError("The JWS does not contain the header x5c") cert_b64 = header["x5c"][0] cert_der = base64.b64decode(cert_b64) cert = load_der_x509_certificate(cert_der) return cert.public_key()def verify_jws(jws_token): try: public_key = get_public_key_from_jws(jws_token) payload = jwt.decode( jws_token, public_key, algorithms=["ES256"], options={"verify_aud": False} # Change to True if you verify 'aud' ) return payload except jwt.exceptions.InvalidSignatureError: raise ValueError("Invalid signature") except jwt.exceptions.ExpiredSignatureError: raise ValueError("Token expired") except Exception as e: raise ValueError(f"Error verifying JWS: {str(e)}")def pad_base64(b64_string): return b64_string + "=" * (-len(b64_string) % 4)
And its usage is like this:
try: payload = verify_jws(jwsRepresentation) print("Purchase verified, payload:") print(payload)except ValueError as e: print("Error:", e)raise HTTPException(status_code=400, detail=f"Invalid Apple purchase: {str(e)}")
Note: If you use Expo IAP, you can use
JWS Representation
Or
purchase.purchaseToken;
