python – 401 Unauthorized Error when fetching Apple’s public keys


I hold getting 401 Unauthorized error when fetching Apple’s public keys.

In [14]: print(f”Error fetching public keys: {response.status_code} {response.textual content}”)
Error fetching public keys: 401 Unauthenticated

I’ve verified that the Key ID, Issuer ID, and personal key file are all appropriate, with the non-public key having admin entry. The server time is appropriately set to UTC. Given this, I can not establish what is likely to be inflicting the difficulty. Any insights?

def generate_apple_developer_token():
    # Load the non-public key in PEM format
    with open(PRIVATE_KEY_FILE, 'rb') as key_file:
        private_key = serialization.load_pem_private_key(
            key_file.learn(),
            password=None,
            backend=default_backend()
        )

    # JWT header
    headers = {
        "alg": "ES256",  # Algorithm: Elliptic Curve
        "child": KEY_ID,   # Key ID from Apple Developer
        "typ": "JWT"     # Sort: JWT
    }

    # JWT payload
    payload = {
        "iss": ISSUER_ID,  # Issuer ID from Apple Developer
        "iat": int(datetime.utcnow().timestamp()),  # Issued at time
        "exp": int((datetime.utcnow() + timedelta(minutes=10)).timestamp()),  # Expiration (max 10 minutes)
        "aud": "appstoreconnect-v1",  # Viewers
        
    }

    # Encode the header and payload as base64
    header_base64 = base64.urlsafe_b64encode(json.dumps(headers).encode()).decode().rstrip("=")
    payload_base64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")

    # Concatenate header and payload
    message = f"{header_base64}.{payload_base64}".encode()

    # Signal the message utilizing ECDSA with SHA256
    signature = private_key.signal(
        message,
        ec.ECDSA(hashes.SHA256())
    )

    # Convert the DER-encoded signature to uncooked format (r and s concatenated)
    der_to_raw_ecdsa_format = lambda der: der[4:36] + der[-32:]

    # Convert the signature to uncooked format (64 bytes)
    signature_64 = der_to_raw_ecdsa_format(signature)

    # Base64 URL-encode the signature
    signature_base64 = base64.urlsafe_b64encode(signature_64).decode().rstrip("=")

    # Concatenate header, payload, and signature to kind the JWT
    jwt_token = f"{header_base64}.{payload_base64}.{signature_base64}"

    return jwt_token

def get_apple_public_keys():
    attempt:
        # Generate a recent JWT
        developer_token = generate_apple_developer_token()

        # Arrange headers with the authorization token
        headers = {
            "Authorization": f"Bearer {developer_token}"
        }

        # Fetch the general public keys from Apple
        response = requests.get('https://api.storekit.itunes.apple.com/in-app-purchase/publicKeys', headers=headers)
         # Log the response if it isn't profitable
        if response.status_code != 200:
            print(f"Error fetching public keys: {response.status_code} {response.textual content}")
        
        response.raise_for_status()  # Raises an exception for 4xx/5xx errors

        # Parse and return the general public keys
        response_data = response.json()
        keys = response_data.get('keys')
        if not keys:
            print("No 'keys' discovered within the response from Apple.")
            return []
        return keys
    besides requests.exceptions.RequestException as e:
        print(f"Error fetching Apple's public keys: {e}")
        return []

I additionally tried utilizing jwt to implement the jwt token

def generate_apple_developer_token():
    with open(PRIVATE_KEY_FILE, 'r') as f:
        private_key = f.learn().strip()
        print('that is the important thing', private_key)
    # JWT header
    headers = {
        "alg": "ES256",  # Apple makes use of ES256 (Elliptic Curve)
        "child": KEY_ID,
        "typ": "JWT"
    }

    # JWT payload
    payload = {
        "iss": ISSUER_ID,
        "iat": int(datetime.utcnow().timestamp()),  # Issued at time
        "exp": int((datetime.utcnow() + timedelta(minutes=10)).timestamp()),  # Expiration (max 10 minutes)
        "aud": "appstoreconnect-v1",
    
    }

    # Generate and return the JWT
    return jwt.encode(payload, private_key, algorithm="ES256", headers=headers)

In both case, I checked the token in jwt.io and they’re appropriate, however for some purpose they fail the authentication

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles