Skip to main content
A Gate is the verification point that checks Passports and makes allow/deny decisions.

L1 Baseline Algorithm

Every Gate MUST implement these checks in order:
1. Verify passport signature         (embedded public_key)
2. Check passport not expired        (timestamp comparison)
3. Apply issuer policy               (allow_self_issued OR issuer in allowlist)
4. Check permission exists           (action matches permissions[])
5. Return allow/deny

Request Format

{
  "uni_version": "1.1.0",
  "request_id": "req_abc123",
  "passport": { "...passport object..." },
  "action": "mcp:search",
  "target": "mcp://tools.example.com",
  "issued_at": "2026-01-25T12:00:00Z",
  "parameters": { "query": "weather" }
}

Decision Format

{
  "uni_version": "1.1.0",
  "request_id": "req_abc123",
  "decision": "allow",
  "decision_at": "2026-01-25T12:00:01Z",
  "passport_id": "uni_abc123",
  "agent_id": "agent:my-agent",
  "action": "mcp:search"
}

Denial Codes

CodeDescription
INVALID_SIGNATUREPassport signature verification failed
PASSPORT_EXPIREDPassport has expired
ISSUER_NOT_ALLOWEDIssuer not trusted by this gate
PERMISSION_DENIEDAction not in permissions
POP_REQUIREDL2+ requires Proof of Possession
POP_INVALIDPoP verification failed

SDK Usage

from uniplex import Gate, GateRequest, TrustProfile

gate = Gate(profile=TrustProfile.L1)

request = GateRequest.create(
    passport=passport,
    action="mcp:search",
    target="mcp://tools.example.com"
)

decision = gate.authorize(request)

if decision.allowed:
    # proceed
    pass
else:
    print(f"Denied: {decision.reason_code}")

Simple Authorization

For quick checks without creating a request object:
from uniplex import Gate, TrustProfile

gate = Gate(profile=TrustProfile.L1)

decision = gate.authorize_simple(
    passport=passport,
    action="mcp:search",
    target="mcp://tools.example.com"
)