Fast, secure Macaroon library for Python 3.8+ with optional Rust acceleration
Project description
PyMacaroons2
⚡ Fast, secure Macaroons for modern Python 3.8+
Hard fork of the unmaintained pymacaroons with security fixes, performance improvements, and modern Python support.
✨ Features
- 🔒 Security fixes - Constant-time comparison, fixed base64 bugs
- 🚀 Optional Rust acceleration - 6-7x faster HMAC operations
- 📦 Modern packaging -
pyproject.toml, nosetup.py - 🔄 Async support -
AsyncVerifierfor async/await workflows - 🎯 Memory optimized -
__slots__on all classes (~40% memory reduction) - 🐍 Python 3.8+ - Drops Python 2 support for cleaner code
📦 Installation
pip install pymacaroons2
Optional: Enable Rust acceleration
For maximum performance, install with Rust extension:
pip install pymacaroons2[rust]
Or build from source:
cd src/pymacaroons2_rs
maturin develop --release
🚀 Quick Start
Creating a Macaroon
from pymacaroons2 import Macaroon, Verifier
# Create a macaroon
m = Macaroon(
location='https://api.example.com',
identifier='user-12345',
key=b'super-secret-key'
)
# Add caveats (restrictions)
m.add_first_party_caveat('action = read')
m.add_first_party_caveat('time < 2024-12-31T23:59:59Z')
# Serialize for transmission
token = m.serialize()
print(f"Token: {token}")
Verifying a Macaroon
from pymacaroons2 import Macaroon, Verifier
# Deserialize the token
m = Macaroon.deserialize(token)
# Create verifier
v = Verifier()
v.satisfy_exact('action = read')
v.satisfy_general(lambda c: c.startswith('time < '))
# Verify with the secret key
try:
verified = v.verify(m, b'super-secret-key')
print("✅ Macaroon verified!")
except Exception as e:
print(f"❌ Verification failed: {e}")
Async Verification
import asyncio
from pymacaroons2 import Macaroon
from pymacaroons2.async_verifier import AsyncVerifier
async def verify_async():
m = Macaroon(
location='https://api.example.com',
identifier='user-12345',
key=b'super-secret-key'
)
v = AsyncVerifier()
await v.verify_async(m, b'super-secret-key')
print("✅ Async verification complete!")
asyncio.run(verify_async())
🔄 Migration from pymacaroons
Package rename
# Before (pymacaroons)
from pymacaroons import Macaroon, Verifier
# After (pymacaroons2)
from pymacaroons2 import Macaroon, Verifier
Breaking changes
- Python 3.8+ required - Python 2 and older Python 3 versions are no longer supported
- Package renamed -
pymacaroons→pymacaroons2 libnaclreplaced withpynacl- For third-party caveats, installpynacl
See CHANGELOG.md for complete list of changes.
⚡ Performance
With the optional Rust extension enabled:
| Operation | Python | Rust | Speedup |
|---|---|---|---|
| HMAC-SHA256 | 0.12s | 0.02s | 6.4x |
| Key Derivation | 0.11s | 0.015s | 7.5x |
| Constant-Time Compare | 0.0075s | 0.005s | 1.4x |
Benchmarks run with 50,000 iterations on Python 3.12
📚 Documentation
Macaroon versions
from pymacaroons2 import Macaroon, MACAROON_V1, MACAROON_V2
# V1 format (default, more compatible)
m1 = Macaroon(location='...', identifier='...', key=b'...', version=MACAROON_V1)
# V2 format (more compact, binary identifiers)
m2 = Macaroon(location='...', identifier=b'\x00\x01\x02', key=b'...', version=MACAROON_V2)
Serialization formats
from pymacaroons2.serializers import JsonSerializer, BinarySerializer
# Binary (default, URL-safe base64)
token = m.serialize()
# JSON
token = m.serialize(serializer=JsonSerializer())
# Deserialize
m = Macaroon.deserialize(token)
m = Macaroon.deserialize(json_token, serializer=JsonSerializer())
Third-party caveats
# Requires: pip install pynacl
# Add third-party caveat
m.add_third_party_caveat(
location='https://auth.example.com',
key=b'shared-secret-with-auth-service',
key_id='caveat-id-12345'
)
# Create discharge macaroon (at auth service)
discharge = Macaroon(
location='https://auth.example.com',
key=b'shared-secret-with-auth-service',
identifier='caveat-id-12345'
)
# Bind discharge to original macaroon
bound = m.prepare_for_request(discharge)
# Verify with discharge
v = Verifier(discharge_macaroons=[bound])
v.verify(m, b'original-key')
🔐 Security
This fork addresses several security issues in the original library:
- Timing attack vulnerability - Now uses
secrets.compare_digest()(or Rustsubtlecrate) for constant-time comparison - Base64 decoding bug - Fixed logic error that could cause incorrect decoding
- Updated dependencies - Uses modern
cryptographylibrary instead of deprecatedhashlibfor HMAC
🛠️ Development
# Clone repository
git clone https://github.com/TazakiN/pymacaroons2.git
cd pymacaroons2
# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Build Rust extension (optional)
cd src/pymacaroons2_rs
maturin develop --release
📝 License
MIT License - see LICENSE for details.
Original work Copyright (c) 2014-2018 Evan Cordell
Modified work Copyright (c) 2024 Tazkia Nizami
🙏 Credits
- Evan Cordell - Original pymacaroons author
- Macaroons paper - Original research by Google
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 pymacaroons2-2.0.0.tar.gz.
File metadata
- Download URL: pymacaroons2-2.0.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f69cc4a37a240adfa5806c76a881a45a4a5c78a46fe5c32739315e0dd646ba3
|
|
| MD5 |
f63b9e2777dd416f65661bb26a0f5a3d
|
|
| BLAKE2b-256 |
67ac8c3e2a926a9ce617629b00cf1f8a57b76f34c78743dd5dcf56642ad95b65
|
File details
Details for the file pymacaroons2-2.0.0-py2.py3-none-any.whl.
File metadata
- Download URL: pymacaroons2-2.0.0-py2.py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
677911f112b87b36fa1a3f5d3c1a1482236e91dbd203811c345e220e88b88a69
|
|
| MD5 |
6e367b9da76c555d25cdc3558ce1c063
|
|
| BLAKE2b-256 |
6ecda76b2a50e0b5b70471932a9556a099a4c28be91895a52f8d8bfa8120586c
|