nkeys (Python)
The `nkeys` Python library, currently at version 0.2.1, provides a public-key signature system built upon Ed25519 cryptography, specifically designed for identity, authentication, and authorization within the NATS ecosystem. It offers utilities for generating, encoding, and managing NATS-compatible key pairs (Operators, Accounts, Users, Servers, Clusters). The library maintains a low-to-moderate release cadence, with recent updates focusing on dependency management and Python version compatibility.
Common errors
-
AttributeError: module 'configparser' has no attribute 'SafeConfigParser'
cause This error typically occurs when the older `ed25519` dependency, which `nkeys` used prior to v0.2.0, attempts to install on Python 3.12 or newer. The `ed25519` library's `versioneer` component has a compatibility issue with `configparser` in newer Python versions.fixUpgrade `nkeys` to version 0.2.0 or higher: `pip install --upgrade nkeys`. This version replaces `ed25519` with `pynacl`, resolving the compatibility issue. -
Failed building wheel for pynacl (or 'error: command 'gcc' failed with exit status 1')
cause The `pynacl` library, a dependency of `nkeys` (since v0.2.0), requires a C compiler (like GCC) and potentially development headers (e.g., `libffi-dev`) to compile its C extensions if a pre-built wheel is not available for your specific Python version and operating system.fixInstall the necessary build tools and development libraries for your operating system. For Debian/Ubuntu: `sudo apt-get update && sudo apt-get install build-essential libffi-dev`. For Alpine Linux (in Docker): `apk add gcc musl-dev libffi-dev`. For other systems, consult `pynacl`'s documentation for prerequisites.
Warnings
- breaking Version 0.2.0 introduced a breaking change by replacing the `ed25519` dependency with `pynacl` to support Python 3.12 and newer versions. Projects relying on `nkeys` might need to update their environments to correctly build `pynacl`.
- gotcha Installing `pynacl` (a core dependency) can sometimes fail in constrained environments (e.g., Docker containers, specific OS builds) if system-level build tools or `libsodium` libraries are not present. This is because `pynacl` is a C extension.
- gotcha NATS NKeys utilize specific prefixes (e.g., 'S' for seed, 'U' for user, 'A' for account, 'O' for operator) encoded into the key string. Misunderstanding or incorrect handling of these prefixes can lead to invalid keys or authentication failures.
Install
-
pip install nkeys
Imports
- nkeys
import nkeys
- SigningKey
from nacl.signing import SigningKey
Quickstart
import nkeys
from nacl.signing import SigningKey
import os
# 1. Generate a raw Ed25519 signing key using PyNaCl
raw_signing_key = SigningKey.generate()
# 2. Encode the raw key as a NATS user seed (e.g., SU...)
# The `encode_seed` function combines the raw private key with the NATS prefix.
# Use nkeys.PREFIX_BYTE_USER for a user key, nkeys.PREFIX_BYTE_ACCOUNT for an account, etc.
user_seed_bytes = nkeys.encode_seed(nkeys.PREFIX_BYTE_USER, raw_signing_key.encode())
print(f"Generated User Seed (NKEY format): {user_seed_bytes.decode()}")
# 3. Create an NKEYS KeyPair object from the seed
key_pair = nkeys.from_seed(user_seed_bytes)
print(f"Public Key (U...): {key_pair.public_key.decode()}")
# The private key and seed should be kept secret.
# The raw private key is a 64-byte Ed25519 private key.
print(f"Private Key (raw hex - keep secret!): {key_pair.private_key.hex()}")
print(f"Seed (S... NKEY format - keep secret!): {key_pair.seed.decode()}")
# 4. Example of signing data
data_to_sign = b"Hello NATS! This is a test message."
signature = key_pair.sign(data_to_sign)
print(f"Signature for data: {signature.hex()}")
# 5. Verification (a KeyPair created from the public key can verify signatures)
verifier_key_pair = nkeys.from_public_key(key_pair.public_key)
try:
verifier_key_pair.verify(data_to_sign, signature)
print("Signature verified successfully.")
except Exception as e:
print(f"Signature verification failed: {e}")
# 6. Secure handling: wipe sensitive key material from memory when no longer needed
key_pair.wipe()
print("Sensitive key material wiped from memory for security.")