# How to Add Custom Connection Hooks in Iroh for Authentication

> Add custom authentication to Iroh connections by implementing EndpointHooks. Inspect and reject connections during connection phases for enhanced security. Learn how to integrate custom connection hooks.

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

---

**You can add custom authentication to Iroh connections by implementing the `EndpointHooks` trait and registering it with `Endpoint::builder().hooks(my_hook)`, allowing you to inspect and reject connections during the `before_connect` and `after_handshake` phases.**

The n0-computer/iroh networking library provides a pluggable hook system that lets you intercept QUIC connections before and after the cryptographic handshake completes. By implementing custom connection hooks in Iroh for authentication, you can validate remote endpoint identities, inspect ALPN protocols, and abort unauthorized connections without modifying the core library.

## Understanding Iroh's Connection Hook Architecture

Iroh's endpoint architecture stores hooks in an `EndpointHooksList` and executes them sequentially during connection establishment. The hook system is defined in [`iroh/src/endpoint/hooks.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/hooks.rs) and integrated into the builder pattern in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs).

### Hook Registration and Execution Order

Hooks attach to the endpoint via the builder method `Endpoint::builder().hooks(my_hook)`. The system stores these instances in an `EndpointHooksList` and invokes them in registration order. If any hook returns `Reject`, the connection aborts immediately and subsequent hooks are skipped.

### Hook Lifecycle Callbacks

The `EndpointHooks` trait defines two async callbacks that execute at specific connection lifecycle points:

- **`before_connect(&self, remote_addr: &SocketAddr, alpn: &str) -> BeforeConnectOutcome`** – Invoked in [`iroh/src/endpoint/connection.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/connection.rs) before the QUIC handshake starts. Use this to filter by IP address or ALPN protocol.
- **`after_handshake(&self, conn: &Connection) -> AfterHandshakeOutcome`** – Invoked after the handshake completes. This provides access to the remote endpoint ID via `conn.remote_id()` and a `WeakConnectionHandle` that can be upgraded to interact with the connection.

Both return enums with `Accept` and `Reject` variants. Returning `Reject` aborts the connection and prevents later hooks from running.

## Implementing a Custom Authentication Hook

To create a custom authentication hook, define a struct to hold your validation state and implement the `EndpointHooks` trait.

### Define the Hook Struct

Store your authentication credentials or validator client in the struct:

```rust
use iroh::endpoint::{EndpointHooks, BeforeConnectOutcome, AfterHandshakeOutcome, Connection};
use std::net::SocketAddr;

struct TokenAuthHook {
    expected_token: Vec<u8>,
}

```

### Implement the EndpointHooks Trait

Use `#[async_trait::async_trait]` to implement the required methods. The `after_handshake` method receives a `&Connection` containing the authenticated remote endpoint identity:

```rust
#[async_trait::async_trait]
impl EndpointHooks for TokenAuthHook {
    async fn before_connect(
        &self,
        _remote_addr: &SocketAddr,
        _alpn: &str,
    ) -> BeforeConnectOutcome {
        // Optional: Pre-filter by IP or ALPN before cryptographic handshake
        BeforeConnectOutcome::Accept
    }

    async fn after_handshake(&self, conn: &Connection) -> AfterHandshakeOutcome {
        let remote_id = conn.remote_id();
        
        // Authentication logic: Open a QUIC stream to exchange tokens
        // or validate against pre-shared keys. Here we illustrate validation.
        if validate_peer(remote_id, &self.expected_token) {
            AfterHandshakeOutcome::Accept
        } else {
            AfterHandshakeOutcome::Reject
        }
    }
}

```

### Register the Hook with the Endpoint Builder

Install your hook when constructing the endpoint in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs):

```rust
let auth_hook = TokenAuthHook { expected_token: b"secret-token".to_vec() };

let endpoint = iroh::Endpoint::builder()
    .bind_addr("[::]:0".parse().unwrap())
    .hooks(auth_hook)
    .build()
    .await?;

```

Now every incoming connection passes through `TokenAuthHook`. If the hook returns `Reject`, the connection closes immediately and the remote side receives a handshake abort error.

## Client-Side Authentication Hooks

For mutual authentication, implement symmetrical hooks on both client and server. The repository provides a reference implementation in [`iroh/examples/auth-hook.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/auth-hook.rs) demonstrating this pattern with `auth::outgoing` and `auth::incoming` helpers that return `(hook, task)` tuples. The outgoing hook sends authentication tokens once the connection establishes, while the incoming hook validates them using the `after_handshake` callback.

## Source Code Reference

Key files in the n0-computer/iroh repository for custom authentication:

- **[`iroh/src/endpoint/hooks.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/hooks.rs)** – Defines the `EndpointHooks` trait and outcome enums (`BeforeConnectOutcome`, `AfterHandshakeOutcome`).
- **[`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)** – Contains the `Builder::hooks` method and `EndpointHooksList` storage.
- **[`iroh/src/endpoint/connection.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/connection.rs)** – Implements the invocation of `before_connect` and `after_handshake` at the correct connection lifecycle points.
- **[`iroh/examples/auth-hook.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/auth-hook.rs)** – Complete runnable example of outgoing and incoming authentication hooks.
- **[`iroh/examples/remote-info.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/remote-info.rs)** – Demonstrates maintaining per-connection state within hooks.
- **[`iroh/examples/monitor-connections.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/monitor-connections.rs)** – Shows diagnostic logging using the hook system.

## Summary

- **Register** hooks using `Endpoint::builder().hooks(my_hook)` before building the endpoint.
- **Implement** `before_connect` to filter connections early by IP address or ALPN protocol.
- **Implement** `after_handshake` to access the authenticated `remote_id` and decide whether to `Accept` or `Reject`.
- **Return** `Reject` from any hook to immediately abort the connection and prevent further processing.
- **Combine** client and server hooks for mutual authentication schemes.

## Frequently Asked Questions

### What is the difference between before_connect and after_handshake hooks?

The `before_connect` hook runs before the QUIC handshake begins and only has access to the remote socket address and ALPN string. The `after_handshake` hook runs after cryptographic verification completes and provides access to the `Connection` object, including the authenticated remote endpoint ID via `conn.remote_id()`.

### Can I access connection data inside an authentication hook?

Yes. Inside `after_handshake`, you receive a `&Connection` parameter that exposes `conn.remote_id()` and provides a `WeakConnectionHandle` that can be upgraded to a `ConnectionHandle`. This allows you to inspect peer identity and open streams for token exchange, though the actual transport of authentication data is implementation-specific.

### How do I reject a connection in Iroh?

Return `BeforeConnectOutcome::Reject` or `AfterHandshakeOutcome::Reject` from the respective hook method. This immediately aborts the connection and prevents subsequent hooks in the `EndpointHooksList` from executing, as implemented in [`iroh/src/endpoint/connection.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/connection.rs).

### Where can I find a complete example of custom authentication?

The repository includes a full implementation in [`iroh/examples/auth-hook.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/auth-hook.rs), which demonstrates both outgoing and incoming hook patterns with token validation logic. Additional examples in [`iroh/examples/remote-info.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/remote-info.rs) and [`iroh/examples/monitor-connections.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/examples/monitor-connections.rs) show how to maintain state and log connections using the same hook architecture.