使用 pywebpush 发送 Web Push 时若手动指定 aud 字段,易触发“Missing 'aud' from claims”错误;实际应留空该字段,由库自动根据订阅端点(endpoint)动态生成符合规范的 aud 值。
使用 `pywebpush` 发送 web push 时若手动指定 `aud` 字段,易触发“missing 'aud' from claims”错误;实际应留空该字段,由库自动根据订阅端点(endpoint)动态生成符合规范的 `aud` 值。
在 Web Push 协议中,VAPID(Voluntary Application Server Identification)要求签名 JWT 包含 aud(Audience)声明,其值必须严格匹配推送服务端点的 scheme + host + port(如 https://fcm.googleapis.com 或 https://web.push.apple.com),且必须与客户端订阅时所用的 Service Worker 所属源完全一致。关键在于:aud 不是应用服务器的域名,而是推送服务提供商(如 Google FCM、Mozilla Autopush 或 Apple Push)的 endpoint 域名。
pywebpush 库的设计逻辑是——它会在调用 webpush() 时自动解析 subscription_info['endpoint'],从中提取 scheme、host 和 port,并据此填充 aud。因此,当你显式传入 vapid_claims = {"aud": "https://chat.bitsquad.ru/"} 时,库检测到 aud 已存在,便跳过自动填充;但该值不符合规范(它指向你的前端域名,而非推送服务 endpoint),导致签名验证失败,最终抛出 ValueError: Missing 'aud' from claims —— 这个错误信息具有误导性,真实含义是:“你提供的 aud 无效,而我又没被允许自动生成”。
✅ 正确做法是:将 aud 留空或完全省略,交由 pywebpush 自动推导:
from pywebpush import webpush, WebPushException
vapid_private_key_pem = "KE0RL_B2SY1AVcpHRWgTzC68or6cLC4RZaHmkM4ZsLk"
def send_push_notification(subscription_info, data):
# ✅ 正确:不提供 aud,或显式设为空字符串(两者等效)
vapid_claims = {
"sub": "mailto:admin@bitsquad.ru", # 必须为 mailto: 邮箱格式
"aud": "" # ← 关键修复:留空,让 pywebpush 自动填充
}
try:
response = webpush(
subscription_info=subscription_info,
data=data,
vapid_private_key=vapid_private_key_pem,
vapid_claims=vapid_claims
)
print("Push sent successfully:", response.status_code)
return True
except WebPushException as ex:
print("Web push failure:", ex)
return False? 注意事项:
- subscription_info 必须包含完整的 endpoint 字段(例如 "https://fcm.googleapis.com/fcm/send/xxx"),否则库无法提取有效 aud;
- sub 字段必须是 mailto: 开头的有效邮箱(如 "mailto:support@example.com"),不可省略或格式错误;
- 确保 vapid_private_key_pem 是标准 PEM 格式的私钥(以 -----BEGIN EC PRIVATE KEY----- 开头),而非 Base64 编码的原始密钥字符串(你示例中的密钥看起来像 Base64,需确认是否已正确转换);
- 若仍报错,请打印 subscription_info['endpoint'] 并验证其协议与主机是否可被 urllib.parse.urlparse() 正确解析。
总结:VAPID 的 aud 是面向推送服务的,不是面向你的网站。信任 pywebpush 的自动推导机制,移除手动 aud 声明,即可彻底解决该错误。

















