Metadata-Version: 2.4
Name: keybind.py
Version: 1.0.0
Summary: Symmetric encrypted identity-bound token library
Author: Pravanjan Roy
License: Apache-2.0
Project-URL: Homepage, https://keybind.kingmon.xyz
Project-URL: Repository, https://github.com/kingmon6996/keybind
Project-URL: Issues, https://github.com/kingmon6996/keybind/issues
Keywords: encryption,identity-bound,symmetric-token,stateless-token
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography
Requires-Dist: PyNaCl
Requires-Dist: zstandard
Requires-Dist: orjson
Dynamic: license-file

# Keybind (v1.0)

**Keybind** is a highly secure Python package for generating **stateless, encrypted, identity-bound tokens** using **Symmetric Cryptography**.

It is designed for secure, trustless data sharing where you want to ensure **confidentiality** and **authentication** without worrying about file I/O or asymmetric key management. The payload is encrypted with a single symmetric key and returned as a Base64-URL encoded string.

---

## Installation

The project is installed from PyPI under the name `keybind.py`:

```bash
pip install keybind.py
```

---

## The Core Philosophy

* **Stateless Tokens:** The library directly encodes the data into a Base64-URL encoded string.
* **Identity-Bound:** The token is mathematically glued to two specific strings (e.g., `"Alice_ID"` and `"Bob_ID"`). It cannot be intercepted and passed off to a different microservice.
* **Symmetric:** Uses a single string or bytes key provided by the user, from which secure encryption keys are derived.
* **Time-to-Live (TTL):** Embed a strict expiration timestamp (`expires_at`) into tokens. If the token is too old, the decode process natively catches it and aborts.

---

## What is Keybind for?

You can use Keybind when you need to:
- Securely share a payload (JSON dictionary) from one party to another relying on a shared secret.
- Bind that payload to specific user or application identities (e.g., Sender ID and Receiver ID).
- Pass heavily compressed payloads directly between microservices.
- Ensure that the generated token expires automatically after a set duration.

---

## Full Developer Tutorial & Usage Guide

### Step 1: Encoding Data to a Token

Imagine you want to encode a highly sensitive JSON configuration and send it to another server that shares the same secret key.

```python
import time
from keybind import Keybind

# A shared symmetric key for encoding and decoding
shared_key = "super_secret_shared_key_123!"

# Initialize the Keybind chain
chain = Keybind()

# Define the Python dictionary payload
payload = {
    "user_role": "admin",
    "secret_launch_code": 99342,
    "permissions": ["read", "write", "execute"]
}

# Calculate expiration time (1 hour from now)
expires = int(time.time()) + 3600

# Encode the token
token = chain.encode(
    key=shared_key,
    primary_identity="alice_service",
    secondary_identity="bob_server",
    data=payload,
    expires_at=expires    # Enforce TTL
)

print(f"Generated Token: {token}")
```

### Step 2: Decoding the Token

The receiving server receives the token string. It uses the same shared key and identities to unlock it.

```python
from keybind import Keybind
from keybind.exceptions import ExpiredToken, CryptoError

# Initialize the Keybind chain
chain = Keybind()

# A shared symmetric key for encoding and decoding
shared_key = "super_secret_shared_key_123!"

try:
    # Decode the token
    # You must supply the EXACT same identities used during encoding!
    decoded_data = chain.decode(
        key=shared_key,
        primary_identity="alice_service",
        secondary_identity="bob_server",
        token="<THE_BASE64_TOKEN_STRING>"
    )
    print("Decoded Dictionary:", decoded_data)

except ExpiredToken:
    print("Error: The token has expired!")
except CryptoError:
    print("Error: Decryption failed! The token was tampered with, or identities don't match.")
except Exception as e:
    print(f"An unexpected error occurred: {e}")
```

---

## Important Security Best Practices

- **Identities must be strict.** Do not use generic identities like `"user"` and `"app"` in production. Bind tokens to strict database UUIDs (e.g., `"user_a8f9d"` and `"service_auth_991"`). If identities don't perfectly match between `encode` and `decode`, decryption is mathematically guaranteed to fail.
- **Key management.** The `key` string acts as your master password for the token generation. Store it securely in environment variables and rotate it periodically.

---

## Complete API Reference

### `Keybind(config=None)`
Initializes a new Keybind instance.
```python
chain = Keybind()
```

### `Keybind.encode(key, primary_identity, secondary_identity, data, expires_at=None)`
Encodes and encrypts a Python dictionary payload into a base64url-encoded string token.
- `key` (str | bytes): Symmetric key used for derivation.
- `primary_identity` (str): Sender identity.
- `secondary_identity` (str): Receiver identity.
- `data` (dict): Dictionary to encrypt.
- `expires_at` (int, optional): Unix timestamp representing the token's expiration time.

```python
token = chain.encode(
    key="my_secret_key",
    primary_identity="alice",
    secondary_identity="bob",
    data={"secret": "message"},
    expires_at=1735689600
)
```

### `Keybind.decode(key, primary_identity, secondary_identity, token)`
Decrypts a token back into a Python dictionary.
- `key` (str | bytes): Symmetric key used for derivation.
- `primary_identity` (str): Sender identity used during encoding.
- `secondary_identity` (str): Receiver identity used during encoding.
- `token` (str): Base64url-encoded token string.

```python
decoded_data = chain.decode(
    key="my_secret_key",
    primary_identity="alice",
    secondary_identity="bob",
    token=token
)
```

## License

Copyright 2026 Pravanjan Roy

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
