Concepts

Delegation

Delegation is the act of passing a subset of authority from one key to another. The delegating party signs a new credential granting some of their permissions to a different public key. The result is a chain: root → node → leaf. Each link is a signed credential. Any party holding the root public key can verify the entire chain locally.

Rules

  • A credential may only grant permissions it holds. No escalation is possible.
  • The delegated scope must be a subset of the parent credential's scope. This is enforced cryptographically at verification time.
  • The delegated validity window must fall within the parent's window.
  • A leaf credential cannot delegate further. Only node credentials may issue child credentials.
  • Depth must increment monotonically. The root issues at depth 1; each subsequent hop increments by one.

Example

import os
from qhermes.kernel import (
    make_identity, derive_public_key, make_policy,
    issue_credential, build_chain, verify_chain,
)

master = os.urandom(32)

root    = make_identity(master, deployment=b"prod", context=b"root")
agent   = make_identity(master, deployment=b"prod", context=b"agent-0")
worker  = make_identity(master, deployment=b"prod", context=b"worker-0")

root_pk   = derive_public_key(root)
agent_pk  = derive_public_key(agent)
worker_pk = derive_public_key(worker)

# Root grants agent broad access, node role so it can delegate further
agent_cred = issue_credential(
    identity=root,
    child_pk=agent_pk,
    policy=make_policy(
        resources=[b"/jobs"],
        actions=[b"GET", b"POST"],
        hours_valid=1,
    ),
    depth=1,
    role="node",
)

# Agent delegates a narrower slice to worker, leaf role — chain ends here
worker_cred = issue_credential(
    identity=agent,
    child_pk=worker_pk,
    policy=make_policy(
        resources=[b"/jobs"],
        actions=[b"GET"],          # read-only subset
        minutes_valid=15,
    ),
    depth=2,
    role="leaf",
)

Chain verification

verify_chain walks from root to leaf checking every signature, depth sequence, scope containment, and time bound. If any link fails, the whole chain is rejected.

wire = build_chain((agent_cred, worker_cred))
n    = verify_chain(root_pk=root_pk, wire=wire)
print(f"Verified: {n} credential(s)")

Scope escalation attempt

If a credential attempts to claim a permission not present in its parent, verify_chain raises. The check happens at every hop, not only at the leaf.

from qhermes.kernel import decode_chain, parse_payload

for i, cred in enumerate(decode_chain(wire)):
    p = parse_payload(cred)
    print(f"  [{i+1}] role={p['role']} perms={p['perms']}")

Next: Scopes and resources