Python API Reference
Overview
The Python entity-side API supports two application workflows:
- Create a secure channel with
SecureClient,SecureServer, andSecureChannel. This is the recommended workflow for most applications. - Manage session keys explicitly with
IoTAuthContext.request_session_keys()andSessionKeyCachewhen an application needs to select or reuse keys.
Most applications only need these top-level imports:
from iotauth import IoTAuthContext, SecureClient, SecureServer, SecureChannel, IoTAuthError
The iotauth package root intentionally exposes only the application-facing
client, server, channel, context, configuration and key models, and public
exceptions. Low-level protocol, cryptography, handshake, serialization,
transport, and credential helpers remain available from their dedicated
modules and are not top-level imports. For example:
from iotauth.protocol import IoTSPFrame, MessageType, parse_frame
from iotauth.crypto import symmetric_encrypt_authenticate
from iotauth.transports import recv_frame, send_frame
Applications should normally use SecureClient, SecureServer, and
SecureChannel instead of calling those low-level helpers directly.
Common setup: IoTAuthContext
The IoTAuthContext class holds the runtime state of a Python entity: configuration parameters, cryptographic keys, distribution-key settings, and cached session keys.
Constructors
IoTAuthContext.from_config
@classmethod
def from_config(cls, path: str | Path, *, validate_paths: bool = True) -> IoTAuthContext
Reads an entity configuration file, loads its configured credentials or
permanent distribution key, and initializes an IoTAuthContext. This is the
only public configuration entry point and is the method applications should
use.
The internal parser supports both C-style dotted properties (key=value) and Node-style JSON configuration files.
It detects JSON from the first non-whitespace character ({), rather than relying on the filename extension.
Both formats produce the same runtime context.
Relative credential and key paths are resolved differently by format:
-
Properties paths are relative to the directory containing the config file.
-
JSON paths are relative to the current working directory from which the Python process is started.
-
Absolute paths work in both formats.
-
Parameters:
path: Path to a properties or JSON configuration file, commonly using the.configextension.validate_paths: IfTrue, verifies that configured credential and key files exist during initialization.
-
Returns: An initialized
IoTAuthContextinstance with an emptySessionKeyCache. -
Raises:
ConfigErrororCredentialErrorif the configuration is invalid or files cannot be loaded.
The parsed configuration is available as ctx.config for inspection.
Applications should treat it as file-owned runtime configuration and should not modify it in code.
To change configuration, update the source file and create a new context with from_config().
1. Create a secure channel
Use this workflow when an application only needs to establish an encrypted
connection and exchange messages. SecureClient and SecureServer handle key
acquisition and the secure handshake. Application data is always sent through
the returned SecureChannel.
SecureClient
A wrapper for client-side key acquisition, connection establishment, and the secure handshake.
Constructor
def __init__(
self,
ctx: IoTAuthContext,
*,
key: SessionKey | None = None,
purpose: dict[str, object] | str | None = None,
host: str | None = None,
port: int | None = None,
timeout: float | None = 5.0,
)
ctx: The runtimeIoTAuthContext.key: Optional session key. If omitted,connect()requests one from Auth.purpose: Optional purpose override used when requesting a key.host/port: Optional peer address. If omitted, the first configured target is used.timeout: Timeout for Auth, connection, and handshake operations.
connect
def connect(self) -> SecureChannel
Returns an open SecureChannel. If the client was not constructed with a key,
this method requests one from Auth before connecting to the peer.
Each SecureClient owns at most one open channel. Close the returned channel
before calling connect() again; otherwise connect() raises
SecureClientStateError.
Client example
ctx = IoTAuthContext.from_config("path/to/client.config")
with SecureClient(ctx) as client:
channel = client.connect()
channel.send(b"hello")
reply = channel.recv(timeout=5.0)
Exiting the with block closes the active channel. To close it earlier, call
channel.close().
SecureServer
A wrapper that listens for incoming TCP connections from peer entities and completes secure handshakes.
Constructor
def __init__(
self,
ctx: IoTAuthContext,
*,
host: str | None = None,
port: int | None = None,
backlog: int = 5,
accept_timeout: float | None = None,
handshake_timeout: float | None = 5.0,
)
ctx: The runtimeIoTAuthContext.host/port: Listen address. If omitted, the first configured target is used.backlog: Maximum pending TCP connections passed tosocket.listen().accept_timeout: Maximum seconds to wait for an incoming TCP connection. The default,None, waits indefinitely.handshake_timeout: Maximum seconds to complete the secure handshake after accepting a peer. The default is five seconds. UseNoneto wait indefinitely.
serve_once
def serve_once(self) -> SecureChannel
Blocks until a single client TCP connection is accepted, reads the session key ID from the initial handshake frame, fetches the key if necessary, completes the challenge/response verification, and returns a connected SecureChannel.
Server example
ctx = IoTAuthContext.from_config("path/to/server.config")
with SecureServer(ctx) as server:
channel = server.serve_once()
try:
message = channel.recv()
channel.send(b"ack")
finally:
channel.close()
Exiting the with block closes the server's listening socket. The application
closes each channel returned by serve_once().
SecureChannel
Represents an established, bidirectional encrypted communication session between two entities.
The socket, session key, and send/receive sequence counters are managed
internally. Applications can inspect the read-only closed property and use
the methods below.
Methods
send
def send(self, payload: bytes) -> None
Encrypts payload using the active session key and cryptographic mode (for
example, AES_128_CBC or AES_128_GCM) and transmits the framed bytes over the
TCP socket.
recv
def recv(self, *, timeout: float | None = None) -> bytes
Reads an incoming frame from the TCP socket, verifies any HMAC/GCM
authentication tags, decrypts the payload using the session key, and returns
the raw plaintext bytes. timeout limits how many seconds the operation
waits for a complete message; None waits indefinitely. The socket's previous
timeout is restored after the call succeeds or fails.
close
def close(self) -> None
Closes the underlying TCP connection.
2. Manage session keys explicitly
Use this workflow when an application needs to request several keys, inspect the key cache, or choose a specific key before creating a secure channel.
IoTAuthContext.request_session_keys
def request_session_keys(
self,
*,
purpose: dict[str, object] | str | None = None,
count: int | None = None,
timeout: float | None = 5.0,
) -> list[SessionKey]
purpose: Optional purpose override. If omitted, the configured purpose is used.count: Number of keys to request. If omitted, the configured key count is used.timeout: Socket timeout in seconds for communication with Auth.- Returns: The keys returned by Auth. They are also added to
ctx.session_keys. - Raises:
AuthConnectionErrorwhen Auth is unreachable andAuthProtocolErrorwhen Auth returns an unexpected response.
Request and select a key
ctx = IoTAuthContext.from_config("path/to/client.config")
keys = ctx.request_session_keys(
purpose={"group": "Servers"},
count=2,
)
with SecureClient(ctx, key=keys[0]) as client:
channel = client.connect()
channel.send(b"hello")
reply = channel.recv()
Passing key= prevents SecureClient.connect() from requesting another key.
SessionKeyCache
The context exposes its in-memory cache as ctx.session_keys:
ctx.session_keys.add(key, replace=False)
key = ctx.session_keys.get(key_id)
key = ctx.session_keys.require(key_id)
keys = ctx.session_keys.values()
add()stores a key. Setreplace=Trueto replace a key with the same ID.get()returnsNonewhen the key is absent.require()raisesKeyCacheErrorwhen the key is absent.values()returns all cached keys.
SessionKey
SessionKey(
id: bytes,
cipher_key: bytes,
mac_key: bytes | None,
abs_validity: int | None,
rel_validity: int | None,
encryption_mode: str,
hmac_enabled: bool,
permanent_distribution_key: bool,
first_use_ms: int | None = None,
)
id: Eight-byte session-key identifier.cipher_key: Symmetric encryption key.mac_key: Message-authentication key, orNonewhen HMAC is disabled.abs_validity: Absolute expiration time in epoch milliseconds.rel_validity: Validity duration in milliseconds after first use.encryption_mode: Configured symmetric encryption mode.hmac_enabled: Whether messages require HMAC authentication.permanent_distribution_key: Whether Auth issued the session key using permanent distribution-key mode.first_use_ms: First-use time in epoch milliseconds used to evaluate relative validity. It isNoneuntil the key is first used.
Most applications should use keys returned by request_session_keys() rather
than constructing them directly. Cipher and MAC key material is excluded from
the object's representation to avoid exposing secrets in logs and tracebacks.
Exceptions
All exceptions raised by the Python SDK inherit from IoTAuthError (iotauth.exceptions):
| Exception | Description |
|---|---|
IoTAuthError | Base class for all IoTAuth Python API errors. |
ConfigError | Raised when an .config file is missing required fields or malformed. |
CredentialError | Raised when a private key or certificate cannot be read or verified. |
KeyCacheError | Raised when a session-key cache operation is invalid. |
SerializationError | Raised when protocol bytes cannot be encoded or decoded. |
AuthConnectionError | Raised when TCP communication with Auth or a peer fails. |
AuthProtocolError | Raised when Auth returns a semantically unexpected message. |
UnsupportedCryptoError | Raised when a configured crypto operation is unsupported. |
MessageIntegrityError | Raised when signature, MAC, or authenticated decryption verification fails. |
SecureHandshakeError | Raised when the peer-to-peer secure handshake fails. |
ExpiredKeyError | Raised when an expired session key is used. |
SecureChannelClosed | Raised when an operation is attempted on a closed channel. |
SecureClientStateError | Raised when a client already owns an open channel. |
InvalidSequenceNumberError | Raised when secure-message sequence validation fails. |