What is an EndpointId in Iroh? A Developer's Guide to Peer Identity

The EndpointId is the unique cryptographic identifier of an iroh endpoint, represented as a type-alias for the endpoint's Ed25519 public key.

Iroh is a peer-to-peer networking library that uses cryptographic identities to authenticate and route connections between nodes. The EndpointId serves as the fundamental identity mechanism in the Iroh ecosystem, acting as both a public identifier and the foundation for secure communication. Understanding how this identifier is generated and used is essential for building applications with the n0-computer/iroh framework.

What is an EndpointId in Iroh?

The EndpointId is the canonical identifier for an iroh endpoint. Internally, it is nothing more than a type alias for the endpoint's public key, but this simplicity masks its critical role in the network's security architecture.

Defining the EndpointId

In the Iroh codebase, the EndpointId is defined as a direct alias for the PublicKey type. According to the source code in iroh-base/src/key.rs, the type definition is straightforward:

pub type EndpointId = PublicKey;

This definition appears at lines 58-70 in key.rs, where PublicKey represents a compressed Ed25519 public key (specifically the compressed Y coordinate). By using a type alias, Iroh creates a semantic distinction between generic public keys and those specifically used to identify endpoints, while maintaining the same underlying cryptographic properties.

How EndpointId is Generated

When you create an endpoint using the builder pattern, the EndpointId is derived from the secret key. In iroh/src/endpoint.rs at lines 24-27, the Builder::bind method handles key generation:

  1. If no secret key is provided by the user, the builder generates a fresh one using SecretKey::generate().
  2. The public key is derived from this secret key via SecretKey::public().
  3. This public key becomes the EndpointId for the lifetime of the endpoint.

This generation process ensures that every EndpointId is globally unique and cryptographically secure, as it is backed by a randomly generated Ed25519 key pair.

How EndpointId is Used in Iroh

The EndpointId serves multiple critical functions within the Iroh networking stack, from basic identification to complex TLS verification.

Endpoint Identification

Each Endpoint instance exposes its identity through the id() method. As implemented in iroh/src/endpoint.rs at lines 66-72, calling ep.id() returns the EndpointId:

// Returns the EndpointId (which is the PublicKey)
pub fn id(&self) -> EndpointId {
    self.endpoint_id
}

This method allows applications to display their own network identity or share it with other peers that need to establish connections.

Connection Establishment

To connect to a remote peer, you must know its EndpointId. The identifier is embedded within EndpointAddr, which combines the EndpointId with network addressing information. As defined in iroh-base/src/endpoint_addr.rs at lines 42-46, the EndpointAddr struct always contains an EndpointId:

pub struct EndpointAddr {
    pub id: EndpointId,
    pub addrs: Vec<SocketAddr>,
    pub relay_url: Option<RelayUrl>,
}

When calling Endpoint::connect, you provide an EndpointAddr that includes the target peer's EndpointId. This identifier is used to authenticate the remote peer during the cryptographic handshake, ensuring you are connecting to the intended node and not an intermediary or attacker.

TLS Verification

Beyond routing, the EndpointId plays a crucial role in transport layer security. The Iroh team implements TLS certificate verification using the EndpointId as the subject name. In iroh/src/tls/name.rs, the EndpointId is encoded as a DNS name using iroh::tls::name::encode, allowing the TLS layer to verify that the certificate presented by a remote peer matches their claimed EndpointId.

This approach eliminates the need for centralized certificate authorities, instead using the self-authenticating properties of Ed25519 public keys.

Code Example: Working with EndpointId

Below is a practical example demonstrating how to create an endpoint, retrieve its EndpointId, and prepare to connect to a remote peer:

use iroh::{Endpoint, endpoint::presets};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build a default endpoint (generates a fresh secret key)
    let ep = Endpoint::builder(presets::N0).bind().await?;

    // Retrieve the Endpoint Id (public key)
    let id = ep.id();
    println!("My Endpoint Id: {}", id); // hex encoding of the public key

    // Use the id to connect to a remote peer (requires the remote's EndpointId)
    // let remote_id: iroh_base::EndpointId = …;
    // let remote_addr = iroh_base::EndpointAddr::from_parts(remote_id, vec![]);
    // let conn = ep.connect(remote_addr, b"my-alpn").await?;
    Ok(())
}

In this example, Endpoint::builder(presets::N0).bind().await? creates an endpoint with a newly generated secret key, automatically deriving the EndpointId. The ep.id() call returns the EndpointId (which is a PublicKey), which implements Display for convenient hex output. To dial another peer, you would construct an EndpointAddr using their EndpointId, ensuring cryptographically authenticated connections.

Summary

  • EndpointId is a type alias: Defined as pub type EndpointId = PublicKey; in iroh-base/src/key.rs, representing the Ed25519 public key.
  • Cryptographic generation: Created when Builder::bind executes, either from a user-supplied secret key or a freshly generated one via SecretKey::generate().
  • Self-authenticating identity: Used in EndpointAddr for routing and embedded in TLS certificates for verification without centralized authorities.
  • Retrieval: Accessed via the Endpoint::id() method, which returns the public key identifier assigned during endpoint construction.

Frequently Asked Questions

Is the EndpointId in Iroh the same as a public key?

Yes, the EndpointId is technically a type alias for PublicKey. According to the source code in iroh-base/src/key.rs, the definition pub type EndpointId = PublicKey; means they are identical types, but the alias provides semantic clarity that this specific public key represents an endpoint's identity.

How do I get the EndpointId of my local endpoint?

Call the id() method on your Endpoint instance. As implemented in iroh/src/endpoint.rs at lines 66-72, ep.id() returns the EndpointId that was generated during the binding process. This returns the public key corresponding to the secret key held by your endpoint.

Can I reuse an EndpointId across different sessions?

Yes, if you reuse the same secret key. The EndpointId is derived from the secret key's public component, so if you provide an existing secret key to Endpoint::builder instead of generating a new one, you will obtain the same EndpointId. However, if you let the builder generate a random key (the default behavior), you will get a unique EndpointId every time.

Why does Iroh use EndpointId instead of IP addresses for peer identification?

IP addresses can change, are subject to NAT, and provide no authentication. The EndpointId provides a stable, globally unique, and self-authenticating identifier that remains constant regardless of network topology changes. This enables secure peer-to-peer connections where the cryptographic key proves identity, rather than relying on network location or centralized certificate authorities.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →