Skip to content

feat(dashboard): OAuth client-credentials form (closes #2761 UI leg)#2808

Merged
bokelley merged 2 commits into
mainfrom
bokelley/oauth-cc-dashboard-ui
Apr 22, 2026
Merged

feat(dashboard): OAuth client-credentials form (closes #2761 UI leg)#2808
bokelley merged 2 commits into
mainfrom
bokelley/oauth-cc-dashboard-ui

Conversation

@bokelley

@bokelley bokelley commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Closes the UI leg of #2761. Completes the feature — server-side persistence and resolution landed in #2800.

Rebase dependency: #2813 renumbers the colliding migration 419 to 420. Merge that first, then this PR rebases onto clean main.

What this PR adds

A third option on the agent-compliance page's Auth-type select — OAuth client credentials (machine-to-machine) — alongside the existing OAuth (authorization-code) and bearer/basic options. Selecting it reveals:

Field Notes
token_endpoint HTTPS URL, required. Validated server-side for SSRF (same helper as agent URLs). Inline hint shows Auth0/Okta/Azure AD/Keycloak URL patterns.
client_id Required. May be $ENV:ADCP_OAUTH_<NAME>.
client_secret Required, masked. May be $ENV:ADCP_OAUTH_<NAME>. Stored encrypted at rest.
scope Optional. Space-separated.
resource Optional. RFC 8707 resource indicator. Hint clarifies Okta/Keycloak use this one.
audience Optional. Hint clarifies this is Auth0's name for the same thing (aud claim).
auth_method basic (HTTP Basic header, default, RFC 6749 §2.3.1 preferred) or body (form fields).

Submit fires PUT /api/registry/agents/:encodedUrl/oauth-client-credentials (the endpoint from #2800), which runs the input through the shared parseOAuthClientCredentialsInput validator — same rules (SSRF, $ENV:ADCP_OAUTH_ allowlist, length limits) whether the save came from this form or the Addie save_agent tool.

The "Auth configured" label on the post-save state now distinguishes oauth_client_credentials from plain OAuth.

Review cycle

Ran through code-reviewer, security-reviewer, and dx-expert. Addressed in this PR:

  • Code (should-fix): Added .agent-cc-save to the CSS selector lists so the new button matches the branded primary-colored look of the other two save buttons.
  • DX: IdP URL pattern hint under token_endpoint; one-line clarifications distinguishing resource (RFC 8707, Okta/Keycloak) from audience (Auth0's aud claim); expanded $ENV:ADCP_OAUTH_ hint to explain why the prefix is mandatory (server-side allowlist — prevents a misconfigured agent from referencing unrelated env vars).
  • Security: Clean bill (verified CSRF is enforced globally via the /csrf.js fetch monkey-patch, no local guard needed).

Deferred as follow-ups:

  • #2809 — "Test now" dry-run button
  • #2810 — Structured error codes on credential-save endpoints
  • #2811 — Dedupe platform_type across auth-variant field groups

Verification

  • Isolated Playwright test — 16/16 assertions pass. Loads the real buildConnectForm + toggle + submit handlers, stubs fetch, drives the form end-to-end, and asserts on the captured request.
  • E2E against Docker-booted dev server — 10/10 assertions pass. Verified after rebuilding the image that the served /dashboard-agents.html includes every new marker: OAuth client credentials option, auth-cc-fields container, cc_token_endpoint input, $ENV:ADCP_OAUTH_ policy hint, IdP URL patterns (Auth0/Okta/Azure AD/Keycloak), RFC 8707 resource hint, agent-cc-save CSS class.
  • JS in the HTML parses cleanly.
  • npm run typecheck clean.

Screenshot

Full-page screenshot of the empty-state dashboard served from Docker available at .context/oauth-cc-dashboard.png locally; the form-visible render is covered by the isolated Playwright test.

🤖 Generated with Claude Code

Closes the UI leg of #2761. Completes the server-side work in #2800.

Adds a third option to the existing Auth-type select on
dashboard-agents.html — "OAuth client credentials
(machine-to-machine)" — alongside OAuth (auth-code) and bearer/basic.
Selecting it reveals:

- token_endpoint (URL, required)
- client_id, client_secret (required, both accept
  `$ENV:ADCP_OAUTH_<NAME>` references)
- scope, resource, audience (optional)
- auth_method select (basic / body)

Submit calls PUT /api/registry/agents/:encodedUrl/oauth-client-credentials
(from #2800), validated server-side through the shared
parseOAuthClientCredentialsInput. The "Auth configured" label
distinguishes oauth_client_credentials from plain OAuth post-save.

Verified via an isolated Playwright test that loads the real
buildConnectForm + toggle + submit handlers, stubs fetch, drives the
form, and asserts on the captured request. 16/16 assertions pass.

Full in-browser validation against a running dev server is recommended
before merge (requires WorkOS/PG/encryption-secret setup not available
in this workspace).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t review

Three small fixes from the code + DX reviews on #2808:

- CSS: add .agent-cc-save to the selector lists used by .agent-connect-save
  and .agent-oauth-start. Without this the new button inherits default
  browser styling instead of the branded primary-colored look. Flagged by
  code review.
- Token endpoint field: add a hint line showing the Auth0 / Okta / Azure AD
  / Keycloak URL patterns so operators don't have to fish in their IdP
  console to remember the shape.
- resource vs audience: add one-line hints under each field clarifying
  that resource (RFC 8707) is what Okta/Keycloak want and audience is
  Auth0's name for the same thing — operators routinely conflate these.
- $ENV:ADCP_OAUTH_ prefix explanation: extend the heading hint to explain
  *why* the prefix is mandatory (server-side allowlist prevents a
  misconfigured agent from referencing unrelated env vars).

Playwright test still passes (16/16 assertions) — these are text-only
edits that don't change behavior.

Not in this PR (filed as follow-ups):
- Test-now dry-run button (#2809)
- Structured error codes on credential-save endpoints (#2810)
- Dedupe platform_type across auth-variant field groups (#2811)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit 9190347 into main Apr 22, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant