What is an EndpointId in Iroh?
An EndpointId in Iroh is the unique cryptographic identifier of an endpoint, implemented as a type alias for the Ed25519 public key that authenticates all peer-to-peer connections and enables secure routing across the network.
The n0-computer/iroh distributed systems framework uses the EndpointId as the canonical identity primitive for every network participant. Derived directly from an endpoint's cryptographic keypair, this identifier ensures global uniqueness without centralized coordination and appears in all connection establishment flows, from direct peer dialing to relay-assisted NAT traversal.
EndpointId Definition and Cryptographic Foundation
The EndpointId is fundamentally a type alias for the PublicKey structure. According to the iroh source code in iroh-base/src/key.rs (lines 58-70), it is defined as:
pub type EndpointId = PublicKey;
The underlying PublicKey represents a compressed Ed25519 public key (specifically the compressed Y coordinate), providing 128-bit security and global uniqueness. Because the identifier derives from asymmetric cryptography, you can share it openly for routing purposes without exposing the private SecretKey used to prove ownership.
How Iroh Generates the EndpointId
Endpoint generation occurs during the binding phase of the Builder API. When you invoke Endpoint::builder().bind().await in iroh/src/endpoint.rs (lines 24-27), the system executes the following sequence:
- Secret Key Generation – If the user does not supply a secret key via
Builder::secret_key, the system invokesSecretKey::generate()to create a cryptographically secure Ed25519 keypair. - Public Key Derivation – The builder calls
SecretKey::public()to derive the corresponding public key. - Identifier Assignment – This public key becomes the endpoint's permanent EndpointId.
Once constructed, the Endpoint::id() method (defined in iroh/src/endpoint.rs, lines 66-72) returns this identifier on demand:
pub fn id(&self) -> EndpointId {
self.public_key()
}
Working with EndpointId in Practice
Retrieving and displaying your endpoint's identifier requires only a few lines of Rust. The following example demonstrates creating an endpoint, extracting its EndpointId, and preparing to connect to a remote peer:
use iroh::{Endpoint, endpoint::presets};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Build endpoint with default configuration (generates fresh secret key)
let ep = Endpoint::builder(presets::N0).bind().await?;
// Retrieve the EndpointId (PublicKey)
let id = ep.id();
println!("My EndpointId: {}", id); // Hex-encoded public key
// Form an EndpointAddr to dial a remote peer
// let remote_id: iroh_base::EndpointId = ...;
// let addr = iroh_base::EndpointAddr::from_parts(remote_id, vec![]);
// let conn = ep.connect(addr, b"my-alpn").await?;
Ok(())
}
The Display implementation for PublicKey renders the EndpointId as a hexadecimal string, making it easy to log, share, or serialize for discovery services.
EndpointId in Network Addresses and TLS Verification
Every network-level address in Iroh explicitly includes the EndpointId to ensure cryptographic authentication during connection establishment. The EndpointAddr struct, defined in iroh-base/src/endpoint_addr.rs (lines 42-46), couples the identifier with optional relay and direct IP addresses:
pub struct EndpointAddr {
pub id: EndpointId,
// ... relay and direct addresses
}
When establishing TLS connections, Iroh encodes the EndpointId into DNS names for certificate verification. The iroh::tls::name module (in iroh/src/tls/name.rs) handles this encoding, allowing the TLS stack to verify that the connecting peer actually possesses the private key corresponding to the expected EndpointId.
Summary
- EndpointId is a type alias for
PublicKeydefined iniroh-base/src/key.rs, representing the compressed Ed25519 public key of an endpoint. - Generation occurs automatically during
Builder::bindiniroh/src/endpoint.rs, deriving the identifier from a freshly generated or user-suppliedSecretKey. - The
Endpoint::id()method provides runtime access to the identifier, which displays as a hex string via theDisplaytrait. - EndpointAddr structures always contain an EndpointId to ensure secure routing, and the identifier participates in TLS certificate verification via DNS name encoding.
Frequently Asked Questions
Is the EndpointId sensitive information?
No. The EndpointId is the public component of your cryptographic identity and is designed to be shared freely with other peers. Only the SecretKey (the private component) must remain confidential, as it proves ownership of the EndpointId and authorizes connections.
How do I share my EndpointId with other peers?
You can serialize the EndpointId using its Display implementation to obtain a hexadecimal string, or use standard serialization libraries. Other peers need this identifier to construct an EndpointAddr when calling Endpoint::connect to reach your node.
Can I reuse the same EndpointId across application restarts?
Yes, but only if you persist and reload the same SecretKey. The EndpointId is deterministically derived from the secret key; generating a fresh secret key (the default behavior when none is provided to the Builder) creates a new random EndpointId. To maintain a stable identity, use Builder::secret_key to supply a persisted secret key when constructing the endpoint.
What is the relationship between EndpointId and EndpointAddr?
The EndpointId is the cryptographic identity component, while EndpointAddr is the complete network address that includes both the EndpointId and routing information (IP addresses or relay URLs). You cannot establish a connection with only an IP address; Iroh requires the EndpointId to authenticate the remote peer during the cryptographic handshake.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →