Skip to main content
Outlook Assistant · v3.7.2 minor release ·

Outlook Assistant v3.7.2 — Restart-Safe Device Code Auth (Telegram-Friendly)

Outlook Assistant v3.7.2 persists device code auth state across MCP server restarts and fixes token refresh for public-client tokens. Critical for Telegram bridges.

Highlights

Device code state survives restarts

the pending auth payload now persists to ~/.outlook-assistant-pending-auth.json (mode 0o600). authenticate writes, device-code-complete reads. Works across server crashes, host reloads, and any process boundary.

Token refresh fixed for public clients

device code is a public client flow — Microsoft rejects client_secret on refresh ('Public clients can't send a client secret'). v3.7.2 stores auth_method in the token file and excludes client_secret on refresh for device-code tokens. Browser-flow tokens unchanged.

auth_method tracked per token

every token now records how it was obtained — auth_method: device-code or browser. The refresh logic branches on this so each flow uses the right OAuth contract.

What’s new in v3.7.2

This release exists because of Untether. Untether’s Telegram bridge restarts coding agents (and their MCP servers) between tool calls — that’s part of how it works. Outlook Assistant’s device code auth flow assumed the server stayed up between authenticate and device-code-complete. It didn’t.

The bug: pending auth state was in-memory only

Microsoft’s device code flow has two server calls. The first (authenticate) returns a user code and a polling URL. You go to the URL on a browser, type the code, sign in. The second (device-code-complete) fires when you tell the agent you’re done, which exchanges the device code for a real access token.

In a normal MCP setup, those two calls happen in the same process, seconds apart. The pending state lived in a module-level variable. Fine.

In Untether (and similar agent-host environments), the MCP server may restart in between — process boundaries, idle timeouts, anything. The pending state vanished, and device-code-complete failed with “no pending device code flow”, forcing you to start over. Sometimes you’d start over and the same thing would happen.

The fix: persist to disk

v3.7.2 writes the pending auth payload to ~/.outlook-assistant-pending-auth.json with mode 0o600 (owner read/write only). authenticate writes; device-code-complete reads first, falls back to in-memory if the file isn’t there. Survives restarts, crashes, host reloads, anything that doesn’t rm the file.

The token refresh bug

Once you actually had a token, refreshing it broke if you’d authenticated via device code. Microsoft’s OAuth treats device code as a public client flow — no client_secret allowed on refresh. The previous refresh code always sent the secret, so refreshes failed with “Public clients can’t send a client secret” and the user had to re-authenticate every time the access token expired.

v3.7.2 stores auth_method: "device-code" (or "browser") in the token file and branches on it. Device code tokens refresh without the secret; browser tokens refresh with it. Both work indefinitely now.

About re-authenticating

Tokens issued before v3.7.2 don’t carry auth_method, so the first refresh after upgrading defaults to the browser-flow contract. If your tokens came from device code, that first refresh will fail and you’ll need to re-authenticate once. The fresh token gets tagged correctly and stays good thereafter.

I built this for Untether but anyone running MCP servers in environments with process restarts — orchestrators, sandbox managers, headless deployments — benefits.