Skip to main content

Overview

The Hive credential system provides encrypted storage for API keys, OAuth tokens, and other secrets. Credentials are encrypted at rest using Fernet (AES-128-CBC + HMAC) and can be refreshed automatically via OAuth2 providers.

Architecture

The credential system consists of three main components:

Storage

Encrypted file storage, environment variables, or external vaults

Providers

Lifecycle management for OAuth2 tokens and API key validation

Store

Unified interface with caching and template resolution

Setup

Initialize Credential Store

The quickstart script initializes the credential store automatically. For manual setup:
1

Generate Encryption Key

uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
This generates a base64-encoded 32-byte key for Fernet encryption.
2

Set Environment Variable

export HIVE_CREDENTIAL_KEY="your-generated-key-here"

# Add to shell config for persistence
echo 'export HIVE_CREDENTIAL_KEY="your-key"' >> ~/.bashrc
3

Create Directory Structure

mkdir -p ~/.hive/credentials/credentials
mkdir -p ~/.hive/credentials/metadata
echo '{"credentials": {}, "version": "1.0"}' > ~/.hive/credentials/metadata/index.json

Storage Backends

Encrypted file storage provides secure at-rest encryption with local caching.
from framework.credentials.storage import EncryptedFileStorage
from framework.credentials.store import CredentialStore

# Create store with encrypted file storage
store = CredentialStore.with_encrypted_storage(
    base_path="~/.hive/credentials"
)
Directory structure:
~/.hive/credentials/
├── credentials/
│   ├── github_oauth.enc    # Encrypted credential files
│   ├── slack_oauth.enc
│   └── brave_search.enc
└── metadata/
    └── index.json          # Unencrypted metadata index

Environment Variable Storage

Read credentials from environment variables (read-only).
from framework.credentials.storage import EnvVarStorage
from framework.credentials.store import CredentialStore

# Map credential IDs to env vars
store = CredentialStore.with_env_storage(
    env_mapping={
        "brave_search": "BRAVE_SEARCH_API_KEY",
        "github": "GITHUB_TOKEN",
    }
)

Composite Storage

Layer multiple storage backends with fallback:
from framework.credentials.storage import (
    EncryptedFileStorage,
    EnvVarStorage,
    CompositeStorage
)
from framework.credentials.store import CredentialStore

# Primary: encrypted files, Fallback: env vars
storage = CompositeStorage(
    primary=EncryptedFileStorage("~/.hive/credentials"),
    fallbacks=[EnvVarStorage()]
)

store = CredentialStore(storage=storage)

Credential Types

API Key

Simple static API keys.
from framework.credentials.models import CredentialObject, CredentialKey, CredentialType
from pydantic import SecretStr

# Create API key credential
credential = CredentialObject(
    id="brave_search",
    credential_type=CredentialType.API_KEY,
    keys={
        "api_key": CredentialKey(
            name="api_key",
            value=SecretStr("your-api-key-here")
        )
    },
    description="Brave Search API key"
)

# Save to store
store.save_credential(credential)

OAuth2 Token

OAuth2 access tokens with automatic refresh.
from datetime import datetime, timedelta, UTC

credential = CredentialObject(
    id="github_oauth",
    credential_type=CredentialType.OAUTH2,
    keys={
        "access_token": CredentialKey(
            name="access_token",
            value=SecretStr("ghp_xxxxxxxxx")
        ),
        "refresh_token": CredentialKey(
            name="refresh_token",
            value=SecretStr("ghr_xxxxxxxxx")
        )
    },
    auto_refresh=True,
    expires_at=datetime.now(UTC) + timedelta(hours=1),
    provider_id="oauth2",
    description="GitHub OAuth token"
)

store.save_credential(credential)

Username/Password

Basic auth credentials.
credential = CredentialObject(
    id="postgres_db",
    credential_type=CredentialType.USERNAME_PASSWORD,
    keys={
        "username": CredentialKey(name="username", value=SecretStr("admin")),
        "password": CredentialKey(name="password", value=SecretStr("secret123"))
    },
    description="PostgreSQL database credentials"
)

store.save_credential(credential)

Using Credentials

Get Credential

# Get full credential object
credential = store.get_credential("github_oauth")
if credential:
    access_token = credential.get_key("access_token")
    print(f"Token: {access_token}")

# Convenience method for single key
api_key = store.get_key("brave_search", "api_key")

# Legacy compatibility (returns primary key)
token = store.get("github_oauth")  # Returns access_token

Template Resolution

Resolve credential templates in strings:
# Resolve in string
url = store.resolve("https://api.example.com?key={{brave_search.api_key}}")

# Resolve in headers
headers = store.resolve_headers({
    "Authorization": "Bearer {{github_oauth.access_token}}"
})
# Returns: {"Authorization": "Bearer ghp_xxx"}

# Resolve in query params
params = store.resolve_params({
    "api_key": "{{brave_search.api_key}}"
})

Register Usage Specs

Define how tools use credentials:
from framework.credentials.models import CredentialUsageSpec

# Register usage spec
store.register_usage(CredentialUsageSpec(
    credential_id="brave_search",
    required_keys=["api_key"],
    headers={"X-Subscription-Token": "{{brave_search.api_key}}"},
    description="Brave Search API authentication"
))

# Get resolved request kwargs
kwargs = store.resolve_for_usage("brave_search")
# Returns: {"headers": {"X-Subscription-Token": "actual-key"}}

OAuth2 Integration

The framework supports OAuth2 with automatic token refresh.

Setup OAuth2 Provider

from framework.credentials.oauth2 import OAuth2Provider

# Create OAuth2 provider
oauth_provider = OAuth2Provider(
    client_id="your-client-id",
    client_secret="your-client-secret",
    token_url="https://oauth.example.com/token"
)

# Register with store
store.register_provider(oauth_provider)

Automatic Token Refresh

Tokens are refreshed automatically on access:
# Token is auto-refreshed if expired
credential = store.get_credential("github_oauth", refresh_if_needed=True)

# Manual refresh
refreshed = store.refresh_credential("github_oauth")

Aden Server Sync

Sync credentials from Aden authentication server:
# Create store with Aden sync
store = CredentialStore.with_aden_sync(
    base_url="https://api.adenhq.com",
    cache_ttl_seconds=300,
    auto_sync=True
)

# Requires ADEN_API_KEY environment variable
# Falls back to local-only storage if not set

Credential Management

List Credentials

# List all credential IDs
all_creds = store.list_credentials()
print(f"Credentials: {all_creds}")

# List accounts for a provider
accounts = store.list_accounts("google")
for account in accounts:
    print(f"{account['alias']}: {account['identity']['email']}")

Find by Alias

# Get credential by provider and alias
cred = store.get_credential_by_alias("google", "work")
if cred:
    print(f"Found: {cred.identity.email}")

Validate Credentials

# Validate single credential
is_valid = store.validate_credential("github_oauth")

# Validate against usage spec
errors = store.validate_for_usage("brave_search")
if errors:
    print(f"Validation errors: {errors}")

# Validate all registered usage specs
all_errors = store.validate_all()
for cred_id, errors in all_errors.items():
    print(f"{cred_id}: {errors}")

Delete Credentials

# Delete credential
success = store.delete_credential("old_api_key")
if success:
    print("Credential deleted")

Security Best Practices

  • Never commit HIVE_CREDENTIAL_KEY to version control
  • Store key in a secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • Rotate encryption keys periodically
  • Use different keys for dev/staging/prod
  • Back up the key securely (losing it means losing all credentials)
  • Use encrypted file storage for production
  • Set restrictive file permissions: chmod 600 ~/.hive/credentials/credentials/*
  • Enable full-disk encryption on the server
  • Use encrypted volumes in Docker/Kubernetes
  • Never log credential values
  • Use scoped tokens with minimal permissions
  • Set expiration dates on tokens when possible
  • Rotate API keys regularly
  • Monitor API usage for anomalies
  • Revoke compromised keys immediately
  • Store refresh tokens securely
  • Implement token refresh error handling
  • Set short TTLs on access tokens
  • Use PKCE (Proof Key for Code Exchange) when available
  • Validate token scopes before use

Testing

Create a test credential store:
# In-memory store for testing
test_store = CredentialStore.for_testing({
    "brave_search": {"api_key": "test-brave-key"},
    "github_oauth": {
        "access_token": "test-token",
        "refresh_token": "test-refresh"
    }
})

# Use in tests
api_key = test_store.get_key("brave_search", "api_key")
assert api_key == "test-brave-key"

Troubleshooting

Error: Failed to decrypt credential 'xxx': ...Causes:
  • HIVE_CREDENTIAL_KEY not set or incorrect
  • Credential encrypted with different key
  • Corrupted credential file
Solution:
# Verify key is set
echo $HIVE_CREDENTIAL_KEY

# If key changed, re-encrypt all credentials
# (requires original key to decrypt first)
Error: Credential 'xxx' not foundSolution:
# Check if exists
exists = store.exists("credential_id")
print(f"Exists: {exists}")

# List all credentials
all_creds = store.list_credentials()
print(f"Available: {all_creds}")
Error: Failed to refresh credential 'xxx': ...Causes:
  • Refresh token expired
  • OAuth2 provider unreachable
  • Invalid client credentials
Solution:
  • Re-authenticate with the OAuth2 provider
  • Check provider status page
  • Verify client_id and client_secret

Next Steps

Self-Hosting

Set up your own Hive instance

LLM Providers

Configure LLM provider credentials

Build docs developers (and LLMs) love