hermes-agent/website/docs/user-guide/messaging
victor-kyriazakos e9579a9896
feat(relay): ambient token endpoint mode for gateway.idp.token_url (#84074)
* feat(relay): ambient token endpoint mode for gateway.idp.token_url

When gateway.idp.token_url is configured WITHOUT client_id/client_secret,
treat the URL as a metadata-server-style ambient credential endpoint:
plain GET, response body is the token (raw JWT or {"access_token": ...}
JSON envelope). Covers workload-identity proxies such as Domino's
$DOMINO_API_PROXY/access-token, which mint short-lived user-scoped OIDC
tokens with no client registration.

Previously this configuration was a hard error (client_id/client_secret
missing), so no working deployment changes behaviour: creds present keeps
the OAuth2 client_credentials POST, no token_url keeps Nous Portal. The
misconfig error now self-diagnoses (names the ambient fallback and how to
select the client_credentials grant instead).

* fix(relay): reject short plain-text bodies in ambient token shape gate

Review finding: the shape gate accepted any base64url-alphabet word, so an
IdP answering the ambient GET with a terse error body ('unauthorized',
'error', 'null') had that word returned as a bearer token instead of the
fail-closed misconfiguration error. Tighten the gate to JWT-like dotted
tokens (3+ segments) or long opaque tokens (>= 32 chars); short bare words
now raise the self-diagnosing ambient error.

* fix(relay): partial IdP client credentials keep the loud error, never select ambient GET

The ambient-endpoint dispatch used 'not client_id or not client_secret',
so configuring exactly one credential (a mistyped client_credentials
setup) silently issued a GET at the IdP token endpoint and then raised
'no client_id/client_secret configured' — factually wrong for that
operator, and a stray request the old hard error never made.

Ambient mode now requires NEITHER credential; a partial pair raises
immediately, names the missing key, and issues no HTTP request (tests
assert urlopen is never called). Docstring and relay.md now say
'neither' instead of 'without'.

* fix(relay): ambient JSON envelope requires a string access_token, no coercion

Review finding (P2): the JSON-envelope branch accepted any truthy
access_token via str() coercion — a number became '12345…', a boolean
became 'True', an object became its Python repr — bypassing the fail-
closed contract and deferring the failure to the connector, where it
hides the real endpoint problem.

The envelope value must now be a non-empty string, the same contract the
client_credentials path enforces on its token response. Deliberately NO
shape gate on envelope values: an envelope is an intentional token
response (mode-1 symmetry), and opaque tokens may use the standard-base64
alphabet the raw-body gate rejects. Mutation check: reverting the branch
to str() coercion sends the 3 coercion tests red (3 failed, 15 passed).

---------

Co-authored-by: Ben Barclay <ben@nousresearch.com>
2026-08-12 10:06:28 +10:00
..
_category_.json
a2a.md docs(a2a): website docs page + canonical agent-card.json path in prose 2026-08-02 15:10:15 -07:00
bluebubbles.md
buzz.md feat(buzz): WebSocket inbound transport — NIP-42 auth, live DM discovery, poll fallback 2026-07-28 21:45:34 -07:00
dingtalk.md
discord.md docs: accuracy sweep + coverage for 2 months of shipped features 2026-07-29 08:48:05 -07:00
email.md
feishu.md
google_chat.md fix(deps): repair Google transitive security floors (#72108) 2026-07-31 23:18:38 -07:00
homeassistant.md
index.md docs: document /personality none|default|neutral reset across personality docs 2026-08-03 12:29:49 -07:00
irc.md
line.md docs: fix 0.0.0.0 bind-default drift after dual-stack change 2026-07-28 22:42:41 -07:00
matrix.md docs: accuracy sweep + coverage for 2 months of shipped features 2026-07-29 08:48:05 -07:00
mattermost.md
msgraph-webhook.md docs: fix 0.0.0.0 bind-default drift after dual-stack change 2026-07-28 22:42:41 -07:00
ntfy.md
open-webui.md
photon.md docs: document dashboard session filter tabs and photon immutable-tree fallback 2026-07-28 22:54:45 -07:00
qqbot.md
raft.md
relay.md feat(relay): ambient token endpoint mode for gateway.idp.token_url (#84074) 2026-08-12 10:06:28 +10:00
signal.md
simplex.md feat(gateway): simplex channel enumeration + show configured platforms in hermes send --list 2026-08-02 15:08:45 -07:00
slack.md
sms.md
teams-meetings.md docs: accuracy sweep + coverage for 2 months of shipped features 2026-07-29 08:48:05 -07:00
teams.md docs(teams): correct devtunnel webhook protocol 2026-08-11 04:17:50 +05:30
telegram.md docs(telegram): explain rich draft final delivery 2026-08-08 17:15:45 -07:00
webhooks.md
wecom-callback.md docs: fix 0.0.0.0 bind-default drift after dual-stack change 2026-07-28 22:42:41 -07:00
wecom.md
weixin.md
whatsapp-cloud.md docs: fix 0.0.0.0 bind-default drift after dual-stack change 2026-07-28 22:42:41 -07:00
whatsapp.md docs: accuracy sweep + coverage for 2 months of shipped features 2026-07-29 08:48:05 -07:00
yuanbao.md docs: accuracy sweep + coverage for 2 months of shipped features 2026-07-29 08:48:05 -07:00