Skip to content

Layr8

Layr8

Layr8 is a commercial implementation of Layer 8, developed by Protocol Technologies, Inc. It provides a platform for creating and hosting agents with built-in identity resolution, policy enforcement, and cryptographically verifiable audit trails.

What Layr8 Provides

  • Nodes — Host agents and manage DIDComm communication between them. Available as a cloud managed solution, but can be licensed and run on-prem.
  • DID Resolution — Support for standard DID methods including did:web and did:peer, with more to come.
  • Agents — Provide identity-specific functionality. Agents focus on logic while their host Node handles the complexity of encryption, authorization, logging, and message delivery.
  • Policy Engines — Enforce and delegate fine-grained authorization with cryptographically verifiable grants, expiry, and use limits.
  • Audit Chains — Hash-linked logs for cryptographically verifiable interaction history.

What Layr8 Is Not

Understanding Layr8’s boundaries helps you evaluate where it fits—and where it doesn’t.

Layr8 is not a replacement for your existing API authentication. Leave your API as-is. If you use OIDC, OAuth, or SAML to secure your APIs today, those systems continue to work. Layr8 operates on a layer above them—it provides identity for cross-organization coordination, not single sign-on for your users. Your API auth stack remains unchanged.

Your Org Partner Org
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ │ │ │
│ ┌─────┐ ┌───────┐ ┌──────┐ │ │ ┌──────┐ ┌───────┐ ┌─────┐ │
│ │ API │◄──►│ Agent │◄──►│ Node │◄───┼──┼──►│ Node │◄──►│ Agent │◄──►│ API │ │
│ └─────┘ └───────┘ └──────┘ │ │ └──────┘ └───────┘ └─────┘ │
│ OIDC/OAuth Your Encrypts │ │ Decrypts Their OIDC/OAuth │
│ unchanged logic & routes │ │ & authorizes logic unchanged │
│ │ │ │
└──────────────────────────────────────┘ └──────────────────────────────────────┘

Layr8 is not a message queue or event bus. A single Layr8 node can easily deliver thousands of messages per second and can horizontally scale to tens or even hundreds of thousands with additional machines. But DIDComm is designed for identity-aware messaging, not low-latency high-throughput raw streaming. If your use case demands high-throughput or does no require multi-party authentication and authorization, a dedicated messaging solution like Kafka or NATS might be a better choice. Use Layr8 when you need messaging that crosses organizational boundaries; if you need cryptographic proof of who sent a message and whether they are authorized to perform an action.

Good fit for Layr8Less good fit
Cross-org coordinationInternal microservice events
Identity matters (who sent this?)Anonymous fire-and-forget
Authorization required per messageBulk streaming with no auth
Audit trail neededHigh-frequency telemetry
Hundreds to thousands of msg/secMillions of msg/sec sustained

Layr8 is not Web3 or blockchain. Layr8 makes use of cryptography to prove identity, which shares similarities with blockchain. Layr8’s use of cryptography doesn’t require messages to be published to any blockchain, nor do you need to wait for global concensus, which can slow things down. We use Decentralized IDentifiers (DIDs), a W3C standard that supports multiple ways to create, publish, read, and verify identity. Some DIDs rely on blockchains, however Layr8’s initial focus is on supporting did:web and did:peer. Additional DID methods will follow, but the point is architectural: Layr8 can, and does, leverage blockchain, but it is not fundamentally tied to blockchain or any particular DID method. You get decentralized identity through standard web infrastructure—no ties to a distributed ledger, no enforced consensus mechanism, no cryptocurrencies or tokens.

With did:web, identity verification uses standard web infrastructure you already trust. Messages are packed with authenticated encryption (ECDH-1PU)—the sender’s identity is proven during decryption, not as a separate step:

Encrypted message arrives
┌──────────────────────────────────────────────┐
│ Receiving Node │
│ │
│ 1. Parse sender key ID from JWE headers │
│ skid: did:web:acme.layr8.io:purchasing#key-1
│ │ │
│ ▼ │
│ 2. Resolve sender's DID Document │
│ GET https://acme.layr8.io/purchasing/did.json
│ │ │
│ ▼ │
│ 3. Authenticated decryption (ECDH-1PU) │
│ Uses sender's public key + │
│ recipient's private key │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ Decrypts Fails │
│ ──────── ───── │
│ Sender is Reject │
│ authentic (problem report) │
│ │ │
│ ▼ │
│ 4. Continue with authorization & delivery │
│ │
└──────────────────────────────────────────────┘

No certificate authority to configure. No shared secret to exchange. The sender’s domain serves their public key; the receiver fetches it to decrypt. If decryption succeeds, the sender is authenticated—only someone with the corresponding private key could have produced the message. DNS and TLS—infrastructure you already operate—form the trust chain.

Layr8 is not all-or-nothing. You don’t need to rearchitect your systems to try Layr8. It coexists with existing infrastructure, handles a scoped use case, and can be removed if it doesn’t prove valuable. Start with one integration between two parties; expand only where it earns its place. Systems evolve—Layr8 is designed to evolve with them, not lock you into a decision made today.

Agents and Nodes

A Layr8 agent is a software program with its own identity. Agents connect to the cloud node that hosts their DID—think of a DID as the agent’s email address that the agent can prove it owns. The separation between agent and node keeps your code focused on business logic while the node handles infrastructure:

Agent (your code)Node (Layr8 infrastructure)
IdentityProvides a DID at connect time, or requests one via did_specCreates DIDs, generates keys, serves the DID Document publicly
KeysNever touches private keysGenerates, stores (encrypted at rest), and uses keys for all signing and decryption
ProtocolsRegisters handlers for message types before connectingRoutes inbound messages to the matching handler; queues messages when agent is offline
CredentialsReceives sender credential info as read-only contextRequests, validates, and caches verifiable credentials on the agent’s behalf
AuthorizationReceives an authorized flag with each messageEnforces per-DID allow/deny lists, grant-based policies, and verifiable credential checks before delivery
EncryptionSends and receives plaintext only — never sees encrypted wire formatPacks outbound messages (ECDH-1PU authcrypt); unpacks and authenticates inbound
AuditNo audit responsibilityRecords every interaction in hash-linked audit chains — tamper-evident, independently verifiable by both parties

Agents can represent people, organizations, IoT devices, APIs, databases, or any entity that needs a Layer 8 identity.

How Messages Flow

From your agent’s perspective, sending a message feels like passing JSON to another agent:

What it feels like:
Your Agent ──── JSON ────► Their Agent

The actual flow has more steps — but the node handles all of them:

What actually happens:
Your Agent Their Agent
│ ▲
│ plaintext plaintext │
▼ │
Your Node Their Node
│ ▲
├─ resolve recipient DID route to agent ┤
├─ encrypt (ECDH-1PU authcrypt) audit chain ─┤
├─ audit chain authorize ─┤
│ decrypt + authenticate ───┤
▼ resolve sender DID ─┤
Internet ──────── encrypted JWE ───────────► Internet

Your agent sends plaintext. Their agent receives plaintext. Everything in between — key resolution, authenticated encryption, policy enforcement, audit logging — is invisible to both.

How Nodes Connect

Nodes connect peer-to-peer using gRPC (HTTP/2) or HTTPS — there is no central message broker. When your node needs to deliver a message, it discovers the recipient’s service endpoint from their DID Document and opens a direct connection:

Sender's Node Recipient's Node
│ │
│ 1. Resolve recipient DID Document │
│ → find service endpoint │
│ │
│ 2. Connect (gRPC or HTTPS) │
│─────────────────────────────────────────────► │
│ │
│ 3. Deliver encrypted JWE │
│═════════════════════════════════════════════► │
│ │
│ 4. Same connection, different DID │
│═════════════════════════════════════════════► │
│ │

A single service endpoint serves all DIDs hosted on that node. When multiple DIDs reside on the same node — which is the common case — one connection carries messages for all of them. The recipient node identifies the target DID from the decrypted message, not from the connection itself.

did:web:acme.layr8.io:sales ─────┐
│ one connection
did:web:acme.layr8.io:purchasing ─┼────────────────────► acme.node.layr8.io
did:web:acme.layr8.io:support ────┘

When your node sends to multiple recipients across different nodes, it calculates the minimum set of connections needed. If five recipient DIDs are spread across two nodes, your node opens two connections — not five.

TransportProtocolWhen used
gRPCHTTP/2 (h2)Default — binary framing, multiplexed streams
HTTPSHTTP/1.1 POST to /didcommFallback — works through any standard proxy or firewall
WebSocketws/wssComing soon — persistent bidirectional channel for agent-to-node and node-to-node

All transports carry the same encrypted DIDComm payload. The choice is transparent to your agent.

What Messages Look Like

Agents communicate by sending and receiving DIDComm plaintext messages—structured JSON with a standard envelope. Here’s a message from one agent requesting data from another:

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "https://example.com/protocols/orders/1.0/query",
"from": "did:web:acme.layr8.io:purchasing",
"to": ["did:web:widgets.layr8.io:catalog"],
"created_time": 1706745600,
"expires_time": 1706749200,
"body": {
"status": "open",
"limit": 50
}
}
FieldPurpose
idUnique message identifier (UUID)
typeProtocol URI — defines what this message means and how to handle it
fromSender’s DID — cryptographically verified by the node
toRecipient DID(s)
created_timeWhen the message was created (Unix timestamp)
expires_timeWhen the message expires (default: 1 hour)
bodyApplication-specific payload — whatever your protocol needs

The response follows the same structure, with a thid (thread ID) linking it back to the original:

{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "https://example.com/protocols/orders/1.0/results",
"from": "did:web:widgets.layr8.io:catalog",
"to": ["did:web:acme.layr8.io:purchasing"],
"thid": "550e8400-e29b-41d4-a716-446655440000",
"body": {
"orders": [
{"id": "ORD-1042", "item": "Widget A", "quantity": 200},
{"id": "ORD-1043", "item": "Widget B", "quantity": 75}
]
}
}

This is all your agent works with. The body is whatever your use case needs—the rest is a standard DIDComm envelope. Your agent constructs a message with type, to, and body; everything else is handled for you:

ResponsibilityHandled by
Message type, to, bodyYour agent
id, from, timestampsSDK (auto-generated)
Thread correlation (thid)SDK (automatic for responses)
Encryption and signingNode
Routing and deliveryNode
Authorization (policy check)Node
Problem reports on failureNode
Audit loggingNode

Your agent speaks plaintext. The node handles the rest.

Protocols: The Language Agents Speak

DIDComm is a meta-protocol — it defines how to securely exchange messages, but not what those messages mean. The meaning comes from protocols: agreed-upon sets of message types and interaction patterns that agents use to coordinate.

Think of DIDComm like the postal system. It guarantees authenticated delivery, encryption, and a return address. But the postal system doesn’t define what a purchase order looks like, or what steps follow an invoice. Protocols define that.

Standard Protocols

The DIDComm community maintains a set of standard protocols that every implementation can support out of the box:

ProtocolURIPurpose
Trust Pinghttps://didcomm.org/trust-ping/2.0Verify that a connection is alive and the other party is reachable
Basic Messagehttps://didcomm.org/basicmessage/2.0Send a simple text message — the “hello world” of DIDComm
Report Problemhttps://didcomm.org/report-problem/2.0Signal errors back to the sender (analogous to HTTP status codes)

These are useful for testing and diagnostics, but the real value comes from application-specific protocols.

Application Protocols

You define protocols for your business domain. A procurement protocol might look like this:

Protocol: https://acme.com/protocols/procurement/1.0
Message types:
.../rfq Request for quote
.../quote Supplier's response
.../order Purchase order
.../confirmation Order accepted
.../invoice Payment request

Each message type is a URI. Your agent registers handlers for the types it understands:

client.Handle("https://acme.com/protocols/procurement/1.0/rfq",
func(msg *layr8.Message) (*layr8.Message, error) {
// process the RFQ...
})

The protocol URI is just a namespace — Layr8 doesn’t fetch it or validate it. What matters is that both parties agree on the message types and their semantics. You publish a protocol spec; partners implement handlers for it.

Why This Matters

Traditional integrations couple partners at multiple levels: API endpoint paths, authentication mechanisms, payload schemas, error formats, rate limiting, versioning schemes. Change any one of these and the integration breaks.

DIDComm protocols decouple these concerns:

Traditional integration DIDComm protocol
───────────────────────── ─────────────────────────
POST /api/v2/orders type: .../orders/1.0/create
Authorization: Bearer xyz... (handled by node — ECDH-1PU)
Content-Type: application/json (always JSON in body)
X-API-Version: 2.3.1 (version is in the type URI)
X-Idempotency-Key: abc... (id field is always unique)
X-Webhook-Secret: def... (no webhooks — bidirectional)
Custom error format per API (standard problem reports)

The protocol defines what you’re coordinating on. DIDComm handles how messages get there. Your node handles who is authorized. These three concerns evolve independently.

In practice, this means your code shifts from designing around endpoints to designing around identities:

Traditional: Different URL, different auth, different client for every partner.

POST https://api.partner-a.com/orders Authorization: Bearer token123
POST https://api.partner-b.com/v2/orders X-API-Key: abc456
POST https://supplier.net/api/v3/create-order Basic: base64(user:pass)

Layr8: Same message type, same code, different recipient.

client.Request(ctx, &layr8.Message{
Type: "https://acme.com/protocols/orders/1.0/create",
To: []string{"did:web:partner-a.com:orders"},
Body: orderData,
})

Change the To field to reach a different partner. Authentication, encryption, and delivery are handled by the node — your code doesn’t change.

One Agent, Many Partners

Because protocols are decoupled from infrastructure, adding a new partner doesn’t require a new integration. If three suppliers all speak https://acme.com/protocols/procurement/1.0, your purchasing agent handles all three with the same code. A fourth supplier joins the network? Same protocol, same handlers, no code change.

procurement/1.0
Your Purchasing Agent ◄──────────────────────► Supplier A
◄──────────────────────► Supplier B
◄──────────────────────► Supplier C
◄──────────────────────► Supplier D (new)
Same handlers. Same code. Different DIDs.

Partners can run different technology stacks, deploy on different clouds, and release on different schedules. As long as they speak the same protocol, coordination works. This is what designed for change means in practice: the protocol is the contract, not the implementation.

Protocol Versioning

Protocols are versioned in their URI. When a protocol evolves, the version changes:

https://acme.com/protocols/procurement/1.0/rfq ← original
https://acme.com/protocols/procurement/1.1/rfq ← backward-compatible addition
https://acme.com/protocols/procurement/2.0/rfq ← breaking change

An agent can register handlers for multiple versions simultaneously, supporting partners who have upgraded alongside those who haven’t. Migration happens at each partner’s pace, not yours.

See the DIDComm Messaging reference for technical details on protocol design and message handling.

Examples

API Access

Identity replaces API keys.

Today, calling a partner’s API means exchanging shared secrets — API keys, OAuth client credentials, webhook secrets — each one a credential to provision, store, rotate, and revoke across organizational boundaries. Each copy is an attack surface.

With Layr8, Alice calls Bob’s API using her own identity. No shared secrets.

Alice's Org Bob's Org
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ │ │ │
│ Application │ │ │
│ │ │ │ │
│ ▼ │ │ Bob's Node │
│ Alice's Agent │ │ • Decrypt + authenticate (ECDH-1PU)
│ │ │ │ • Check grant (read /api/orders?) │
│ │ plaintext │ │ • Log to audit chain │
│ ▼ │ │ │ │
│ Alice's Node │ │ ▼ │
│ │ encrypt │ │ Bob's Agent │
│ │ │ │ • Translate DID → Bearer token │
│ ▼ encrypted JWE │ │ • Call REST API │
│ Internet ─────────────────────────►│ │ │ │
│ ◄─────────────────────────│ │ ▼ │
│ │ │ REST API (unchanged) │
│ │ │ │
└──────────────────────────────────────┘ └──────────────────────────────────────┘

Alice’s agent sends plaintext. Her node encrypts and delivers. Bob’s node decrypts — authenticating Alice in the process — checks her grant, and logs the interaction. Only then does Bob’s agent receive the authorized message. The agent translates Alice’s DID into a Bearer token and calls the API.

The REST API is unchanged — it receives credentials it already understands. Alice holds no API key. If Bob revokes her grant, the node rejects future messages immediately.

Layr8’s Zero-Trust Gateway is a commercially available agent that implements this pattern. It sits between untrusted compute — remote developers, AI agents, or third-party services — and external APIs. Credentials never leave the gateway. Callers hold only a DID; the gateway verifies their identity, checks their grant, decrypts the API key just-in-time, makes the call, and discards the key. No shared secrets at the edge.

Database Access

Query across organizations like querying locally.

Alice’s organization needs data from Bob’s PostgreSQL database. Without Layr8, this means VPNs, shared database credentials, or building a custom API. With Layr8, Alice queries Bob’s data as naturally as querying her own — if Bob permits it.

Alice's Org Bob's Org
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ │ │ │
│ psql -h localhost -p 5433 │ │ │
│ │ │ │ Bob's Node │
│ ▼ │ │ • Decrypt + authenticate │
│ Alice's Agent (postgres proxy) │ │ • Check grant (read-only?) │
│ │ SQL → DIDComm │ │ • Log to audit chain │
│ │ plaintext │ │ │ │
│ ▼ │ │ ▼ │
│ Alice's Node │ │ Bob's Agent │
│ │ encrypt │ │ • Execute query against DB │
│ │ │ │ • Return results │
│ ▼ encrypted JWE │ │ │ │
│ Internet ─────────────────────────►│ │ ▼ │
│ ◄─────────────────────────│ │ PostgreSQL │
│ │ │ │
└──────────────────────────────────────┘ └──────────────────────────────────────┘

Alice has no direct database connection. She runs psql -h localhost -p 5433, which connects to her local agent acting as a postgres proxy. The agent encapsulates the SQL as a DIDComm message. From there, the node pipeline takes over: encrypt, deliver, authenticate, authorize, audit — same as every other Layr8 interaction. Bob’s agent receives the authorized query, executes it, and returns results.

Both nodes record the interaction in hash-linked audit chains. If either party disputes what happened, the chains provide cryptographic proof.

Transparent to Existing Clients

The client sees a normal postgres connection. The value is baked into the stack beneath it.

psql -h localhost -p 5433 -c "SELECT * FROM invoices"
│ Looks like a normal database connection.
│ Underneath:
│ ✓ Identity — caller authenticated by DID
│ ✓ Authorization — grant checked per query
│ ✓ Encryption — end-to-end, automatic
│ ✓ Audit — both sides logged, tamper-evident
│ ✓ Cross-org — query crosses boundaries invisibly
Results

No special client. No SDK. No code changes. Standard psql connects to localhost and gets results — the same way it always has. Authentication, authorization, encryption, and audit are handled by the networking stack, not the application.

This pattern works for any Layer 7 system — REST APIs, databases, message queues, legacy services. The agent adapts the protocol; Layr8 handles identity, authorization, and audit beneath the surface.

Grants and Policies

Layr8 uses grants to control access. A grant specifies:

  • Subject — The DID allowed to use this grant
  • Action — What operation is permitted (e.g., read, write)
  • Resource — The DID-based resource path (e.g., did:web:bob.org:database/invoices)
  • Expiry — When the grant expires
  • Uses — How many times the grant can be used

Policies define rules that incoming requests must satisfy before execution. A policy might require that the requester holds a specific verifiable credential, belongs to a trusted network, or has been delegated a specific authority by an owner.

Audit Chains

Every interaction between agents is recorded in a hash-linked audit chain. Each node maintains its own chain independently — there is no shared ledger.

What Gets Recorded

Each audit entry captures the full context of a policy decision:

FieldPurpose
timestampWhen the interaction occurred
subject_didWho made the request
actionWhat was requested (read, write, etc.)
resourceWhat was accessed
decisionAllow or deny
explainWhy — which policy matched, which grant was used
grant_idThe specific grant that authorized access
phaseRequest, execute, or response
hashSHA-256 hash of this entry
prev_hashHash of the previous entry (the chain link)
remote_audit_hashThe other party’s hash for this interaction

How the Chain Works

They’re called “chains” for the same reason as blockchain: each entry contains the hash of the previous entry, forming a cryptographic link. The structure is identical — hash-linked entries where modifying any record breaks the chain from that point forward.

Entry 1 Entry 2 Entry 3
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ action: READ │ │ action: READ │ │ action: WRITE│
│ decision: ✓ │ │ decision: ✗ │ │ decision: ✓ │
│ ... │ │ ... │ │ ... │
│ │ │ │ │ │
│ prev: 000000 │ │ prev: a3f8c1 │──► │ prev: 7b2c1d │
│ hash: a3f8c1 │──► │ hash: 7b2c1d │ │ hash: 8f3a2b │
└──────────────┘ └──────────────┘ └──────────────┘
Modify this entry?
Its hash changes →
Entry 3's prev_hash
no longer matches →
Chain is broken.
Tampering detected.

The difference from blockchain: there’s no distributed ledger, no consensus mechanism, and no performance penalty. Git uses the same hash-linking structure for commits. Audit chains apply it to interactions — each organization maintains its own chain locally, and the chains cross-reference each other for verification.

Both Sides Keep Records

When Alice queries Bob’s database, both nodes independently record what happened. Alice’s node logs that she made the request. Bob’s node logs that he received, authorized, and executed it.

Alice's Chain Bob's Chain
(requester) (data owner)
┌──────────────────┐ ┌──────────────────┐
│ REQUEST │ │ EXECUTE │
│ action: READ │ │ action: READ │
│ resource: orders │ │ resource: orders │
│ decision: allow │ │ decision: allow │
│ grant: #a7x9 │ │ grant: #a7x9 │
│ │ hash exchange │ │
│ remote: c4f19e ──┼───────────────────►│ hash: c4f19e │
│ hash: 8f3a2b ◄─┼───────────────────┤ remote: 8f3a2b │
└──────────────────┘ └──────────────────┘

After the interaction, both nodes exchange hashes. Alice’s entry stores Bob’s hash; Bob’s entry stores Alice’s hash. This mutual hash exchange means both chains contain cross-references to each other — without sharing a database, without a blockchain, and without trusting the other party.

Reconciliation and Dispute Resolution

If a dispute arises — “you accessed our data without permission” or “we never received that request” — each party produces their chain. Because entries are hash-linked and cross-referenced:

  • Tampering is detectable. Modifying an entry breaks the chain. Both parties can independently verify the other’s chain is intact.
  • Disagreements are provable. If Alice’s chain says the request was made and Bob’s chain says it wasn’t received, the missing cross-reference is evidence of where the failure occurred.
  • Scope is verifiable. The audit entry records exactly which grant authorized access, what resource was accessed, and what query was executed — not just “access occurred.”

Neither party can deny an interaction that both chains record. Neither party can fabricate an interaction without the other’s matching hash.

What if one party claims they lost their chain? The other party’s chain still stands as evidence. Bob’s chain is hash-linked and tamper-evident — he can’t insert a fake entry after the fact without breaking the chain. And the audit entry records something that happened at a deeper layer: the message was authenticated via ECDH-1PU, meaning only Alice’s private key could have produced it. The audit chain doesn’t provide the authentication — it records that authentication occurred. Even with Alice’s chain missing, Bob’s chain proves a cryptographically authenticated message arrived from Alice’s DID, was authorized by a specific grant, and accessed a specific resource at a specific time.

Getting Started

  • Visit layr8.io to explore the platform
  • Read the technical documentation for architecture details
  • Contact the team to discuss implementation for your use case

Layer 8 was conceived by Protocol Technologies, Inc. as the missing identity layer for the Internet—a foundational extension to the OSI model that makes authentication, authorization, and audit intrinsic to network communication. Read The Genesis of Layr8 to learn more. Layr8 is our commercial implementation of Layer 8.

Standards

Organizations

Open-Source Implementations