feat(server): support A2A protocol#2656
Conversation
|
hey! thanks for contribution - we'll check this after the weekend. |
|
Thank you for the contribution, made a few comments here and there :) Is that all required to fully support A2A, as you wrote that I'd close #1762 which is the full integration? Also, is there a way to do the proper integration/e2e testing like e..g for existing MCP runtime to ensure it works well with A2A as the full transport? |
|
Thanks for the review! All comments are clear and I will address every point as suggested. |
|
when testing, see how |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2656 +/- ##
============================================
+ Coverage 68.33% 68.40% +0.06%
Complexity 739 739
============================================
Files 1053 1054 +1
Lines 84763 84955 +192
Branches 61297 61499 +202
============================================
+ Hits 57923 58111 +188
+ Misses 24468 24460 -8
- Partials 2372 2384 +12
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
bd98498 to
b85afac
Compare
28f9cb5 to
dff37e2
Compare
|
Hello @Tyooughtul |
Hi @hubcio , I think I’ve addressed all comments from @spetz, and the PR is ready for review. I’ll keep following up and fix any issues promptly. 😊 |
|
Hi @spetz @hubcio, |
|
@Tyooughtul sure, the CI has started again, however I can see that there are still some pending comments waiting to be resolved. |
24f9624 to
0b3ec9f
Compare
|
Hi @spetz, |
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. If you need a review, please ensure CI is green and the PR is rebased on the latest master. Don't hesitate to ping the maintainers - either @core on Discord or by mentioning them directly here on the PR. Thank you for your contribution! |
- Support JWKS for A2A compliant secure agent authentication - Enable key rotation without restarting the server - Allow agents from different tenants to publish to the same Iggy bus rebase to the newest master
…ness macro Extend `#[iggy_harness]` with `jwks_server(...)` attribute to support declarative JWKS mock server setup, as suggested in review to follow the harness macro convention used for MCP and connectors. - Fix the problem as suggested - Add `jwks_server(store_path = "...")` attribute to #[iggy_harness] - Add `config_path` to server(...) for custom TOML via IGGY_CONFIG_PATH - Start WireMock MockServer and inject trusted issuer env vars before server startup - Add ServerHandle::add_env() for pre-start env var injection - Add 4 e2e tests: valid_token, expired_token, unknown_issuer, missing_token with RSA key pair and JWKS fixtures
|
@Tyooughtul could you please rebase this PR? |
Yes, I'm working on it. 😊 |
57c1658 to
b18459c
Compare
b18459c to
e8ff862
Compare
| @@ -0,0 +1,75 @@ | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Why is there python under rust integration tests?
| @@ -0,0 +1,28 @@ | |||
| -----BEGIN PRIVATE KEY----- | |||
| MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/TvzTyulqS+s3 | |||
There was a problem hiding this comment.
We have the example certs under core/certs.
| } | ||
| }; | ||
|
|
||
| // debug!("Found trusted issuer config: {}", config.issuer); |
| } | ||
| }; | ||
|
|
||
| // debug!("Got decoding key from JWKS for kid: {}", kid_str); |
There was a problem hiding this comment.
Also this one, and any others similar to this one (commented out line of code).
| .http_addr() | ||
| .expect("http address should be available"); | ||
|
|
||
| let client = Client::new(); |
There was a problem hiding this comment.
Why not use Iggy HTTP client?
| } | ||
| }; | ||
|
|
||
| /* debug!( |
There was a problem hiding this comment.
Let's get rid of any commented out code.
| IggyError::InvalidJwtAlgorithm(Self::map_algorithm_to_string(algorithm)) | ||
| })?; | ||
|
|
||
| jsonwebtoken::decode::<JwtClaims>(token, &self.validator.key, validation) |
There was a problem hiding this comment.
Maybe let's log with error! macro here and don't discard it in map_err?
| } | ||
|
|
||
| let request_details = request.extensions().get::<RequestDetails>().unwrap(); | ||
| let user_id = jwt_claims |
There was a problem hiding this comment.
Sub now uses string instead of u32 yet we expect it to be parsed to numeric value - in such a case, why it's been changed to string?
|
Added a few more comments (some might be stale already, but some are up to date) - please take a look, and once resolved we could finally merge it :) |
|
@spetz Thanks for your comment and review, it helps me a lot 😊! I've got the A2A JWT authentication working end-to-end for HTTP with integration test coverage, external IdPs can now authenticate users via JWKS endpoints. That said, I'm running into a few architectural rough edges that I'd rather hash out with you before polishing this further. The immediate concern is identity mapping: I'm currently using the external JWT's 'sub' claim directly as the Iggy user_id, which feels like we're begging for namespace collisions between external issuers and our internal IDs. Should I add a claims mapping layer to transform something like "oidc|user123" into a proper local user_id? Related to that, the permission model currently grants A2A tokens full user privileges, which might be too permissive if these tokens leak🤔 Looking ahead to the VSR clustering work, I took another look at the doc and realized the shared-nothing architecture is actually a core philosophy.So the local-only JWKS cache and revocation lists might actually be fine with short TTLs rather than trying to synchronize state across nodes. That leaves me wondering: should each node just fetch JWKS independently, or is there a better approach? There's also the protocol scope to consider: JWT authentication currently only works for HTTP, so should I plan to extend this to TCP, QUIC, and WebSocket as well, or is HTTP-only the intended scope for now? Would love your guidance on these points! |
|
@Tyooughtul good questions, but don't worry about VSR here and don't expand the scope - let's finish this PR first. There are still a few unresolved inline comments from @spetz's latest review - please mark them as resolved if these are already fixed. As for the architectural stuff:
For clustering: JWKS keys could be replicated via the metadata plane, same way PATs are - one node fetches, all replicas get them through VSR. No need for each node to hit external IdP endpoints independently. |
|
@Tyooughtul as @hubcio already suggested, let's stick to HTTP as it's the only supported transport protocol AFAIR. |


Which issue does this PR close?
Closes #1762
Rationale
A2A protocol requires JWKS support to enable secure agent authentication with multiple identity providers. This change allows agents from different tenants to authenticate using their own public keys, and supports key rotation without requiring server restarts.
What changed?
Added JWKS support for secure agent-to-agent authentication. The implementation includes a JwksClient that fetches and caches public keys from JWKS endpoints, integrated JWKS into JwtManager for multi-tenant agent authentication, and updated HTTP middleware to support asynchronous JWT decoding. Also added TrustedIssuerConfig to support configuring multiple trusted issuers.
Local Execution
AI Usage
debug!to help me find bugs。cargo check --package serverandcargo build --package server.