How Muse works
Muse is a personal agent that acts for Sam. It asks, gets turned away, sends Sam to PingOne to sign in, and then asks again with a token that says Muse is acting for Sam. Every step in the real mode talks to the real systems.
The path of one request
Sam asks "Show my airline points". The first call carries no token on purpose, so the gateway answers 401 and tells Muse where to sign in.
The steps, in order
- Sam asks. A request such as "Show my airline points".
- Muse calls the gateway with no token and gets 401. The answer points to the sign-in server. Nothing authenticated has been sent.
- Muse sends Sam to PingOne with a fresh sign-in (auth code with PKCE, always asking for the password). The user name is pre-filled, so Sam types only the password.
- PingOne runs a DaVinci flow. It checks the user, asks PingOne Protect for a risk level, and acts on it (next section).
- PingOne returns a code to Muse. Muse swaps it for Sam's token. The token stays on Muse's server.
- Muse acts for Sam. It gets its own agent token, then makes two token exchanges. The result names Sam as the subject and Muse as the actor.
- Muse asks again with that token. The gateway checks the signature, audience and scope.
- PingOne Authorize decides. It checks the audience, that Muse is a registered actor, and that the tool is allowed.
- The tool runs and Muse tells Sam "You have 4,500 points (Gold)."
What PingOne does at sign-in
- Protect scores the sign-in. The flow sends the user, the address, the browser and the app to a risk evaluation. The level comes back as LOW, MEDIUM or HIGH.
- HIGH stops the sign-in. Sam sees "Sign-in blocked: this login looks high risk."
- MEDIUM asks for MFA. Muse has a PingOne MFA switch. With it off, the flow skips MFA for that sign-in.
- Protect flags Muse. A Protect predictor matches Muse's app id, which the flow sends as the target of the risk evaluation, and rates it HIGH. The flow records that verdict on the user and it travels into the final token as
protect_agent. The flow also recognizes Muse by its app id on its own. When both agree, Protect's verdict is the one shown. - An "AI agent detected" screen comes first. It shows what the flow knows about the requester, then Sam gives consent. The agent's name is bold and coloured: red with the line "PingOne Protect agent check: FLAGGED as an AI agent" when Protect rated it HIGH, and blue with "no agent signal, identified from the client ID only" when only the app id gave it away.
| Shown on the screen | Where it comes from |
|---|---|
| Agent name, id, type | The PingOne app that started the sign-in |
| Signing in as | The user name from the sign-in hint |
| Request from IP, browser | The request that reached PingOne |
| Protect risk and evaluation id | The risk evaluation the flow just created |
| PingOne MFA | On, or switched off for this sign-in |
How Muse acts for Sam
Muse never sends Sam's token as if it were Sam. It trades it for a token that says who is acting for whom (RFC 8693, on behalf of).
- Agent token. Muse proves its own identity with its client credentials.
- Exchange 1. Sam's token plus Muse's token become one token for Sam with an
actclaim naming Muse. - Exchange 2. The same token is re-issued for the gateway's audience, and
actcarries over.
The final token has Sam as sub and Muse's client id as act.sub. Authorize requires Muse to be on its registered actor list, and Muse is.
On the Muse page, the name turns red ("Detected by Protect") when the token carries Protect's verdict, and blue ("Identified from the client id") when only the act claim names Muse. Protect wins when both are present.
Signing in as just a user
The same page has a second button, "Sign in as Sam (no agent)". Sam signs in as himself, through a different PingOne app (Muse user login), so the flow shows no "AI agent detected" screen and no consent, and nothing is exchanged. Sam's own token then goes straight to the gateway, which refuses it: it carries no act claim and is not for the gateway's audience. Only a token that names an agent acting for Sam gets through.
The flow tells the apps apart by app id: it shows the agent screen and asks for consent only when the sign-in comes from the Muse app.
Two ways to reach the tools
| Lane | Path | Status |
|---|---|---|
| Agent Gateway | Muse calls the gateway directly. The gateway validates the token against PingOne's keys and runs Authorize. | Works |
| Agent Privilege, then Agent Gateway | Muse calls a Privilege app in front of the gateway. Privilege matches the token to Muse's identity and key, passes it on, and the gateway and Authorize decide. | Works |
| Agent Privilege alone | Privilege cannot do the on-behalf-of exchange yet, so the gateway has to. | Waiting on Privilege |
The Privilege lane needed Privilege's own audience to be accepted by the gateway and by Authorize. Both now allow it as an extra audience, and nothing changes for other callers.
Using it from another agent: which connector gets picked
The Airline Connector lets an agent such as Meta's Muse reach the same tools. The agent reads the tool names and descriptions from every connector you have added, and its model decides which tool fits your request. The server is never asked whether a request is for it. It only sees a call after the agent has chosen it.
- With one airline connected, "How many airline points do I have?" goes to it.
- With two airlines connected, such as United and American, and tools described only as "airline points", the agent may pick either, call both, or ask you which airline you mean. That is the agent's choice, not the connector's.
- To steer it, name the airline in the prompt ("How many United points do I have?"), and put the airline in the connector name and in each tool description.
- Each connector signs you in on its own, and it only ever holds your token for its own airline. One airline's server never sees another's token.
How an agent chooses between tools is up to that agent, and this page can only describe the general behaviour of MCP clients. The tool descriptions are the part you control.
How a customer connects: from their own assistant
A customer never types a server address or a client ID. The airline lists its connector once in each assistant's directory. The customer finds the airline there by name, clicks Connect, and signs in at PingOne. On the Muse page, "Connect from your assistant" plays this out: the directory card is a stand-in, and everything after Connect is real.
- Find it. In ChatGPT, Claude or Meta AI, the customer searches the apps or connectors directory for the airline, or the assistant suggests it when they mention the airline.
- Connect. One click. The assistant opens the airline's PingOne sign-in.
- Sign in and consent. PingOne Protect checks the sign-in, the "AI agent detected" screen names the assistant (ChatGPT, Claude, or the Airline Connector for Meta AI), and the customer allows it to act for them.
- Ask. "How many points do I have?" The assistant calls the airline's tools with a token that says who the customer is and which assistant is acting.
| Assistant | What the airline does once | How PingOne knows which assistant it is |
|---|---|---|
| ChatGPT (OpenAI) | Builds an app with the Apps SDK, which runs on MCP, and submits it for review with its listing text, test account and countries. Once approved it is in the app directory. | Its own PingOne app, "ChatGPT agent login". Protect's agent check lists that app, and the consent is "Allow ChatGPT to act for you". |
| Claude (Anthropic) | Submits the server to Anthropic's Connectors Directory: OAuth, a readOnlyHint or destructiveHint on every tool, a privacy policy, support contacts, example prompts and a test account. | Its own PingOne app, "Claude agent login", with its own consent. |
| Meta AI | No public directory yet, so there is nothing to list today. The airline would list it once Meta offers one. | Muse's PingOne app through the Airline Connector; the screens say "Airline Connector". |
Behind the listing it is the same MCP server and the same PingOne flow for every assistant. Only the PingOne app differs, picked from the assistant's callback address, so Protect and the screens can name each one, and the final token's act is that assistant.
The listing steps come from each vendor's documentation as of October 2026, and they change. A listing is the vendor's decision after review. This demo is not listed in any directory, which is why the card on the Muse page is a stand-in.
Client ID Metadata Documents (CIMD): no registration step
An OAuth server has to know who is asking before it sends someone to sign in. There are three ways it learns that. The company types in a client ID by hand, as in Meta's Muse. The app registers itself on first use (Dynamic Client Registration, DCR), and the server mints a new client every time. Or, with CIMD, the app's client_id is an HTTPS address, and the server fetches the document at that address to read the app's name and allowed callbacks. Nothing is registered, so nothing piles up on the server.
| App | Supports CIMD | The client_id it presents |
|---|---|---|
| Claude: web, Desktop, mobile, Claude Code | Yes, on by default. Anthropic recommends it over DCR for busy servers. | A metadata address Anthropic hosts. For Claude Code the docs give https://claude.ai/oauth/claude-code-client-metadata. |
| ChatGPT | Yes, and it prefers CIMD over DCR. | https://chatgpt.com/oauth/client.json, or a per-callback https://chatgpt.com/oauth/{callback_id}/client.json |
| Codex | Yes. It uses CIMD when the server advertises it, then DCR. A client ID you set always wins. | https://chatgpt.com/oauth/codex/client.json |
| Meta's Muse | Not checked. | Unknown. Today it is given a client ID by hand. |
To use it, the server's authorization metadata must say client_id_metadata_document_supported: true. Claude also needs none listed in token_endpoint_auth_methods_supported, or it falls back to DCR. ChatGPT's own document asks for private_key_jwt (it signs a token request with a key it publishes), so a server that wants ChatGPT needs to support that too; Codex and Claude Code are public clients that need only PKCE. When the authorize request arrives with an HTTPS client_id, the server fetches the document, checks that the document names that same address, and checks that the requested callback is one of its redirect_uris.
Open Muse's connector does not do this yet. It lists none but does not advertise CIMD, so Claude, ChatGPT and Codex would register through /connector/register on every new connection. Building CIMD is a separate change. See real requests and responses against Linear and Notion, and a mock of what Muse would do. The client IDs above come from each vendor's documentation as of October 2026, and the hosted address for Claude's web and Desktop apps has not been confirmed (the docs show Claude Code's).
What is real and what is not
- Real The PingOne sign-in, the DaVinci flow, the Protect risk evaluation, MFA, the agent screen and consent.
- Real The token exchanges, the Agent Gateway, Privilege's identity and key check, and PingOne Authorize.
- Real The "just a user" sign-in and the gateway's refusal of Sam's own token.
- Real The tool call. The points come back from the gateway's tool server, which holds sample data.
- Mock The offline Muse. It keeps the same screens with a stub gateway and stub checks, and contacts nothing. It is still there for demos with no network.
- Real On a local run Muse can use a llama.cpp model. The model picks one tool from Muse's own short list before the 401 and words the reply after the tool runs. It never writes tool arguments and never sees a token, and Muse checks that every number in its reply comes from the result.
- Simple Without a model, and always on the hosted site, Muse reads a request by keyword and answers points requests only.
- Simple Protect's signal for Muse is its app id fed into a custom predictor. It is not behavioural bot detection from the device.
- Open The device fingerprint is not passed in yet, so demouser lands on MEDIUM.
The hosted site runs Real mode with its own PingOne app. A local run needs the PingOne app's secret and the gateway, and the offline Mock is local only.