Verificar compra in app con Apple Store Kit 2 y JWT en Python

Tiempo de lectura: < 1 minuto

Ho voy a compartir una función que nos permitirá verificar las compras que realicemos en Apple con Apple Store Kit 2 y JWT usando Python.

Parapente - pexels

Lo primero que haremos es crear una función utils que nos permitira validar el jwsRepresentation de la compra de Apple.

Para ello usaremos estas funciones:

import base64
import requests
import jwt
from cryptography.x509 import load_der_x509_certificate

def get_public_key_from_jws(jws_token):
    # Decodificar solo el header (sin verificar)
    header_b64 = jws_token.split('.')[0]
    header_json = base64.urlsafe_b64decode(pad_base64(header_b64))
    import json
    header = json.loads(header_json)
    
    # Extraer x5c
    if "x5c" not in header:
        raise ValueError("El JWS no contiene el 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}  # cambiar a True si verificas 'aud'
        )
        return payload
    except jwt.exceptions.InvalidSignatureError:
        raise ValueError("Firma inválida")
    except jwt.exceptions.ExpiredSignatureError:
        raise ValueError("Token expirado")
    except Exception as e:
        raise ValueError(f"Error verificando JWS: {str(e)}")
    
def pad_base64(b64_string):
    return b64_string + "=" * (-len(b64_string) % 4)

Y la forma de utilizarse es esta:

 try:
                payload = verify_jws(jwsRepresentation)
                print("Compra verificada, payload:")
                print(payload)
            except ValueError as e:
                print("Error:", e)
                raise HTTPException(status_code=400, detail=f"Compra no válida Apple: {str(e)}") 

Nota: si utilizas Expo IAP, puedes usar

jwsRepresentation

O

purchase.purchaseToken;

Deja un comentario