---
name: credential-handling
description: No hardcoded credentials; use SOPS vault or env vars; JWT auth; Argon2 hashing; log auth attempts
applies-to: all
---

# Credential Handling

## Core rules

- **Never hardcode credentials** — no passwords, tokens, API keys, or connection strings in any source file, script, or config file that is committed to git
- **Use SOPS vault** for all secrets in this repo — access via the ClaudeTools vault wrapper:
  ```bash
  VAULT="$CLAUDETOOLS_ROOT/.claude/scripts/vault.sh"
  bash "$VAULT" get-field <path> <field>
  bash "$VAULT" get <path>
  bash "$VAULT" search "keyword"
  ```
- **Use environment variables** as an alternative when SOPS is impractical (e.g., Docker, CI). Never put the env var value in a committed file.
- **`.env` files are gitignored** and must never be committed. Verify before staging any `.env` file.

## Vault path structure

```
infrastructure/     — servers, services, SSH keys
clients/            — per-client credentials
services/           — third-party APIs (Syncro, etc.)
projects/           — project-specific secrets (GuruRMM DB, etc.)
msp-tools/          — MSP app suite tokens
```

The vault wrapper reads `vault_path` from `.claude/identity.json` (per-machine, gitignored). Every machine sets its own vault path there — no hardcoded vault paths in any shared file.

## API authentication

- **JWT tokens** for all ClaudeTools API authentication
- **Argon2** for password hashing (not bcrypt, not MD5, not SHA-256 plain)
- Log all authentication attempts and sensitive operations — failures must be logged with timestamp, IP, and identity attempted

## What not to commit

Never commit:
- `.env` files
- `credentials.json`, `*.pem`, `*.p12`, `*.pfx`
- Any file matching `*secret*`, `*password*`, `*token*` unless it is a SOPS-encrypted `.sops.yaml`
- Vault YAML files before encryption (plaintext SOPS files)
- SSH private keys

## Accessing secrets in scripts

```bash
# Correct — vault wrapper
PASSWORD=$(bash "$VAULT" get-field projects/claudetools/database.sops.yaml credentials.password)

# Correct — environment variable (set externally, not hardcoded)
psql "postgres://${DB_USER}:${DB_PASS}@localhost:5432/gururmm"

# WRONG — hardcoded inline (caught in code review)
psql "postgres://gururmm:43617ebf7eb242e814ca9988cc4df5ad@localhost:5432/gururmm"
```

## 1Password fallback

The 1Password service account token is in `infrastructure/1password-service-account.sops.yaml`. Use 1Password as a secondary vault for secrets that need to be accessed outside the SOPS workflow.
