Credential governance for AI agents - Python edition.
pip install id-wispera# LangChain support
pip install id-wispera[langchain]
# CrewAI support
pip install id-wispera[crewai]
# All integrations
pip install id-wispera[all]idw-py init# Scan a directory
idw-py scan /path/to/project
# Scan system locations (OpenClaw format)
idw-py scan --system# Scan and import all
idw-py import ./project --all --owner dev@company.com -y
# Import high-confidence only
idw-py import ./project --min-confidence 0.9 --owner dev@company.com
# Import single file
idw-py import .env --owner dev@company.com| Option | Description |
|---|---|
--all |
Import all detected credentials from scan |
--min-confidence <level> |
Minimum confidence threshold (0-1) |
--format <format> |
Import format (env, json, openclaw) |
--owner <owner> |
Human owner email |
--auto-name |
Auto-generate passport names |
-y, --yes |
Import without confirmation |
-p, --path <path> |
Custom vault path |
# List all passports
idw-py list
# Show passport details
idw-py show <passport-id>
# Revoke a passport
idw-py revoke <passport-id> --reason "Compromised"from id_wispera import Vault, create_passport, list_passports
from id_wispera.types import CreatePassportInput, CredentialType, VisaType, Platform
# Load vault
vault = Vault.load("~/.id-wispera/vault.json", passphrase="your-passphrase")
# Create a passport
passport = create_passport(vault, CreatePassportInput(
name="openai-prod",
agent_id="agent-001",
credential_type=CredentialType.API_KEY,
credential_value="sk-...",
visa_type=VisaType.ACCESS,
platforms=[Platform.OPENAI],
scope=["chat", "embeddings"],
human_owner="developer@example.com",
))
# List passports
passports = list_passports(vault, status="active")
for p in passports:
print(f"{p.name}: {p.status}")from id_wispera.detection import detect_credentials, mask_credentials_in_text
# Detect credentials in text
text = "My API key is sk-abc123...xyz789"
results = detect_credentials(text)
for result in results:
print(f"Found {result.type} at line {result.line}")
print(f" Value: {result.value[:10]}...")
print(f" Confidence: {result.confidence}")
# Mask credentials for safe logging
safe_text = mask_credentials_in_text(text)
print(safe_text) # "My API key is [REDACTED]"from id_wispera.policy import evaluate_policy, validate_passport
# Evaluate whether a passport is allowed to perform an action
result = evaluate_policy(passport, action="access")
print(f"Allowed: {result.allowed}, Reason: {result.reason}")
# Validate a passport against all configured policies
validation = validate_passport(passport)
print(f"Valid: {validation.valid}, Violations: {validation.violations}")from id_wispera.delegation import add_delegation, get_delegation_depth
# Add a delegation hop to a passport
delegated = add_delegation(vault, passport_id, hop, issued_by="admin")
print(f"Delegated passport: {delegated.id}")
# Check delegation chain depth
depth = get_delegation_depth(vault, passport_id)
print(f"Delegation depth: {depth}")from id_wispera.sharing import create_share_link, resolve_share_link
# Create a share link with expiry and view limits
link = create_share_link(vault, passport_id, expires_in=3600, max_views=1)
print(f"Share URL: {link.url}")
# Resolve a share link to retrieve the passport
shared = resolve_share_link(vault, link.token)
print(f"Shared passport: {shared.name}")from id_wispera.locations import detect_installed_providers, get_provider
# Detect which credential providers are available on the system
providers = detect_installed_providers()
for p in providers:
print(f"Provider: {p.name} ({p.provider_type})")
# Get a specific provider by name
provider = get_provider("aws")
print(f"Provider: {provider.name}, Installed: {provider.installed}")from id_wispera.provisioning import provision_and_create_passport, list_providers
# List available provisioning providers
providers = list_providers()
for p in providers:
print(f"{p.name}: {p.description}")
# Provision a new credential and create a passport in one step
passport = provision_and_create_passport(vault, request, auth)
print(f"Provisioned: {passport.name} on {passport.platforms}")from id_wispera.integrations.langchain import WisperaCredentialProvider
from langchain_openai import ChatOpenAI
# Initialize provider (authenticates via session token or OS keychain automatically)
provider = WisperaCredentialProvider(vault_path="~/.id-wispera")
# Use with LangChain
llm = ChatOpenAI(api_key=provider.get("openai-prod"))
# Or use convenience methods
llm = ChatOpenAI(api_key=provider.get_openai_key())Deprecated: The
passphraseparameter in theWisperaCredentialProviderconstructor is deprecated. Authentication is now resolved automatically viaIDW_SESSION_TOKENor OS keychain. Runidw auth loginbefore first use.
from id_wispera.integrations.crewai import WisperaSecretManager, WisperaToolCredentials
from crewai import Agent, Task, Crew
# Initialize secret manager (authenticates via session token or OS keychain)
secrets = WisperaSecretManager()
# Create agent with governed credentials
researcher = Agent(
role="Research Analyst",
goal="Research and analyze information",
llm_config=secrets.get_llm_config("anthropic-research", model="claude-3-5-sonnet-20241022"),
)
# Use tool credentials — retrieve via creds.get() instead of os.environ injection
from crewai_tools import SerperDevTool
creds = WisperaToolCredentials(secrets, "serper")
search_tool = SerperDevTool(api_key=creds.get())Deprecated: The
passphraseparameter in theWisperaSecretManagerconstructor is deprecated. Authentication is now resolved automatically viaIDW_SESSION_TOKENor OS keychain.Breaking change:
WisperaToolCredentialsno longer injects credentials intoos.environ. Usecreds.get()to retrieve the credential value directly.
from id_wispera.integrations.openai_agents import WisperaOpenAIAgentProvider
provider = WisperaOpenAIAgentProvider()
# Get API key for agent initialization
api_key = provider.get_agent_key("openai-prod")
# Get full agent config (api_key, model, provider)
config = provider.get_agent_config("openai-prod", model="gpt-4")
# Get tool authentication headers
tool_auth = provider.get_tool_auth("serper-api")
# Returns: {"tool": "serper-api", "credential": "...", "header_name": "Authorization", "header_template": "Bearer ..."}
# Scoped handoff credentials
cred = provider.get_handoff_credential("openai-prod", target_agent="research-agent", allowed_scopes=["read"])
# Batch tool credentials
creds = provider.get_tool_credentials({"search": "serper-api", "weather": "weather-api"})from id_wispera.integrations.google_a2a import WisperaA2AProvider
provider = WisperaA2AProvider()
# Populate an Agent Card with credentials
creds = provider.get_agent_credentials("my-agent")
# Returns: {"auth_token": "...", "agent_id": "...", "scopes": [...], "expires_at": "..."}
# Validate incoming agent authentication
result = provider.validate_agent_auth(token="...", expected_agent_id="agent-123")
# Returns: {"valid": True, "agent_id": "agent-123"}
# Task-scoped credential access
task_creds = provider.get_task_credentials("task-456", required_scopes=["read"], passport_names=["my-agent"])from id_wispera.integrations.slack import WisperaSlackProvider
provider = WisperaSlackProvider()
# Individual tokens
bot_token = provider.get_bot_token("slack-bot") # xoxb-...
app_token = provider.get_app_token("slack-app") # xapp-...
user_token = provider.get_user_token("slack-user") # xoxp-...
webhook_url = provider.get_webhook_url("slack-webhook")
# Typed credential with auto-detection
cred = provider.get_slack_credential("slack-bot")
# Returns: {"value": "xoxb-...", "token_type": "bot", "team_id": "T12345"}
# Socket Mode (bot + app tokens together)
tokens = provider.get_socket_mode_tokens("slack-bot", "slack-app")
# Returns: {"bot_token": "xoxb-...", "app_token": "xapp-..."}
# List all Slack credentials in the vault
names = provider.list_slack_credentials()The id_wispera.auth module provides the zero-plaintext credential architecture for Python:
from id_wispera.auth import PassphraseProvider, SessionTokenManager, KeychainProvider
# PassphraseProvider — derive vault key from passphrase (interactive login)
pp = PassphraseProvider()
vault_key = pp.derive_key(passphrase)
# KeychainProvider — cache/retrieve vault key from OS keychain
kc = KeychainProvider()
kc.store(vault_key)
cached = kc.retrieve()
# SessionTokenManager — create, validate, revoke scoped session tokens
stm = SessionTokenManager(vault)
token = stm.create(name="ci-deploy", scope=["read", "list"], ttl="24h")
session = stm.validate(token)
stm.revoke(token.id)
tokens = stm.list()| Class | Purpose |
|---|---|
PassphraseProvider |
Derive vault key from passphrase (interactive login) |
SessionTokenManager |
Create / validate / revoke / list scoped session tokens |
KeychainProvider |
Cache vault key in the OS keychain for session persistence |
| Variable | Description | Default |
|---|---|---|
IDW_SESSION_TOKEN |
Scoped session token (recommended for headless/CI) | |
IDW_VAULT_PATH |
Vault directory path | ~/.id-wispera |
IDW_PASSPHRASE |
Vault passphrase | Deprecated -- use idw auth login or IDW_SESSION_TOKEN |
The Python SDK uses the same vault format as the TypeScript SDK. Vaults are interoperable:
- AES-256-GCM encryption
- Scrypt key derivation (N=16384, r=8, p=1)
- JSON storage format
# Install in development mode
pip install -e ".[dev]"
# Run tests
pytest
# Type checking
mypy id_wisperaMIT