Each workstation user needs a continuously valid Claude token under their own Enterprise identity. Store only that user's OAuth state in an isolated Vault path, renew and verify it automatically, recover from Vault when possible, and alert when interactive SSO is required.
95 lines
3.6 KiB
Markdown
95 lines
3.6 KiB
Markdown
# Workstation Claude authentication renewal
|
|
|
|
## Scope
|
|
|
|
Every roster user authenticates Claude Code with their own Enterprise identity.
|
|
Credentials are never shared between OS users. Claude refreshes its normal OAuth
|
|
access token; `claude-auth-sync@<user>.timer` verifies that refresh using real
|
|
inference every six hours and backs up only the `claudeAiOauth` object to:
|
|
|
|
```text
|
|
secret/workstation/claude-users/<os-user>
|
|
```
|
|
|
|
The user's unrelated `mcpOAuth` credentials never leave their home directory.
|
|
Each renewal service has a distinct 32-day periodic Vault token, mode `0600`, at
|
|
`~/.config/claude-auth-sync/vault-token`. Its policy can access only that user's
|
|
path. The service renews the Vault token on every run.
|
|
|
|
## Normal lifecycle
|
|
|
|
1. Add the user to `scripts/workstation/roster.yaml` and apply the Vault stack.
|
|
2. Run `scripts/workstation/setup-devvm.sh` as root with the admin Vault token.
|
|
Its foreground provisioner mints the isolated periodic token and enables the
|
|
user's timer. Routine hourly provisioning never needs an admin token.
|
|
3. The user completes one initial Enterprise login:
|
|
|
|
```bash
|
|
claude auth login --claudeai --sso --email <enterprise-email>
|
|
```
|
|
|
|
4. Start the first sync immediately instead of waiting for the timer:
|
|
|
|
```bash
|
|
systemctl start claude-auth-sync@<os-user>.service
|
|
systemctl status claude-auth-sync@<os-user>.service
|
|
```
|
|
|
|
Success writes no secrets to the journal. The user's private log records `OK` in
|
|
`~/.local/state/claude-auth-sync/sync.log`; journald receives the same status with
|
|
`identifier=claude-auth-sync` for Loki alerting.
|
|
|
|
## Automatic recovery
|
|
|
|
`claude auth status` is not a sufficient health check: it can report logged in
|
|
while inference returns HTTP 401. The service therefore runs a minimal Haiku
|
|
inference with no session persistence. On failure it:
|
|
|
|
1. reads the user's latest OAuth object from Vault;
|
|
2. atomically merges it into `.credentials.json`, preserving MCP OAuth state;
|
|
3. retries inference once;
|
|
4. stores the newly refreshed OAuth object back in Vault on success.
|
|
|
|
Vault KV version history remains available for audit, but the service deliberately
|
|
does not cycle through old refresh tokens: providers commonly invalidate rotated
|
|
refresh tokens, so replaying old versions can make recovery less deterministic.
|
|
|
|
## Recovery requiring a person
|
|
|
|
If both local state and the latest Vault copy fail, the refresh token was revoked,
|
|
invalidated, or the Enterprise session requires reauthorization. Run the login as
|
|
the affected OS user, then rerun the service:
|
|
|
|
```bash
|
|
claude auth login --claudeai --sso --email <enterprise-email>
|
|
systemctl start claude-auth-sync@$(id -un).service
|
|
```
|
|
|
|
If the scoped Vault token expired or drift protection rejected it, rerun the root
|
|
provisioner with an admin Vault token after confirming the matching policy exists:
|
|
|
|
```bash
|
|
export VAULT_ADDR=https://vault.viktorbarzin.me
|
|
export VAULT_TOKEN="$(cat /home/wizard/.vault-token)"
|
|
sudo --preserve-env=VAULT_ADDR,VAULT_TOKEN /usr/local/bin/t3-provision-users
|
|
```
|
|
|
|
Never copy another user's `.credentials.json` or scoped Vault token. Never restore
|
|
the old shared `CLAUDE_CODE_OAUTH_TOKEN`; environment credentials outrank per-user
|
|
login and would silently collapse all users onto one identity.
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
systemctl list-timers 'claude-auth-sync@*'
|
|
systemctl status claude-auth-sync@<os-user>.service
|
|
journalctl -t claude-auth-sync --since today
|
|
```
|
|
|
|
Inspect Vault metadata, not secret values:
|
|
|
|
```bash
|
|
vault kv metadata get secret/workstation/claude-users/<os-user>
|
|
```
|
|
|
|
Alert `WorkstationClaudeAuthInvalid` fires when any renewal agent logs `FAIL`.
|