feat: add specification for A2UI web app iframe component (v0.9) - #2123
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the WebAppFrameUrl component to support rendering external web applications inside a sandboxed iframe, alongside a detailed specification document for the WebApp Iframe Component (v0.9). It also adds a local Python server and a bridge script to serve and integrate a web-based Pong game. The review feedback highlights critical security concerns that must be addressed before merging: specifically, the use of wildcard origins ('') for postMessage target origins and expected origin validation, which exposes the application to message interception, and an overly permissive CORS header (Access-Control-Allow-Origin: '') on the local server.
9657e63 to
2c3de18
Compare
|
|
||
| This specification document defines the A2UI Iframe Component (v0.9) for the secure, sandboxed rendering of rich interactive web applications and model-generated HTML content. This document serves two primary purposes: | ||
|
|
||
| 1. **Platform Implementation Blueprint:** It provides client-side platform developers with a strict, standard set of instructions to implement compliant `WebAppFrameUrl` and `WebAppFrameSrcdoc` components in any native programming language (e.g., TypeScript/Web, Kotlin/Android, Swift/iOS, or Dart/Flutter) while maintaining identical security and sandboxing guarantees. |
There was a problem hiding this comment.
How does this work on, e.g., Android? Unless you're embedding a browser view, there's no such thing as frames like this what there is present in the web.
There was a problem hiding this comment.
While the specification is written primarily using web terminology (iframes, srcdoc, postMessage), it serves as a blueprint for configuring native WebView and WKWebView components to behave securely and communicate identically.
And you are correct, this is assuming that you are serving a web-application so the native app will display this by a browser widget.
|
|
||
| # 4. Component catalog definition | ||
|
|
||
| The two web frame components, _WebAppFrameUrl_ and _WebAppFrameSrcdoc_, shall be registered as distinct options in the A2UI v0.9 Component Catalog. |
There was a problem hiding this comment.
Why do we need 2 components in the catalog? Isn't the fact that we use two iframes an implementation detail that could be encapsulated by one A2UI component?
There was a problem hiding this comment.
That’s a great question, and it highlights a subtle but important distinction in the architecture.
You are correct that the double-iframe sandbox pattern (an outer proxy iframe wrapping an inner sandbox iframe) is strictly an implementation detail that is completely hidden from the A2UI agent.
However, the reason there are two distinct components in the catalog (WebAppFrameUrl and WebAppFrameSrcdoc) has nothing to do with the double-iframe implementation. In fact, both components use the double-iframe setup under the hood.
They exist as two separate components in the catalog for two primary reasons:
- Different JSON Schemas for the Agent
The A2UI Component Catalog dictates the JSON structure the LLM agent must generate. These two components take fundamentally different inputs:
WebAppFrameUrl requires a url property (a string pointing to a remote server).
WebAppFrameSrcdoc requires an htmlContent property (a potentially massive string of raw HTML/JS/CSS generated dynamically by the model).
2. Divergent Security Threat Models (CSP Enforcement)
As detailed in Section 5 of the specification, because the source of the content differs, the client renderer must apply completely different security pipelines before rendering the iframe:
For WebAppFrameUrl: The client is loading an external URL via the src attribute. It cannot manipulate the HTML of the remote site, so it must rely on the remote server's HTTP headers to provide the Content Security Policy (CSP). The client's primary security duty here is checking the URL against a strict Domain Allowlist.
For WebAppFrameSrcdoc: The client receives a raw HTML string generated by the LLM. Because LLM output can be unpredictable or maliciously prompted, the client must treat it as untrusted. The client must intercept this HTML, strip out any model-generated CSP tags, and forcibly inject a strict, network-free CSP tag into the before rendering it as srcdoc.
Summary
While the double-iframe sandbox is indeed an encapsulated implementation detail, the agent does need to know whether it is passing a URL or raw HTML. Because they have different schemas and require the client to apply completely different security parsing rules, they are modeled as two separate components in the protocol catalog.
There was a problem hiding this comment.
Makes sense. I'll read over the docs again to see if I missed this or if there's something that could be added.
96a3afe to
72b342d
Compare
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { |
There was a problem hiding this comment.
Could it make sense to also have a way to pass arbitrary static data to the embedded app as a property, rather than needing to pass it via the data model?
There was a problem hiding this comment.
Love the idea.
I have introduced a new property config to allow static data assignment to embedded app.
Please check this commit.
- I have updated the spec document to discuss about it. In addition to the spec update, I added a section to discuss the difference between the 3 flavors of data:
config,datawithoutmutableData, anddatawithmutableData. - I have updated the component catalog and implementation.
- I have updated the WebAppFrameUrl example Pong game to leverage this
configto define the "matching-score" of the game. Previously, it was hard-coded to announce a winner who scored 3 points first. Now, the Agent will return aconfigto set the exact score to call the winner (5).
There was a problem hiding this comment.
Let me know if you think config is not the right design here.
|
|
||
| ```json | ||
| { | ||
| "type": "a2ui_function_call", |
There was a problem hiding this comment.
Are these the same or similar as the API for MCP apps to interact with A2UI? Could we unify them somehow?
There was a problem hiding this comment.
They are very similar. However, I have made a conscious decision to keep them distinct. I have a table in the document https://screenshot-v2.corp.google.com/FCmW9CWE3CgfkeK showing how the mapping works.
While there are some opportunities to mirror them, I believe partial mirroring will make things further convoluted and hard to pin-point which version of an app is implemented.
Furthermore, mirroring the MCP Apps protocols could put us in a situation where we will need to keep updating our implementation to match resulting in additional workload to maintain the synchrony.
By keeping them completely distinct, I believe it gives us more consistency for the A2UI Iframe (WebAppFrame) protocol and a more room to make independent feature evolution paths.
| {name: 'McpApp', component: McpApp, schema: McpAppSchema}, | ||
| {name: 'PongScoreBoard', component: PongScoreBoard, schema: PongScoreBoardSchema}, | ||
| {name: 'PongLayout', component: PongLayout, schema: PongLayoutSchema}, | ||
| {name: 'WebAppFrameUrl', component: WebAppFrameUrl, schema: WebAppFrameUrlSchema}, |
There was a problem hiding this comment.
@josemontesp is there some way in Angular that we the application developer could pass some configuration data to the Component when installing it in a catalog?
I think it could be great for a developer to be able to set some static domain allowlist for these apps here, to statically protect the client against loading apps at arbitrary domains.
There was a problem hiding this comment.
Oooo
This would be cool.
Maintaining an allowlist on the client-side catalog would be a nice protection against Agent hallucination and compromised A2UI payloads coming from Agent/MCP servers.
There was a problem hiding this comment.
In Angular we could use injection tokens that are provided at the app root level, with an optional type-safe configuration. The component can then inject that configuration directly into the component class.
|
|
||
| Used to load standalone, sandboxed, model-generated HTML/JS layouts. | ||
|
|
||
| ```json |
There was a problem hiding this comment.
Just a thought -- take it or leave it...
WebAppFrameSrcdoc and WebAppFrameUrl are quite similar. If we expect them to remain this way, maybe extract the common properties into a new WebApp schema, and then include that in both?
The WebApp schema would have all the properties that are common between the two.
There was a problem hiding this comment.
I think this is a reasonable POV.
But I will leave it until I have an implementation of the 2 versions completed.
We already had some spec updates through this review cycle and prematurely refactoring them might make us less agile to polish implementation or identify new ideas.
…g ajv to secure event, function, and data communications.
…ting in the spec file
…d validation structures
…yped properties and data paths
…nsure consistent object key ordering in data model comparisons
…and update pong engine to support configurable winning scores
|
Hi all, If there are any more comments, please LMK. I will address them as a follow up! |
Description
This PR introduces the new URL-based web application iframe component (
web-app-frame-url) for the A2UI protocol, adding a secure and isolated method to embed external web applications via URL. It also includes a new "Pong" community sample application to demonstrate its usage.https://screencast.googleplex.com/cast/NDU2Njg0MjA3MTg0MjgxNnxjNzRjZjIyZS0zOA
🌟 Key Features & Additions
Web App Frame URL Component (
web-app-frame-url):web-app-frame-url.tsto the Angular client to handle rendering external web apps inside a sandboxed iframe.web-frame-component_spec.mdto define the component's API, two-way data binding handshake behavior, and strict security considerations.mcp_app_catalog.json.sandbox-url.htmland updatedsandbox.tsto facilitate securepostMessagecross-origin communications while strictly defining<meta>tag requirements andContent-Security-Policylimits for URL-based frames.Pong Web Sample:
samples/community/web/pong/sample app.pong_web_frame_bridge.js, which handles the client-sidepostMessagehandshake, state synchronization (player/cpu scores), and function calls with the A2UI host.pong_server.py) to serve the application and inject the bridge script seamlessly.Python ADK Integration:
mcp_app_proxy/tools.pyandagent.pyto allow the proxy agent to interact with and render the new Pong game component.📝 Notes for Reviewers
web-frame-component_spec.mdandsandbox-url.htmlto ensure the cross-origin communication remains completely secure.uvis configured properly if testing the sample locally, as per theuv.lockandpyproject.tomlconfigurations.Pre-launch Checklist
One time:
For this PR:
If you need help, consider asking for advice on the discussion board.