Pattern for taking authenticated actions inside a widget

Hey everyone,

I’ve got authentication hooked up for my chatGPT app. After authentication I am getting the access token passed through in the header to my mcp server as expected. I can then render the widget based on the user being authenticated (e.g. show them their private information).

What I’d like to be able to do is to be able to use that token within the widget itself. For example, I’d like to be able to show a “like” button next to an image which would save the like against the user’s account.

Does anyone have a good pattern for enabling the widget code to have access to the access token? (Ideally in a way that doesn’t expose the token in plain text.)

Thanks :slight_smile:

The way to send “private” data to the widget (in your case the access token) is via the _meta parameter

return {

      content,
      structuredContent,


      // These meta are not exposed to the model, just directly sent to the widget
      // so a good place to send some secrets
      _meta: {
         …. (add token)
     }
}

and you can read it via useOpenAiGlobal('toolResponseMetadata') on the client side

Thanks very much for the response @achieving100ms .

As I understand it that would expose the token on the front-end so it could potentially be intercepted. I guess this could be ok for actions that are of low security impact and if a short-lived token was minted for the purpose.

The only other way that I have found to interact as I need to is to use the window.openai.callTool function from within the widget.
Having just tested that approach, the result from calling that function is the result of the tool call, which means that the tool call result gets returned directly to the widget and it can re-render accordingly.

This is different (and better) than my original understanding of that function, which was that callTool would invoke another turn in the main chat thread.

1 Like

The live Instacart app does what @achieving100ms suggested. It’s passing a short-lived, scoped token.

I’m exploring this too. Each tool can have a short-lived token with only the scopes it needs for more typical client-side calls you don’t want to expose a whole tool for.

Only caveat is when these tokens expire, those features of the UI that relied on it stop working. Instacart’s button to increase the count of an item, for example, quietly fails after an hour. Could make a tool to refresh the token in the background or display a “Please re-run tool” message on the UI at that point.

2 Likes

Ah, thanks for the example @deanvmauro
It’s good to see that it’s been deemed an acceptable approach by a “proper” company. :slight_smile:
This token approach would definitely be a faster and less complicated approach than the callTool round trip.

As for the tokens expiring, I’ve also been thinking about that. Regardless of these tokens, I think it’s going to be really hard to keep these standalone widgets in a fully functional and updated state some time after they were originally presented. At this point it’s hard to know how much users are going to go back to old widgets.

1 Like

Another consideration on the “callTool” vs “short-lived token” approach is that the user may want to invoke the action via the chat thread. So in my case, rather than pressing the like button within the widget they may just respond “I like that” back to chatGPT. In that case there will need to be a “like” MCP tool ready to be executed anyway. This is even more likely to happen if the user is interacting with voice.

1 Like

Good points. It’s an weird new paradigm where the user can interface either with the UI or chat box. Guess we’ll see how people end up using it, but I expect you’re right that they’ll want most functionality to be a tool and the UIs largely for displaying information in a nice format and serving as glorified confirmation buttons.