12.6 C
New York
Thursday, October 17, 2024

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


I maintain 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 right, with the personal key having admin entry. The server time is accurately set to UTC. Given this, I can not establish what could be inflicting the problem. Any insights?

def generate_apple_developer_token():
    # Load the personal 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"     # Kind: 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 contemporary 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 right, however for some cause they fail the authentication

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles