Files
iot-dboard/backend/jwt_util.py
T
2026-08-06 11:11:11 +08:00

56 lines
1.7 KiB
Python

"""Ed25519 key pair generation and JWT signing for QWeather API."""
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import serialization
import jwt
import time
def generate_key_pair() -> tuple:
"""Generate an Ed25519 key pair.
Returns:
(private_key_pem: str, public_key_pem: str)
"""
private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
).decode("utf-8")
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
).decode("utf-8")
return private_pem, public_pem
def sign_jwt(private_key_pem: str, credential_id: str, project_id: str,
expiry_seconds: int = 3600) -> str:
"""Sign a JWT for QWeather API authentication.
Args:
private_key_pem: Ed25519 private key in PEM format.
credential_id: QWeather credential ID (kid).
project_id: QWeather project ID (sub).
expiry_seconds: Token validity in seconds (max 86400 per QWeather).
Returns:
Signed JWT string.
"""
now = int(time.time())
payload = {
"sub": project_id,
"iat": now,
"exp": now + min(expiry_seconds, 86400),
}
headers = {
"alg": "EdDSA",
"kid": credential_id,
}
token = jwt.encode(payload, private_key_pem, algorithm="EdDSA", headers=headers)
return token