Skip to content

WorkIQ MCP auth: UI-tier device-code flow (Phase 3 of #441)#443

Merged
rockfordlhotka merged 1 commit into
mainfrom
rockfordlhotka/441-workiq-ui-phase3
May 23, 2026
Merged

WorkIQ MCP auth: UI-tier device-code flow (Phase 3 of #441)#443
rockfordlhotka merged 1 commit into
mainfrom
rockfordlhotka/441-workiq-ui-phase3

Conversation

@rockfordlhotka
Copy link
Copy Markdown
Member

Closes Phase 3 of #441. The UI tier (Blazor + CLI) drives the MSAL device-code flow against Entra, serializes the resulting cache, and publishes WorkIqAuthCacheUpdated to the agent. Out of scope here: Phase 4 (Entra app registration + end-to-end smoke), Phase 5 (re-consent polish).

Summary

  • Same flow for Blazor and CLI. Both surfaces use device-code so the Blazor server-rendered app needs no OAuth callback route or PKCE cookie — the user just types the displayed code into a browser tab.
  • New shared library RockBot.UserProxy.WorkIqAuth holds the device-code orchestrator (WorkIqDeviceCodeFlow), settings (WorkIqClientSettings), the expired-notification listener (WorkIqAuthStatusListener), and the auth message contracts (WorkIqAuthCacheUpdated/Expired/Topics — relocated from RockBot.Agent.McpBridge.Auth so both sides reference the same types).
  • Blazor. WorkIqConnect.razor covers the NotStarted/InProgress/Success/Failed states and a copy-code button. WorkIqReconnectBanner.razor appears above the chat header on WorkIqAuthExpired. WorkIqAuthUiService is scoped per circuit and bridges listener events to component re-renders. An "M365" pill in the chat header opens the connect modal.
  • CLI. rockbot auth workiq renders the device code + URL with Spectre.Console, polls until completion, publishes the cache, and exits with stable codes (0 success, 130 user-cancelled, 78 not-configured, 1 other). HostFactory.Build gained an optional configure delegate so only this command pulls MSAL into the host's services.
  • Helm. Blazor deployment env vars (WorkIQ__TenantId/ClientId/Scopes/Authority) gated on workiq.enabled. No new values.yaml keys — reuses the workiq.* block introduced in Phase 2.

Test plan

  • Full dotnet build RockBot.slnx clean (0 errors)
  • Full dotnet test RockBot.slnx clean across all 20 test projects
  • New tests: 10 in RockBot.UserProxy.WorkIqAuth.Tests (settings binding, listener event flow + dead-letter on malformed payload, flow rejects not-configured); 7 in RockBot.UserProxy.Blazor.Tests (UI state service transitions, dispose unsubscribes); 2 in RockBot.Cli.Tests (host factory wires the flow only when configured)
  • Phase 2 tests still pass after the message-type relocation
  • helm template with workiq.enabled=false emits no WorkIQ env vars on Blazor
  • helm template --set workiq.enabled=true ... emits the four conditional env vars on the Blazor deployment
  • Grep confirms no log statements emit token bytes or cache contents

Type relocation note

WorkIqAuthCacheUpdated, WorkIqAuthExpired, and WorkIqAuthTopics moved from RockBot.Agent.McpBridge.AuthRockBot.UserProxy.WorkIqAuth so the UI tier doesn't depend on the agent project. Phase 2's agent files added one new using RockBot.UserProxy.WorkIqAuth; directive; behavior is unchanged.

🤖 Generated with Claude Code

Phase 3 of #441. The UI tier (Blazor + CLI) drives the MSAL device-code
flow against Entra, serializes the resulting cache, and publishes
WorkIqAuthCacheUpdated to the agent. Both surfaces use the same flow so
the Blazor server-rendered app needs no callback route or PKCE cookie —
the user just types the displayed code into a browser tab.

New shared library RockBot.UserProxy.WorkIqAuth contains the device-code
orchestrator, settings, the expired-notification listener, and the auth
message contracts (relocated from RockBot.Agent.McpBridge.Auth so both
sides reference the same types).

Blazor: WorkIqConnect.razor (NotStarted/InProgress/Success/Failed states),
WorkIqReconnectBanner.razor, WorkIqAuthUiService (scoped per circuit).
M365 pill in chat header opens a connect modal; banner reappears above
the chat when the agent publishes WorkIqAuthExpired.

CLI: `rockbot auth workiq` command. Spectre.Console renders the device
code + URL; awaits MSAL polling; publishes cache; exits 0/130/78/1 by
WorkIqAuthFlowException code. HostFactory.Build gains an optional
configure delegate so only this command pulls in MSAL.

Helm: Blazor deployment env vars (WorkIQ__TenantId/ClientId/Scopes/Authority)
gated on workiq.enabled. No new values.yaml keys — reuses the block
introduced in Phase 2.

Out of scope: Phase 4 Entra registration + end-to-end smoke,
Phase 5 re-consent polish.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rockfordlhotka rockfordlhotka merged commit 7d613fa into main May 23, 2026
2 checks passed
@rockfordlhotka rockfordlhotka deleted the rockfordlhotka/441-workiq-ui-phase3 branch May 23, 2026 07:06
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