Search code examples
pythonswiftjwtstorekit

What is the right way to validate a StoreKit 2 transaction jwsRepresentation in python?


It's unclear from the docs what you actually do to verify the jwsRepresentation string from a StoreKit 2 transaction on the server side.

Also "signedPayload" from the Apple App Store Notifications V2 seems to be the same, but there is also no documentation around actually validating that either outside of validating it client side on device.

What gives? What do we do with this JWS/JWT?


Solution

  • Apple now provides an App Store Server Library available in a few different languages (including Python).

    You still need to manage loading the root certificates on your own, but here is an example:

    from functools import 
    
    from appstoreserverlibrary.models.Environment import Environment
    from appstoreserverlibrary.signed_data_verifier import VerificationException, SignedDataVerifier
    
    @lru_cache(maxsize=None)
    def _load_apple_root_certificates():
        # https://www.apple.com/certificateauthority/
        certs_urls = [
            "https://www.apple.com/appleca/AppleIncRootCertificate.cer",
            "https://www.apple.com/certificateauthority/AppleComputerRootCertificate.cer",
            "https://www.apple.com/certificateauthority/AppleRootCA-G2.cer",
            "https://www.apple.com/certificateauthority/AppleRootCA-G3.cer",
        ]
        return [requests.get(cert_url).content for cert_url in certs_urls]
    
    root_certificates = _load_apple_root_certificates()
    enable_online_checks = True
    bundle_id = "com.example"
    environment = Environment.SANDBOX
    app_apple_id = None # appAppleId must be provided for the Production environment
    signed_data_verifier = SignedDataVerifier(root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
    
    try:    
        signed_notification = "ey.."
        payload = signed_data_verifier.verify_and_decode_notification(signed_notification)
        print(payload)
    except VerificationException as e:
        print(e)