Skip to content

fix(server): send PushNotificationConfig.authentication as an Authorization header - #1271

Merged
JakubWorek merged 2 commits into
jakubworek/acts-context-id-mismatchfrom
jakubworek/acts-push-auth-header
Sep 29, 2026
Merged

JakubWorek merged 2 commits into
jakubworek/acts-context-id-mismatchfrom
jakubworek/acts-push-auth-header

Conversation

@JakubWorek

@JakubWorek JakubWorek commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

What

Spec 4.3.3 gives the webhook request an Authorization: {authentication_scheme} {credentials} header, built from PushNotificationConfig.authentication.

BasePushNotificationSender never read that field - the only header it has ever sent is X-A2A-Notification-Token, from the sibling token. A receiver therefore had no credential to check and no way to tell a genuine push from a forged one, which is the whole point of registering authentication in the first place.

Nothing suggests this was left to the application. The constructor docstring explicitly justifies delegating URL screening, on the grounds that the spec makes it a SHOULD, and says nothing about auth, which the spec makes a MUST. The code already reads the field next to it. This reads as an omission.

Only when both halves are present

AuthenticationInfo is a message, so a config can set scheme without credentials. Sending on that would put Bearer with nothing after it on the wire - a header that looks like a credential and is not. Both must be non-empty.

Note the singular scheme. Only the v0.3 compat type has repeated schemes, and conversions.py:252-261 collapses it to schemes[0] on the way in, so the sender only ever deals with one.

Heads-up on the ACTS side

SEC-PUSH-001, SEC-PUSH-002 and PUSH-DELIV-001 currently pass in nightly CI for every SDK, so this may look like a fix to something that was not broken. It is not: the assertion that inspects the delivered request is new, added in a2aproject/A2A@82c277f. The corpus CI runs predates it, and the older tests only checked that the config API accepted the config - which, as that commit's own note puts it, "a server that stores it and pushes anonymously, or never pushes, satisfies".

A consequence worth stating: no other SDK has been measured against the real assertion yet, so unlike the rest of this stack there is no cross-SDK corroboration here. The code is the evidence - push_info.authentication appears nowhere under src/a2a/server/ before this change.

Result

Clears SEC-PUSH-001, SEC-PUSH-002 (must) and PUSH-DELIV-001 (may) on all three bindings, and with them the last failing MUST:

binding must verdict
jsonrpc 59/59 CONFORMANT
grpc 47/47 CONFORMANT
rest 49/49 CONFORMANT

The three PRs after this one are SHOULD-level and change the verdict for nobody; they take the remaining non-MUST failures to zero.

Closes #585

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🧪 Code Coverage (vs jakubworek/acts-context-id-mismatch)

⬇️ Download Full Report

Base PR Delta
src/a2a/server/tasks/base_push_notification_sender.py 95.12% 94.34% 🔴 -0.78%
Total 93.12% 93.12% ⚪️ -0.00%

Generated by coverage-comment.yml

@JakubWorek
JakubWorek added this pull request to stack #1275 September 23, 2026 12:55
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-push-auth-header branch from 675e513 to 337c1e8 Compare September 23, 2026 13:11
@JakubWorek
JakubWorek marked this pull request as ready for review September 23, 2026 13:26
@JakubWorek
JakubWorek requested a review from a team as a code owner September 23, 2026 13:26
@ConnorMoss02

Copy link
Copy Markdown

This also fixes #585, open since December, so adding Closes #585 would close it. #598 targets the same issue but reads authentication.schemes, which the v1 AuthenticationInfo no longer has.

Comment thread src/a2a/server/tasks/base_push_notification_sender.py Outdated
Comment thread src/a2a/server/tasks/base_push_notification_sender.py Outdated
Comment thread src/a2a/server/tasks/base_push_notification_sender.py Outdated
Comment thread src/a2a/server/tasks/base_push_notification_sender.py Outdated
Comment thread src/a2a/server/tasks/base_push_notification_sender.py Outdated
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-push-auth-header branch from 337c1e8 to 8ffc371 Compare September 28, 2026 08:30
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-push-auth-header branch from 8ffc371 to 2957666 Compare September 28, 2026 08:47
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-push-auth-header branch from 2957666 to c431444 Compare September 28, 2026 08:54
…zation header

Spec 4.3.3 gives the webhook request an
'Authorization: {scheme} {credentials}' header built from
PushNotificationConfig.authentication, but the sender only ever read the
sibling token field, so a receiver had no credential to check and could
not tell a genuine push from a forged one.

Sent only when both scheme and credentials are set: a half-filled
AuthenticationInfo would otherwise put 'Bearer ' with nothing after it
on the wire.
@JakubWorek
JakubWorek force-pushed the jakubworek/acts-push-auth-header branch from 533fa53 to faf467a Compare September 28, 2026 10:14
@JakubWorek
JakubWorek merged commit 5751d31 into main Sep 29, 2026
35 of 37 checks passed
@JakubWorek
JakubWorek deleted the jakubworek/acts-push-auth-header branch September 29, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: PushNotificationConfig.authentication is ignored; no Authorization header is sent in push notifications

3 participants