TomLabs Apps
← All applications

PatWatch

Watches the expiry of Azure DevOps and GitHub personal access tokens and warns before one runs out

windows tray azure-devops github tokens Personal

PatWatch

Small Windows desktop utility that watches the expiry of personal access tokens — Azure DevOps first, GitHub and anything else by hand — and warns before one runs out. Avalonia 11 / .NET 10, ops-console look, lives in the tray.

PatWatch

What it does

  • Azure DevOps accounts — give PatWatch a PAT of its own for an organization and it lists every PAT of that user through the Token Admin API: name, scopes, created / expires, whether it is still valid. The PAT used for that needs full access or the "Token administration" scope (the API answers 401 otherwise). It is stored DPAPI-encrypted for the current user; the azdo-pat secret of the TomLabs vault (~/.tomlabs) can be taken over with one click.
  • Tracked tokens — for what no API can list: a GitHub PAT, a token of an organization without a suitable PAT, a NuGet key, anything. Name, provider, where it is used, expiry date and optionally the token value itself. With the value stored PatWatch probes it on every check: Azure DevOps answers whether it still works, GitHub also reports the expiry date (github-authentication-token-expiration), so the date fills itself in.
  • Status per token: OK, EXPIRING (within the warning window, 14 days by default), EXPIRED, REVOKED (the provider refuses it although its date has not passed), UNKNOWN (no date). Colours in the table, the sidebar dots and the header chips; the filters are Active (everything not expired or refused), Attention (expiring, expired, refused), Expired (expired and refused) and All, plus full-text search over name, organization, scopes and usage. An empty table always says how many tokens the filter is hiding.
  • A refusal is explained rather than just coloured: the row's tooltip and the inspector spell out what was asked and what came back ("dev.azure.com/Lineup refused the token: it is revoked or expired, or it belongs to another organization or service"). A stored value that cannot be asked about sensibly — a token of a service PatWatch does not speak to — gets Don't ask the provider about this token, and only the date counts from then on.
  • Background check every few hours while PatWatch runs — in the window or hidden in the tray — and a Windows toast once a day per token that needs attention. Start with Windows starts it minimized to the tray.
  • The tray icon is the indicator: the key turns amber when a token expires within the warning window and red once one has expired, and its tooltip names the token that runs out first. The three variants are drawn by tools/Make-Icons.ps1 from the accent, warn and error colours of the theme.
  • Ops-console UI: System / Light / Dark theme (System follows Windows live), command palette (Ctrl+K), Settings and Logs tabs, self-update from the TomLabs app store (stable = tagged releases, nightly = every push).

Keyboard

Keys Action
Ctrl+K Command palette: jump to a token or source, run any action
Ctrl+N Add an Azure DevOps account
Ctrl+T Track a token by hand
Ctrl+F Filter the table
F5 Check everything now
Esc Leave the text box, then clear the selection
Ctrl+Shift+L Cycle the theme: system → light → dark

Files

What Where
Settings, accounts, tracked tokens %APPDATA%\PatWatch\settings.json (tokens DPAPI-encrypted)
Last token list per account %APPDATA%\PatWatch\cache\<account>.json (no token values — the API never returns them)
Logs (daily, 14 days) %LOCALAPPDATA%\PatWatch\logs\patwatch-<date>.log — also on the Logs tab
Updates %LOCALAPPDATA%\PatWatch\updates

PATWATCH_DATA_DIR=<folder> runs against another data folder (logs then go to <folder>\logs); PATWATCH_NOW=<ISO date> freezes the clock the statuses are evaluated against (UI fixtures).

Command line

PatWatch                 open the window
PatWatch --minimized     start hidden in the tray (what "Start with Windows" uses)
PatWatch --health        print {"status":"Healthy","version":"…","name":"patwatch"} and exit
PatWatch --headless      run without a window for scripted UI checks (see CLAUDE.md)

Build

git clone https://tomlabscloud.visualstudio.com/PatWatch/_git/PatWatch
dotnet build PatWatch.slnx
dotnet test tests/PatWatch.Tests/PatWatch.Tests.csproj
dotnet publish src/PatWatch/PatWatch.csproj -c Release        # portable self-contained PatWatch.exe

Releases are built by azure-pipelines.yml through the app store's publish-desktop-app.yml template: every push to master feeds the nightly channel, a v* tag the stable channel. The version comes from VersionPrefix in src/PatWatch/PatWatch.csproj and is shown in the window header. See CHANGELOG.md.

Why not the PAT Lifecycle API?

Azure DevOps has a newer _apis/tokens/pats API, but it accepts Microsoft Entra tokens only — not PATs, and not at all for organizations backed by a Microsoft account. The older Token Admin API (_apis/tokenadmin/…) works with a PAT that carries the vso.tokenadministration scope, which is what PatWatch uses. Where neither is available, track the token by hand.

Changelog

0.1.5 — 2026-09-24

  • Changed: the self-update library comes from nuget.org (TomLabs.AutoUpdate 0.3.2) instead of a git submodule; updates work as before.

0.1.4 — 2026-09-24

  • Changed: the theme switch now has a System option that follows Windows live; earlier Light/Dark choices were reset to System once.
  • Added: the header button shows the current mode (half circle = System, sun, moon); the command palette can set each mode directly.

0.1.3 — 2026-09-24

  • Fixed: a tracked token the provider refused dropped out of every filter but All, while the sidebar and the status bar still counted it — the table looked empty for no reason. Active now means "not expired and not refused" (a token without a date belongs there too), a refused token counts as needing attention, and an empty table says how many tokens the filter is hiding.
  • Added: a refusal explains itself. The row's tooltip and the inspector name the organization that was asked and what it answered, instead of only painting the token red.
  • Added: Don't ask the provider about this token for a stored value PatWatch cannot ask about sensibly — a token of another service, or an organization it cannot reach. The expiry date then decides alone.
  • Fixed: Azure DevOps answers 200 as "Anonymous" for a credential it does not understand where an organization allows anonymous reads, so any random string was reported as a working token. Such an answer now counts as a refusal.

0.1.2 — 2026-09-24

  • Added: the tray icon itself reports the state — violet while every token is fine, amber once one expires within the warning window, red once one has expired — and its tooltip names the token that runs out first, so hovering answers it without opening the window.
  • Fixed: after an update the status bar kept "updates off: Another instance of the application is running; close it first." for the rest of the session, although the replaced build had exited seconds later (TomLabs.AutoUpdate 0.3.1).

0.1.1 — 2026-09-24

  • Fixed: a tracked token entered with a date that had already passed stayed REVOKED after the date was corrected, with no way back. Editing the expiry date or the provider now forgets what the last probe said, and the check that follows the save asks the provider again.
  • Fixed: a tracked token whose stored value was forgotten is no longer judged by the probe verdict of that value — only its expiry date counts.

0.1.0 — 2026-09-18

  • Azure DevOps accounts: every PAT of the signed-in user listed through the Token Admin API with name, scopes, expiry date and validity; the PAT used for the API is stored DPAPI-encrypted and can be taken over from the TomLabs vault.
  • Tracked tokens entered by hand for Azure DevOps, GitHub and anything else: name, where it is used, expiry date and optionally the token itself, which PatWatch probes (Azure DevOps: still accepted or not; GitHub: also the expiry date from the response header).
  • Status per token — OK, expiring within the warning window (default 14 days), expired, revoked — in the table, the sidebar dots and the header chips; filters and full-text search.
  • Background check every few hours while the window is open or hidden in the tray, Windows toast once a day per token that needs attention, "Start with Windows" minimized to the tray.
  • Ops-console UI with light/dark mode, command palette (Ctrl+K), Settings and Logs tabs, self-update from the TomLabs app store.