Rightshold™ Sign up

Answers · agent safety

How do I bind a one-time human confirmation to an OAuth client/connector and exact action, then consume it?

Last updated

TL;DR: A standing OAuth grant for a connector is not a yes for every tools/call that connector can make. For high-risk actions, mint a one-time confirmation that names the OAuth client_id (or connector id), the exact action (tool name + argument hash), and optionally the step-up strength you required (RFC 9470 acr_values / max_age). Store it outside the agent session, show the human the real client and arguments, then at execution verify client_id + action hash, mark the confirmation consumed, and refuse reuse. Pair OAuth step-up when the access token's authentication event is too weak or too old with an application-level single-use approval so a refreshed token cannot silently replay the same dangerous call.

What should I check, step by step?

1. Identify the OAuth client or connector that will perform the side effect (MCP client_id, IDE connector id, or registered app id). Do not accept a confirmation that omits client_id.

  1. Freeze the action: tool or API name, canonical argument hash, resource/audience, and policy_version. Hash those fields the same way at approve time and at execute time.
  2. If the access token's auth event is too weak or stale for this action, challenge with RFC 9470 insufficient_user_authentication (acr_values / max_age) so the human re-authenticates before you even open the confirmation prompt.
  3. Call request_human_approval with summary plus action { client_id, connector, tool, arguments_sha256, audience, policy_version }. Expire in minutes, not days.
  4. Keep the approval id and decision on the server (or ledger). Give the agent only the approval id — never confirmed=true in chat memory.
  5. Immediately before the side effect: verify_human_approval against the live action hash and client_id; reject on mismatch, expiry, or prior consumption; then mark the confirmation single-use consumed in the same transaction as the start of the side effect.
  6. Refuse a second tools/call that presents the same approval id even with identical arguments unless you deliberately issued a multi-use grant with an explicit remaining_uses counter.
  7. Log client_id, approval id, consume time, and allow/deny outside the agent session (record_ai_run or your SIEM). Rotate or revoke the OAuth client if confirmations are being stolen or replayed.

Why the OAuth grant alone is not enough

OAuth access tokens authorize a client at a resource; they do not bind a human's yes to one tool invocation. RFC 9700 (OAuth 2.0 Security BCP) pushes sender-constrained tokens, exact redirect URI matching, and audience restriction — necessary baselines that still leave room for a compromised agent to call every scope the token carries.

Approve once, verify client + action, consume

Put client_id (and connector label humans recognize) in the approval action object alongside tool and arguments_sha256. verify_human_approval must fail if the agent swaps to another OAuth client that shares a user grant.

What can go wrong?

Confirmation UI shows "GitHub connector" while the token presented belongs to a different client_id the user also authorized.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before this OAuth connector runs a risky tool call, ask me to approve the exact client id, tool and argument hash, expire the yes quickly, and wait for my decision so it can be consumed once.”

One-click setup

{
  "tool": "request_human_approval",
  "arguments": {
    "summary": "Allow cursor-mcp-github (client_id md.cursor.github) to call issues.create on repo acme/payments (args sha256:7a1c…); consume after one use",
    "action": {
      "type": "oauth_connector_action",
      "client_id": "md.cursor.github",
      "connector": "GitHub",
      "tool": "issues.create",
      "arguments_sha256": "7a1c…",
      "audience": "https://api.github.com",
      "policy_version": 9
    },
    "expires_in_minutes": 10
  }
}

Rightshold records human approval requests and signed decisions for agents that call it. It does not run your authorization server, implement RFC 9470 challenges, or stop an OAuth connector that never verifies or consumes the approval. Enforce client_id + action hash checks and single-use consume in your connector and tool runner. Not legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'