How Luci authenticates with external services: OAuth flows, API keys, SSH keys, credential storage, and token refresh patterns.
/home/lucienne/workspace/scripts/graph_api.py8581071e-c8ea-4f51-88fa-64681082c5a6 (Azure AD registered app)https://login.microsoftonline.com/common/oauth2/v2.0offline_access (for refresh tokens)Mail.ReadWrite, Mail.SendCalendars.ReadWrite, Contacts.ReadWriteFiles.ReadWrite.All (OneDrive/SharePoint)MailboxSettings.ReadWrite, Notes.ReadWrite.AllTasks.ReadWrite, Team.ReadBasic.All, User.Read~/.graph-api-token.json (access token + refresh token + expiry timestamp)~/.graph-api-token-personal.json~/.cli-m365-msal.json (old m365 CLI cache) automaticallyLogin sequence:
1. python graph_api.py login requests a device code from Azure AD
2. User visits https://microsoft.com/devicelogin and enters the code
3. Script polls the token endpoint until user authenticates
4. Access token + refresh token cached to ~/.graph-api-token.json
gws (Node.js, installed at ~/.npm-global/bin/gws)~/.config/gws/credentials.json (OAuth tokens)~/.config/gws/client_secret.json (OAuth client configuration)/home/lucienne/workspace/scripts/gdrive_helper.py wraps gws for Drive file operations/home/lucienne/workspace/scripts/auth_portal.pyhttp://100.118.207.3:8788)All API keys are stored as environment variables on the server and documented in ~/.claude/vault/secrets/api-keys.md. The master reference with full per-project breakdown lives in SecondBrain.
Services with API keys:
| Service | Env Var | Auth Method |
|---|---|---|
| Google Gemini | GEMINI_API_KEY |
API key (free tier) |
| Google Gemini (paid) | GEMINI_API_KEY_PAID |
API key (Tier 2 Postpay) |
| Anthropic | ANTHROPIC_API_KEY |
API key |
| OpenAI/Codex | OPENAI_API_KEY |
CLI only (OAuth) |
| Brave Search | BRAVE_API_KEY |
API key (MCP server) |
| Tavily | TAVILY_API_KEY |
API key (MCP server) |
| WebScrapingAPI | WEBSCRAPINGAPI_KEY |
API key |
| Hetzner Cloud | HETZNER_API_TOKEN |
API token |
| Linear | Static token | API token |
| Asana | Static token | Personal access token |
| Notion | Static token | Integration token |
| Make.com | Webhook URL | No auth (URL is the secret) |
| Fireflies.ai | Static token | GraphQL API key |
| Home Assistant | Static token | Long-lived access token |
Key patterns:
- One Anthropic key shared across projects
- Separate OpenAI/Gemini keys per project
- 4 GitHub PATs -- Mission Control PAT (ghp_Kjhq...) is the active one for Luci
- Luci uses MC PAT via ~/.git-credentials (credential store) for all HTTPS git push
SSH keys are stored at ~/.claude/vault/secrets/ssh/:
- id_ed25519 / id_ed25519.pub -- primary Ed25519 keypair
- echo-key.pem -- PEM key for Echo server access
- config -- SSH client configuration
- README.md -- documentation
Infrastructure connectivity:
- Luci (Hetzner): lucienne@100.118.207.3 (Tailscale IP)
- SSH config and network topology documented in ~/.claude/vault/infrastructure/
| Location | Contents |
|---|---|
~/.claude/vault/secrets/api-keys.md |
Quick reference of all API keys |
~/.claude/vault/secrets/api_keys.env |
Environment variable exports |
~/.claude/vault/secrets/passwords.md |
POPIA document passwords (SA financial institutions) |
~/.claude/vault/secrets/ssh/ |
SSH keys and config |
~/.claude/vault/secrets/ha-credentials.env |
Home Assistant credentials |
~/.claude/vault/secrets/spotify-credentials.env |
Spotify API credentials |
~/.graph-api-token.json |
M365 work OAuth token cache |
~/.graph-api-token-personal.json |
M365 personal OAuth token cache |
~/.config/gws/credentials.json |
Google Workspace OAuth tokens |
~/.config/gws/client_secret.json |
Google OAuth client config |
~/.dropbox-api-token.json |
Dropbox API token |
~/.git-credentials |
GitHub PAT for git push |
| Environment variables | Runtime API keys (loaded from .bashrc) |
graph_api.py checks expires_on timestamp before every requestpython graph_api.py logingws CLI tool internallygdrive_helper.py has retry logic for transient errors (500, 503, 429) with exponential backoff/home/lucienne/workspace/scripts/oauth_health_check.py~/workspace/data/oauth-health-status.json/home/lucienne/workspace/scripts/search_all.pyhttp://localhost:8788)graph_api.py -- headless-friendly, tokens cached at ~/.graph-api-token.jsongws CLI with OAuth tokens at ~/.config/gws/~/.claude/vault/secrets/api-keys.md, loaded as environment variablesoauth_health_check.py with Telegram alerts on failurelogin only needed when refresh token expires~/.claude/vault/secrets/ssh/ with Ed25519 as primaryMission Control is the board for your delegated work: requests come in, Luci coordinates the next step, and evidence stays visible for review.
Luci is your always-on assistant for routing, status updates, and follow-through. Operators can still open deeper evidence when needed.