Guide

API Key Rotation, Audit Logging, and Credential Management

Automated email workflows handle sensitive data. This guide covers the operational security practices needed to run Nylas CLI in production: API key rotation without downtime, audit logging that satisfies SOC 2, credential storage best practices, data handling policies, and permission scoping. Works with Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP.

By Prem Keshari

Where Nylas CLI stores credentials

Nylas CLI stores API keys and OAuth grant tokens in ~/.nylas/config.json. The file is created with 0600 permissions (read/write for the current user only). Verify:

# Check config file permissions
ls -la ~/.nylas/config.json
# Expected: -rw------- 1 youruser yourgroup ... config.json

# Fix permissions if needed
chmod 600 ~/.nylas/config.json

# View current auth (never displays full key)
nylas auth whoami

In CI/CD environments, always use environment variables instead of config files:

# CI/CD: pass API key via environment variable
export NYLAS_API_KEY="$NYLAS_API_KEY_SECRET"
nylas auth config --api-key "$NYLAS_API_KEY"
nylas auth whoami

Rotate API keys without downtime

According to NIST SP 800-57, cryptographic keys should be rotated at least every 90 days. Nylas supports concurrent active keys during the rotation window:

#!/bin/bash
# rotate-key.sh — zero-downtime API key rotation

# Step 1: Generate new key in Nylas dashboard
# Step 2: Update CLI config
nylas auth config --api-key "$NEW_API_KEY"

# Step 3: Verify
if nylas auth whoami > /dev/null 2>&1; then
  echo "New key verified"
else
  echo "ERROR: rolling back"
  nylas auth config --api-key "$OLD_API_KEY"
  exit 1
fi

# Step 4: Test read operation
if nylas email list --limit 1 --json > /dev/null 2>&1; then
  echo "Read confirmed with new key"
else
  echo "ERROR: rolling back"
  nylas auth config --api-key "$OLD_API_KEY"
  exit 1
fi

echo "Rotation complete. Revoke old key in dashboard."

Build an audit trail for SOC 2

SOC 2 Type II requires an audit trail of all access to sensitive data. Log every operation with metadata but never log email content or PII:

#!/usr/bin/env python3
"""Audit-logged Nylas CLI wrapper."""
import json, subprocess, os, datetime

AUDIT_LOG = os.path.expanduser("~/.nylas/audit.log")

def nylas_audited(args: list[str]) -> subprocess.CompletedProcess:
    result = subprocess.run(["nylas"] + args, capture_output=True, text=True)
    # Log metadata only — no email content or PII
    entry = {
        "timestamp": datetime.datetime.utcnow().isoformat() + "Z",
        "user": os.getenv("USER", "unknown"),
        "command": " ".join(args),
        "exit_code": result.returncode,
        "hostname": os.uname().nodename,
    }
    with open(AUDIT_LOG, "a") as f:
        f.write(json.dumps(entry) + "\n")
    return result

result = nylas_audited(["email", "list", "--limit", "10", "--json"])
messages = json.loads(result.stdout)
print(f"Read {len(messages)} messages (logged to audit trail)")

Scope permissions with minimum-privilege grants

Create separate grants for different use cases. A monitoring script shouldn’t have send permissions:

# List active grants
nylas auth list

# Check scopes for current grant
nylas auth whoami --json | jq '.scopes'

# Revoke a grant when no longer needed
nylas auth logout --grant-id <grant-id>

Data handling policies

  • Never log email bodies, subjects, or sender addresses. Log message IDs and counts only.
  • Sanitize before piping to external services. Strip PII before sending to LLMs, analytics, or logging.
  • Use temporary files with restricted permissions. mktemp + chmod 600 + delete after processing.
  • Don’t store email content in version control. Add output files to .gitignore.
# Safe: process without persisting
EMAILS=$(nylas email list --json --limit 10)
echo "Processed $(echo "$EMAILS" | jq 'length') messages"

# If temp files needed, use restrictive permissions
TMPFILE=$(mktemp /tmp/nylas-XXXXXX.json)
chmod 600 "$TMPFILE"
nylas email list --json --limit 10 > "$TMPFILE"
# ... process ...
rm -f "$TMPFILE"

CI/CD security patterns

# GitHub Actions example
name: Email Report
on:
  schedule:
    - cron: '0 9 * * 1'
jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - name: Install Nylas CLI
        run: curl -fsSL https://cli.nylas.com/install.sh | bash
      - name: Configure auth
        run: nylas auth config --api-key "$NYLAS_API_KEY"
        env:
          NYLAS_API_KEY: ${{ secrets.NYLAS_API_KEY }}
      - name: Generate report (no email content in logs)
        run: |
          COUNT=$(nylas email list --json --limit 100 | jq 'length')
          echo "Inbox: $COUNT recent messages"

SOC 2 compliance checklist

RequirementImplementation
Access controlPer-user API keys, minimum-privilege scopes
Audit trailLog all operations to tamper-evident file
Key rotationEvery 90 days with zero-downtime overlap
Credential storageConfig at 0600 permissions, env vars in CI/CD
Data minimizationNever log email content or PII
Encryption in transitAll API calls use TLS 1.2+
Incident responseRevoke grants immediately on breach

Next steps