Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions pyaxm/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from dataclasses import dataclass

import jwt
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.serialization import load_pem_private_key


@dataclass
Expand Down Expand Up @@ -35,6 +37,27 @@ def __init__(
self.token_path = token_path
self.access_token = self._get_or_refresh_token()

def _load_ec_key(self) -> bytes:
"""Load and normalize an Apple .p8 EC private key.

Apple provides EC private keys in PKCS#8 PEM format
(``-----BEGIN PRIVATE KEY-----``). Some PyJWT or
``cryptography`` releases can be sensitive to the exact PEM
header / footer wording or encoding. To avoid any such issues,
this helper loads the key with ``cryptography`` (which
transparently handles both PKCS#8 and SEC1 / EC PEM formats)
and re-serialises it back to a consistent PKCS#8 PEM byte
string.
"""
with open(self.key_path, "rb") as f:
key_data = f.read()
private_key = load_pem_private_key(key_data, password=None)
return private_key.private_bytes(
encoding=crypto_serialization.Encoding.PEM,
format=crypto_serialization.PrivateFormat.PKCS8,
encryption_algorithm=crypto_serialization.NoEncryption(),
)

def _generate_assertion(self) -> str:
issued_at = int(dt.datetime.now(dt.timezone.utc).timestamp())
expires_at = issued_at + 60
Expand All @@ -50,8 +73,7 @@ def _generate_assertion(self) -> str:
"jti": str(uuid.uuid4()),
"iss": self.axm_client_id,
}
with open(self.key_path, "rb") as f:
key = f.read()
key = self._load_ec_key()
return jwt.encode(payload, key, algorithm="ES256", headers=headers)

def _get_or_refresh_token(self) -> AccessToken:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ version = "2026.5.18"
description = "Query Apple Business Manager using Python"
requires-python = ">=3.10"
dependencies = [
"cryptography",
"pydantic",
"requests",
"pyjwt",
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cryptography
pydantic
requests
pyjwt
Expand Down
Loading