macOS Keychain Password Manager - CLI tool and Python library with decorator support
Project description
kcpwd
Keychain Password Manager CLI & Library - A simple, secure password manager for macOS that uses the native macOS Keychain. Can be used as both a command-line tool and a Python library.
Features
- Secure storage using macOS Keychain
- Automatic clipboard copying
- Cryptographically secure password generation
- Simple CLI interface
- Python library for programmatic access
- Decorator support for automatic password injection
- No passwords stored in plain text
- Native macOS integration
Installation
From PyPI
pip install kcpwd
From Source
git clone https://github.com/osmanuygar/kcpwd.git
cd kcpwd
pip install -e .
Usage
CLI Usage
Store a password
kcpwd set dbadmin asd123
Retrieve a password (copies to clipboard)
kcpwd get dbadmin
Delete a password
kcpwd delete dbadmin
Generate a secure password
# Generate a 16-character password (default)
kcpwd generate
# Generate a 20-character password
kcpwd generate -l 20
# Generate without symbols (alphanumeric only)
kcpwd generate --no-symbols
# Generate and save immediately
kcpwd generate -s myapi
# Generate a 6-digit PIN
kcpwd generate -l 6 --no-uppercase --no-lowercase --no-symbols
# Generate without ambiguous characters (no 0/O, 1/l/I)
kcpwd generate --exclude-ambiguous
List stored keys
kcpwd list
Library Usage
Basic Functions
from kcpwd import set_password, get_password, delete_password
# Store a password
set_password("my_database", "secret123")
# Retrieve a password
password = get_password("my_database")
print(password) # Output: secret123
# Retrieve and copy to clipboard
password = get_password("my_database", copy_to_clip=True)
# Delete a password
delete_password("my_database")
from kcpwd import set_password, get_password, delete_password, generate_password
# Generate a secure password
password = generate_password(length=20)
print(password) # Output: 'aB3#xK9!mL2$nP5@qR7&'
# Generate alphanumeric password (no symbols)
password = generate_password(length=16, use_symbols=False)
print(password) # Output: 'aB3xK9mL2nP5qR7t'
# Generate a 6-digit PIN
pin = generate_password(
length=6,
use_uppercase=False,
use_lowercase=False,
use_symbols=False
)
print(pin) # Output: '384729'
# Generate and store
password = generate_password(length=20)
set_password("my_database", password)
# Retrieve a password
password = get_password("my_database")
print(password) # Output: the stored password
# Retrieve and copy to clipboard
password = get_password("my_database", copy_to_clip=True)
# Delete a password
delete_password("my_database")
Using Decorators (Recommended!)
The @require_password decorator automatically injects passwords from keychain:
from kcpwd import require_password, set_password
# First, store your password
set_password("my_db", "secret123")
# Use the decorator to auto-inject password
@require_password('my_db')
def connect_to_database(host, username, password=None):
print(f"Connecting to {host} as {username}")
print(f"Password: {password}")
# Your database connection code here
return f"Connected with password: {password}"
# Call without password - it's automatically retrieved!
result = connect_to_database("localhost", "admin")
# Output: Connected with password: secret123
Advanced Decorator Usage
You can specify different parameter names:
from kcpwd import require_password, set_password
# Store API key
set_password("github_api", "ghp_xxxxxxxxxxxx")
# Inject into custom parameter name
@require_password('github_api', param_name='api_key')
def call_github_api(endpoint, api_key=None):
print(f"Calling GitHub API: {endpoint}")
print(f"Using key: {api_key}")
# Your API call code here
return {"status": "success"}
# API key automatically retrieved from keychain
response = call_github_api("/user/repos")
Real-World Examples
Database Connection:
#import psycopg2
from kcpwd import require_password, set_password
# Setup: Store password once
set_password("prod_db", "my_secure_password")
# Use in your code
@require_password('prod_db')
def get_db_connection(host, user, database, password=None):
return psycopg2.connect(
host=host,
user=user,
password=password,
database=database
)
# No need to handle password manually!
conn = get_db_connection(
host="prod.example.com",
user="dbuser",
database="myapp"
)
API Client:
import requests
from kcpwd import require_password, set_password
# Setup
set_password("api_token", "sk-xxxxxxxxxx")
@require_password('api_token', param_name='token')
def make_api_request(endpoint, token=None):
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"https://api.example.com{endpoint}", headers=headers)
return response.json()
# Token is automatically injected
data = make_api_request("/users")
Email Sender:
import smtplib
from kcpwd import require_password, set_password
# Store email password
set_password("email_password", "your_email_password")
@require_password('email_password')
def send_email(to, subject, body, password=None):
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("your_email@gmail.com", password)
message = f"Subject: {subject}\n\n{body}"
server.sendmail("your_email@gmail.com", to, message)
server.quit()
return "Email sent!"
# Password automatically retrieved
send_email("friend@example.com", "Hello", "How are you?")
How It Works
kcpwd stores your passwords in the macOS Keychain - the same secure, encrypted storage that Safari and other macOS apps use. This means:
- Passwords are encrypted with your Mac's security
- They persist across reboots
- They're protected by your Mac's login password
- No plain text files or databases
- Can be accessed programmatically via Python
Viewing Your Passwords
Open Keychain Access app and search for "kcpwd" to see all stored passwords.
Or use Terminal:
security find-generic-password -s "kcpwd" -a "dbadmin" -w
API Reference
Functions
set_password(key: str, password: str) -> bool
Store a password in macOS Keychain.
- Returns
Trueif successful,Falseotherwise
get_password(key: str, copy_to_clip: bool = False) -> Optional[str]
Retrieve a password from macOS Keychain.
copy_to_clip: IfTrue, also copies password to clipboard- Returns password string if found,
Noneotherwise
delete_password(key: str) -> bool
Delete a password from macOS Keychain.
- Returns
Trueif successful,Falseotherwise
copy_to_clipboard(text: str) -> bool
Copy text to macOS clipboard.
- Returns
Trueif successful,Falseotherwise
generate_password(length=16, use_uppercase=True, use_lowercase=True, use_digits=True, use_symbols=True, exclude_ambiguous=False) -> str
Generate a cryptographically secure random password.
length: Password length (minimum 4)use_uppercase: Include uppercase lettersuse_lowercase: Include lowercase lettersuse_digits: Include digitsuse_symbols: Include symbols (!@#$%^&*...)exclude_ambiguous: Exclude ambiguous characters (0/O, 1/l/I)- Returns generated password string
Decorators
@require_password(key: str, param_name: str = 'password')
Decorator that automatically injects password from keychain into function parameter.
key: Keychain key to retrieve password fromparam_name: Parameter name to inject password into (default:'password')- Raises
ValueErrorif password not found in keychain
Security Notes
Important Security Considerations:
- Passwords are stored in macOS Keychain (encrypted)
- Passwords remain in clipboard until you copy something else
- Consider clearing clipboard after use for sensitive passwords
- Designed for personal use on trusted devices
- Always use strong, unique passwords
- Decorator usage means password is in memory during function execution
Requirements
- macOS only (uses native Keychain)
- Python 3.6+ (secrets module built-in from 3.6)
Development
Setup development environment
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install -e .
Run tests
pytest
License
MIT License - See LICENSE file for details
Contributing
Contributions welcome! Please feel free to submit a Pull Request.
Disclaimer
This is a personal password manager tool. While it uses secure storage (macOS Keychain), please use at your own risk. For enterprise or critical password management, consider established solutions like 1Password, Bitwarden, or similar.
Roadmap
- Python library support
- Decorator for automatic password injection
- Password generation
- Import/export functionality
- Master password protection
- Password strength indicator
- Cross-platform support (Linux, Windows)
- GUI web UI application
- Multi Node/user support
- Integration with other password managers
- Two-factor authentication support
- MultiSite password management
Changelog
v0.2.1
- Added cryptographically secure password generation (
generatecommand) - Generate passwords with customizable length and character types
- Option to exclude ambiguous characters (0/O, 1/l/I)
- Generate and save passwords in one command
- Comprehensive password generation tests
v0.2.0
- Added Python library support
- Added
@require_passworddecorator - Refactored code into modular structure
- Enhanced API with better return types
v0.1.0
- Initial CLI release
- Basic password storage and retrieval
- macOS Keychain integration
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kcpwd-0.2.1.tar.gz.
File metadata
- Download URL: kcpwd-0.2.1.tar.gz
- Upload date:
- Size: 14.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dac3a3860004075578f9864d107d04944051ab1ab2bcfc501f8a506f041e5b8d
|
|
| MD5 |
5a12707e566e3c2f915c3306a5e3fcae
|
|
| BLAKE2b-256 |
d3e155668b378b160fd33acab70ad9755957c6e286984cf605ec66a60efe4604
|
File details
Details for the file kcpwd-0.2.1-py3-none-any.whl.
File metadata
- Download URL: kcpwd-0.2.1-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95823e5848fe6993e44b7b4c48ff9b8f0fc8b130e76a41f6844dd53855b95428
|
|
| MD5 |
5db125b91d832710c3fca47db1a24313
|
|
| BLAKE2b-256 |
9b94935807f25cfdda16156117bafd53b2a9262caa225a7f6dfae8c71654737a
|