Authorize: K-of-N Threshold Authorization
Cryptographic multi-party authorization for enterprise governance. Critical operations require K approvals from N designated parties — no single approver can act independently.
Single-Approver Risk
Traditional authorization systems rely on procedural controls — approvals that exist in application logic but can be bypassed by privileged users, compromised accounts, or administrative overrides.
Insider Threats
A rogue administrator with database access can authorize high-value transactions by modifying approval records directly. Application-layer checks provide no defense when the attacker has system-level privileges.
Single Point of Failure
When a single approver has the authority to execute critical operations — production deployments, wire transfers, access grants — that individual becomes a single point of failure. Coercion, social engineering, or account compromise creates an unacceptable operational risk.
Compliance Gaps
Financial services regulations mandate dual control and separation of duties. SOX Section 404 requires segregation of authorization and execution. FINRA Rule 3110 demands supervisory review for high-risk transactions. GDPR Article 32 mandates technical measures to ensure security of processing.
Application-layer approval workflows satisfy the letter of these requirements but fail the spirit — a determined insider or sophisticated attacker can bypass procedural controls. Auditors increasingly demand cryptographic guarantees, not just access control lists.
Cryptographic K-of-N Enforcement
Authorize transforms procedural authorization into cryptographic impossibility. An action payload is split into N shares via XorIDA threshold sharing. Any K shares can reconstruct the payload; K-1 or fewer reveal nothing.
Not Just Approval — Mathematical Guarantee
Traditional approval workflows track who said "yes" in a database. Authorize makes the action payload cryptographically impossible to execute without K physical approvals.
How It Works
import { createAuthorization } from '@private.me/authorize'; const config = { approvers: [ { id: 'did:key:cto', name: 'CTO' }, { id: 'did:key:ceo', name: 'CEO' }, { id: 'did:key:ciso', name: 'CISO' }, ], threshold: 2, // 2-of-3 required action: 'deploy:production', expiresAt: Date.now() + 3600000 // 1 hour }; const payload = new TextEncoder().encode('AUTHORIZED'); const result = await createAuthorization('deploy:production', payload, config); // Distribute shares[0] to CTO, shares[1] to CEO, shares[2] to CISO // Each share is individually HMAC-signed for integrity
const collected = [shares[0], shares[1]]; // CTO + CEO approve const verified = await verifyAuthorization(collected, actionHash); if (verified.ok) { const actionPayload = new TextDecoder().decode(verified.value); console.log('Action authorized:', actionPayload); // "AUTHORIZED" }
Authorization Lifecycle
1. Authorization Creation
An authorized requester (typically an operator or administrator) creates an authorization request for a specific action.
- Validate configuration: Ensure threshold ≥ 2, threshold ≤ N, and action string is non-empty.
- Pad payload: PKCS#7 padding to 16-byte boundary (prevents partial-block information leakage).
- Generate HMAC: HMAC-SHA256 on the padded payload for integrity verification.
- Split via XorIDA: Generate N shares via threshold secret sharing over GF(2).
- Hash action string: SHA-256 hash of the action string binds shares to this specific operation.
- Build share objects: Each share includes actionId, approverId, index, threshold, data, HMAC, originalSize.
2. Approval Flow
Shares are distributed to designated approvers via secure channels (email, secure messenger, in-person). Each approver receives exactly one share.
Out-of-band distribution: The authorization system does not transmit shares. The requester is responsible for secure delivery — this prevents the authorization service itself from becoming a single point of compromise.
Approval submission: Approvers submit their shares to the authorization server. The server stores encrypted shares (AES-256-GCM at rest) until the threshold is reached or the authorization expires.
3. Verification and Reconstruction
Once K shares are submitted, the authorization can be verified and the payload reconstructed.
- Validate share count: Ensure at least K shares are provided.
- Validate action binding: All shares must reference the same actionId.
- Reconstruct via XorIDA: Combine K shares to recover the padded payload.
- HMAC verification BEFORE use: Verify HMAC-SHA256 on reconstructed data. If integrity check fails, reject the authorization immediately — data may be tampered.
- Unpad payload: Remove PKCS#7 padding to recover the original action payload.
- Return to caller: The application receives the authorized payload and proceeds with the action.
Audit Trail
Every authorization lifecycle event is logged to an append-only audit log (via @private.me/auditlog):
- Authorization creation (timestamp, requester, action, threshold, approvers)
- Share distribution (approverId, timestamp)
- Share submission (approverId, timestamp)
- Threshold reached (timestamp, K shares collected)
- Verification success/failure (timestamp, HMAC result)
- Authorization expiry or revocation
The audit log is HMAC-chained to prevent retroactive tampering. Each log entry references the HMAC of the previous entry, creating a tamper-evident chain.
Enterprise Governance Scenarios
Dual control for wire transfers exceeding $100K. Treasury officer initiates, CFO + CEO approve. Cryptographic enforcement prevents rogue transfers.
SOX 404 • FINRA 3110Code deployment requires 2-of-3 approvals from engineering leads. Prevents unauthorized production changes during incidents.
DevSecOpsRoot certificate rotation requires CTO + CISO approval. Split custody prevents single-admin key compromise.
NIST SP 800-57Access to patient records outside normal workflow requires dual approval from Privacy Officer + Department Head.
HIPAA § 164.308(a)(4)Root zone changes require 3-of-5 approval from geographically distributed registrars. Prevents single-point DNS hijacking.
DNSSECDeclassification requires approval from originating agency + reviewing authority. Threshold sharing enforces two-person integrity.
EO 13526Emergency unblinding requires 2-of-3 approval from CRO + IRB + DSMB. Prevents premature trial compromise while preserving patient safety.
FDA 21 CFR Part 11Bulk customer data export for regulatory inquiry requires Compliance Officer + Legal Counsel approval. Prevents unauthorized data exfiltration.
GLBA • GDPR Art. 322-of-3: Default balanced mode. Any 2 of 3 approvers can authorize. Tolerates 1 unavailable approver.
3-of-5: High-value operations. Tolerates 2 unavailable approvers while requiring 3 independent approvals.
K-of-N: Custom thresholds for specific governance requirements.
Benchmarks
Authorization overhead measured on Node.js 22.x, Intel Core i7-1185G7 @ 3.00GHz, single-threaded.
| Operation | Payload Size | Latency | Notes |
|---|---|---|---|
| Create (2-of-3) | 256 bytes | <2ms | PKCS#7 pad + HMAC + XorIDA split |
| Create (2-of-3) | 1 KB | <3ms | Typical JSON action payload |
| Create (3-of-5) | 256 bytes | <3ms | More shares = slightly higher overhead |
| Verify + Reconstruct | 256 bytes | <1ms | HMAC verify + XorIDA reconstruct + unpad |
| Verify + Reconstruct | 1 KB | <1.5ms | Sub-millisecond for typical payloads |
| HMAC verification | Any | <0.3ms | HMAC-SHA256 via Web Crypto API |
Throughput
Authorization creation: ~500 authorizations/second (2-of-3, 256-byte payloads, single-threaded).
Verification: ~1000 verifications/second (reconstruction is faster than splitting).
Scalability
The authorize-cli enterprise server handles concurrent authorization workflows via in-memory state + JSONL persistence. No external database required. Horizontal scaling via multiple server instances with shared JSONL storage (NFS or object storage).
Enterprise CLI
The @private.me/authorize-cli package provides a production-ready HTTP server for managing authorization workflows.
Quick Start
pnpm add @private.me/authorize-cli
# Generate secrets export AUTHORIZE_SHARE_ENCRYPTION_KEY=$(openssl rand -hex 32) export AUTHORIZE_ADMIN_API_KEY=$(openssl rand -hex 32) # Start server on port 4400 authorize-cli serve --port 4400 --data /var/lib/authorize
export AUTHORIZE_API_URL=http://localhost:4400 export AUTHORIZE_API_KEY=$AUTHORIZE_ADMIN_API_KEY authorize-cli create \ '{"operation":"transfer","amount":100000,"to":"alice@example.com"}' \ did:key:approver1 \ did:key:approver2 \ did:key:approver3 \ --threshold 2 \ --expires 7200000
authorize-cli submit <action-id> did:key:approver1 <share1-base64> authorize-cli submit <action-id> did:key:approver2 <share2-base64>
authorize-cli verify <action-id>
# Returns reconstructed payload if threshold reached and HMAC valid
REST API Endpoints
Create a new authorization. Requires admin or operator role. Returns actionId and shares.
Submit an approval share. Requires operator role. Stores encrypted share until threshold reached.
Retrieve authorization status. Returns submitted count, threshold, expiry, and status (pending/authorized/expired).
Verify and reconstruct authorization. Requires admin or operator role. Returns payload if threshold met and HMAC valid.
Retrieve audit trail. Requires auditor role. Returns HMAC-chained log entries.
RBAC (3 Roles)
| Role | Permissions | Use Case |
|---|---|---|
| Admin | Create authorizations, verify, read audit log, manage API keys | System administrators |
| Operator | Create authorizations, submit approvals, verify | Application services, engineers |
| Auditor | Read-only access to audit log | Compliance officers, external auditors |
Deployment
Docker: Official Docker image available. Mount data directory as volume for persistence.
Air-gapped: Zero external network dependencies. All state stored in local JSONL files.
High availability: Run multiple instances with shared JSONL storage (NFS, S3, or distributed filesystem).
Production Deployment
Docker-ready. Air-gapped capable. Port 4400. 71 tests. Part of the Enterprise CLI Suite.
@private.me/authorize-cli provides a production-grade authorization server with full REST API, multi-party approval workflows, HMAC-chained audit logs, and cryptographic threshold enforcement. Integrates the complete @private.me/authorize package for enterprise governance deployments.
Docker Deployment
# Pull and run the Authorize server docker compose up -d authorize # Verify health curl http://localhost:4400/health # {"status":"ok","version":"0.1.0","uptime":42} # Air-gapped deployment docker save private.me/authorize-cli > authorize-cli.tar # Transfer to air-gapped environment docker load < authorize-cli.tar docker compose up -d
Environment Configuration
# Generate secrets on first deployment export AUTHORIZE_SHARE_ENCRYPTION_KEY=$(openssl rand -hex 32) export AUTHORIZE_ADMIN_API_KEY=$(openssl rand -hex 32) # Data directory for JSONL persistence export AUTHORIZE_DATA_DIR=/var/lib/authorize # Server configuration export AUTHORIZE_PORT=4400 export AUTHORIZE_HOST=0.0.0.0 # Audit log configuration (optional) export AUTHORIZE_AUDIT_RETENTION_DAYS=365 export AUTHORIZE_MAX_AUTHORIZATION_AGE_HOURS=72
Kubernetes Deployment
apiVersion: apps/v1 kind: Deployment metadata: name: authorize-server spec: replicas: 3 selector: matchLabels: app: authorize template: metadata: labels: app: authorize spec: containers: - name: authorize image: private.me/authorize-cli:latest ports: - containerPort: 4400 envFrom: - secretRef: name: authorize-secrets volumeMounts: - name: data mountPath: /var/lib/authorize volumes: - name: data persistentVolumeClaim: claimName: authorize-pvc
High Availability
# Mount shared JSONL storage (NFS, EFS, or distributed filesystem) docker run -d \ --name authorize-1 \ -p 4401:4400 \ -v /mnt/shared/authorize:/var/lib/authorize \ -e AUTHORIZE_SHARE_ENCRYPTION_KEY=$KEY \ -e AUTHORIZE_ADMIN_API_KEY=$ADMIN_KEY \ private.me/authorize-cli:latest docker run -d \ --name authorize-2 \ -p 4402:4400 \ -v /mnt/shared/authorize:/var/lib/authorize \ -e AUTHORIZE_SHARE_ENCRYPTION_KEY=$KEY \ -e AUTHORIZE_ADMIN_API_KEY=$ADMIN_KEY \ private.me/authorize-cli:latest # Load balancer routes to both instances # Shared storage ensures consistent state
Security Guarantees
Information-Theoretic Security
XorIDA threshold sharing over GF(2) provides unconditional security: any K-1 or fewer shares reveal zero information about the payload. This is not computational hardness — it is mathematical impossibility. An attacker with infinite computational resources cannot reconstruct the payload from K-1 shares.
HMAC Before Reconstruction
HMAC-SHA256 verification executes on the reconstructed padded data before the payload is returned or trusted. If integrity fails, the authorization is rejected immediately. This prevents timing attacks and ensures data integrity.
Action Binding
Shares are bound to a specific action string via SHA-256 hash. Shares from one authorization cannot be used to authorize a different action. This prevents share replay across different operations.
Time-Limited Authorization
Optional expiresAt timestamp enables time-bounded authorization windows. Expired authorizations are automatically rejected during verification. This limits the window of opportunity for share collection and prevents stale authorizations.
Collusion Resistance
Any K-1 colluding approvers cannot reconstruct the payload. They must obtain the Kth share from a non-colluding party. This enforces true multi-party control.
No Math.random()
All randomness uses crypto.getRandomValues() via Web Crypto API. No weak PRNG, no predictable seeds.
PKCS#7 Padding
Block-aligned padding prevents partial-block information leakage. Padding is validated during unpad to detect tampering.
hmac field. Transport-layer encryption (TLS) is mandatory for share distribution. Do not transmit shares over unencrypted channels.
Audit Trail Integrity
The audit log is HMAC-chained: each entry includes the HMAC of the previous entry. This creates a tamper-evident chain — modifying a historical entry breaks the chain and is immediately detectable.
Regulatory Alignment
SOX Section 404 (Sarbanes-Oxley)
Requirement: Segregation of duties for financial reporting controls. The person who authorizes a transaction must not be the same person who records it.
How Authorize satisfies: Threshold authorization enforces cryptographic separation. A single approver cannot both initiate and authorize a high-value transaction. The K-of-N model ensures multiple independent parties must consent.
2026 trend: SOX auditors increasingly demand continuous monitoring and real-time validation of separation of duties. Authorize provides cryptographic enforcement that cannot be bypassed by privileged users.
FINRA Rule 3110 (Supervisory Procedures)
Requirement: Broker-dealers must establish supervisory procedures for high-risk transactions, including dual approval for large wire transfers.
How Authorize satisfies: Dual control is cryptographically enforced. A front-line officer can initiate a wire transfer, but a supervisor must provide a second approval share for the transaction to proceed.
GDPR Article 32 (Security of Processing)
Requirement: Implement appropriate technical measures to ensure a level of security appropriate to the risk, including measures to ensure ongoing confidentiality and integrity.
How Authorize satisfies: Threshold authorization is a technical measure (not procedural) that enforces multi-party control over sensitive data operations. The audit log provides tamper-evident evidence of all authorization decisions.
HIPAA § 164.308(a)(4) (Information Access Management)
Requirement: Implement policies and procedures for authorizing access to electronic protected health information (ePHI).
How Authorize satisfies: Access to patient records outside normal workflow can require dual approval (Privacy Officer + Department Head). The cryptographic threshold prevents single-admin access abuse.
NIST SP 800-57 (Key Management)
Recommendation: Cryptographic keys should be protected using split knowledge or dual control procedures.
How Authorize satisfies: Root certificate rotation and key generation ceremonies can require K-of-N approval from designated key custodians. This aligns with NIST recommendations for high-value cryptographic material.
GLBA (Gramm-Leach-Bliley Act)
Requirement: Financial institutions must implement administrative safeguards to protect customer information.
How Authorize satisfies: Bulk customer data exports for regulatory inquiries can require dual approval (Compliance Officer + Legal Counsel), preventing unauthorized data exfiltration.
Known Limitations
No Per-Approver Digital Signatures (v0.1.0)
Shares are not individually authenticated with per-approver digital signatures. The publicKey field on Approver is reserved for a future version that will support Ed25519 signatures on submitted shares.
Current mitigation: Share submission requires authenticated API calls (Bearer token or DID-based auth in the enterprise CLI). The server logs which approver submitted each share.
HMAC Key Embedded in Shares
The HMAC key is included in each share's hmac field (format: key:signature). This is necessary for verification but means shares must be protected in transit.
Mitigation: Use TLS for all share transmission. Do not transmit shares over unencrypted channels. The enterprise CLI encrypts shares at rest with AES-256-GCM.
Advisory Expiry
The isExpired() function relies on Date.now() and is advisory only. The library checks expiry during verification, but enforcement depends on the caller not bypassing the check.
Mitigation: The enterprise CLI enforces expiry server-side and automatically cleans up expired authorizations.
No Revocation Propagation
If an approver's share is revoked, there is no automatic propagation mechanism to notify other approvers or the requester.
Mitigation: The enterprise CLI provides a revocation API that marks shares as invalid and emits audit log entries. Applications should poll for status changes.
Payload Size Practical Limit
While XorIDA can handle arbitrary payload sizes, very large payloads (>1MB) incur noticeable overhead. Authorization payloads should be action descriptors (JSON, typically <1KB), not bulk data.
Best practice: Authorize the action, not the data. For large data transfers, authorize a reference (hash, S3 key, database ID) and validate the reference before proceeding.
API Surface
Functions
Splits a payload into K-of-N shares via XorIDA. Pads with PKCS#7, generates HMAC, and binds shares to an action via SHA-256 hash. Returns actionId, shares, and actionHash.
Reconstructs the payload from K shares. HMAC verification runs BEFORE the payload is returned. Returns the original payload bytes if successful.
Same as verifyAuthorization but accepts the action string directly, computing the SHA-256 hash internally.
Returns true if the authorization has passed its expiresAt timestamp. Advisory only — enforcement is the caller's responsibility.
Types
Approver
| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier (DID or email) |
| name | string | Human-readable name |
| publicKey | Uint8Array? | Optional Ed25519 public key (future use) |
AuthorizationConfig
| Field | Type | Description |
|---|---|---|
| approvers | Approver[] | List of approvers (minimum 2) |
| threshold | number | K-of-N threshold (≥2, ≤N) |
| action | string | Action description (non-empty) |
| expiresAt | number? | Optional expiry (ms since epoch) |
ApprovalShare
| Field | Type | Description |
|---|---|---|
| actionId | string | UUID v4 action identifier |
| approverId | string | Approver ID this share is assigned to |
| index | number | Share index (0-based) |
| total | number | Total shares (N) |
| threshold | number | Required threshold (K) |
| data | string | Base64-encoded share data |
| hmac | string | Base64 HMAC (key:signature) |
| originalSize | number | Payload size before padding |
Error Codes
| Code | Returned By | Description |
|---|---|---|
| INVALID_CONFIG | createAuthorization, verifyAuthorization | Fewer than 2 approvers, threshold < 2 or > N, empty action, or mismatched action IDs across shares. |
| SPLIT_FAILED | createAuthorization | XorIDA split operation threw an exception internally. |
| HMAC_FAILED | verifyAuthorization, verifyAuthorizationWithAction | HMAC-SHA256 verification failed after reconstruction. Data integrity compromised — shares may be tampered. |
| RECONSTRUCT_FAILED | verifyAuthorization, verifyAuthorizationWithAction | XorIDA reconstruction failed or PKCS#7 unpadding produced invalid result. |
| INSUFFICIENT_APPROVALS | verifyAuthorization, verifyAuthorizationWithAction | Number of submitted shares is less than the required threshold. |
| ACTION_EXPIRED | Application-level (via isExpired) | Date.now() exceeds config.expiresAt. |
| APPROVAL_REVOKED | Application-level | An approval share has been marked as revoked (enterprise CLI only). |
Error Details
All errors include a message field with a human-readable description. For INVALID_CONFIG, the message specifies which validation rule failed (e.g., "Threshold must be >= 2").
Dependencies
| Package | Relationship |
|---|---|
| @private.me/crypto | Provides XorIDA split/reconstruct, HMAC-SHA256, PKCS#7 padding, base64 encoding, UUID generation. |
| @private.me/shared | Provides Result<T, E> type and ok()/err() constructors for error handling. |
| @private.me/auditlog | Optional integration for HMAC-chained audit trail of authorization events (used by authorize-cli). |
| @private.me/xid | Optional integration for DID-based approver authentication (enterprise deployments). |
Zero npm Dependencies
The @private.me/authorize library has zero npm dependencies beyond PRIVATE.ME platform packages. All cryptography uses Web Crypto API. No OpenSSL, no libsodium, no third-party crypto libraries.