# How Iroh Handles Authentication: Cryptographic Peer Identity and Layered Security

> Discover how Iroh handles authentication using cryptographic peer identity and layered security. Explore its robust peer-to-peer connection security.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-06-21

---

**Iroh authenticates every peer-to-peer connection using cryptographic key pairs where the public key serves as the endpoint identity, layered with optional relay tokens and application-level hooks for custom authorization.**

Iroh, the open-source peer-to-peer networking library from n0-computer/iroh, implements a multi-layered authentication model that secures connections from the transport level up to the application layer. Understanding how iroh handles authentication is essential for building secure distributed systems that verify peer identity without centralized certificate authorities.

## Transport-Level Authentication with Cryptographic Keys

### Endpoint Identity and Public Key Verification

In [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs), iroh defines **EndpointId** as a type alias for `PublicKey`, making the public key the canonical identifier for every node. When you generate a new endpoint, `SecretKey::generate()` creates a curve25519/ed25519 key pair on the elliptic curve.

The secret key remains private to the endpoint, while the public key becomes its addressable identity on the network. This design ensures that owning the private key cryptographically proves ownership of the endpoint identity. According to the source code in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), each endpoint uses its "unique `SecretKey` used to authenticate and encrypt the connection."

```rust
use iroh::Endpoint;
use iroh_base::SecretKey;

// Generate a fresh secret key (the private part)
let secret = SecretKey::generate();

// The corresponding endpoint identifier is the public key
let endpoint_id = secret.public(); // implements EndpointId

// Build an endpoint that will authenticate using this key pair
let ep = Endpoint::builder(presets::N0)
    .secret_key(secret)            // (pseudo‑API – the builder picks up the secret internally)
    .bind()
    .await?;

```

### TLS-Wrapped QUIC Handshake

Iroh wraps QUIC connections in TLS to authenticate peers during the initial handshake. When an `Endpoint` connects to a remote peer, the QUIC layer creates a TLS session that uses the local endpoint's **SecretKey** for signing and the remote peer's **PublicKey** for verification.

This process happens automatically before any application data flows, ensuring that the peer presenting a specific `EndpointId` actually possesses the corresponding private key. The handshake verifies the public key against the curve25519/ed25519 curve, guaranteeing cryptographic proof of identity.

## Relay Authentication with Bearer Tokens

While transport-level encryption secures the connection, relay servers add an additional access control layer. According to [`iroh-relay/README.md`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/README.md), relays can require a shared secret token via either an `Authorization: Bearer <token>` HTTP header or a `?token=` query parameter.

Configure relay authentication using `RelayConfig::with_auth_token()`. The relay transport actor in [`iroh/src/socket/transports/relay/actor.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/relay/actor.rs) processes this token, attaching it to outgoing connections and validating it on incoming relay requests.

```rust
use iroh::{Endpoint, RelayConfig};

// Configure a relay with a token "my-secret-token"
let relay_cfg = RelayConfig::default()
    .with_auth_token("my-secret-token".to_string());

// Build the endpoint and tell it to use that relay
let ep = Endpoint::builder(presets::N0)
    .relay_config(relay_cfg)
    .bind()
    .await?;

```

## Application-Level Authentication Hooks

For scenarios requiring custom authorization logic, iroh provides the **EndpointHooks** trait. This system allows applications to implement `before_connect` for pre-connection checks and `after_handshake` for post-handshake verification.

The example in [`iroh/examples/auth-hook.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/auth-hook.rs) demonstrates a complete token-exchange protocol. On the outgoing side, `OutgoingAuthHook::before_connect` triggers a token check that can abort connections before they complete. On the incoming side, `IncomingAuthHook::after_handshake` validates remote identities against an `allowed_remotes` set, rejecting unauthorized peers.

```rust
use iroh::{Endpoint, endpoint::presets, protocol::Router};

mod auth;

// Outgoing side – attach the hook that will perform a pre‑auth request
let (auth_hook, auth_task) = auth::outgoing(b"my‑service‑token".to_vec());
let endpoint = Endpoint::builder(presets::N0)
    .hooks(auth_hook)                // mount the hook
    .bind()
    .await?;
let _guard = auth_task.spawn(endpoint.clone());

// Accept side – install the corresponding hook and protocol
let (incoming_hook, auth_protocol) = auth::incoming(b"my‑service‑token".to_vec());
let endpoint = Endpoint::builder(presets::N0)
    .hooks(incoming_hook)
    .bind()
    .await?;
let router = Router::builder(endpoint)
    .accept(auth::ALPN, auth_protocol)   // register the auth protocol
    .spawn();

```

## Summary

- Iroh uses **cryptographic key pairs** where the public key serves as the `EndpointId`, ensuring verifiable peer identity at the transport level.
- The **TLS-wrapped QUIC handshake** automatically verifies that peers own their claimed public keys before exchanging data.
- **Relay authentication** protects relay infrastructure using bearer tokens configured via `RelayConfig::with_auth_token()`.
- **Application-level hooks** (`EndpointHooks`) enable custom authentication protocols through `before_connect` and `after_handshake` callbacks.
- All authentication layers are implemented in the core codebase at paths like [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) and [`iroh/src/socket/transports/relay/actor.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket/transports/relay/actor.rs).

## Frequently Asked Questions

### What is an EndpointId in iroh?

An `EndpointId` is the public-facing identity of an iroh node, defined in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) as a type alias for `PublicKey`. It represents the curve25519/ed25519 public key that corresponds to the node's private `SecretKey`. This identifier serves both as the network address and the cryptographic proof of identity during the TLS handshake.

### How does iroh verify peer identity during the handshake?

Iroh verifies identity through a TLS-wrapped QUIC handshake where the connecting endpoint signs handshake data with its `SecretKey`. The receiving endpoint verifies this signature against the claimed `EndpointId` (public key). This process, described in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs), ensures that only the holder of the private key can establish connections using a specific public key identity.

### Can I add custom authentication to iroh connections?

Yes, iroh supports custom authentication through the `EndpointHooks` trait. You can implement `before_connect` to run checks before establishing a connection, or `after_handshake` to validate peers after the cryptographic handshake completes. The [`auth-hook.rs`](https://github.com/n0-computer/iroh/blob/main/auth-hook.rs) example demonstrates implementing a token-exchange protocol using these hooks to authorize peers based on application-specific secrets.

### How do I secure a relay server in iroh?

Secure your relay by configuring a shared bearer token using `RelayConfig::with_auth_token()` when building your endpoint. The relay server checks this token against the HTTP `Authorization` header or `?token=` query parameter, rejecting connections without valid credentials. According to [`iroh-relay/README.md`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/README.md), this prevents unauthorized clients from using your relay infrastructure.