Protect your relays
by Rae McKelveyManaged relays on Iroh Services are now authenticated by default. Only endpoints carrying a token issued by your project's API key can use them.
There's nothing to switch on. If you already connect through the
iroh_services preset, your endpoints authenticate themselves.
Why a relay needs a door
When two devices can't get a direct connection for whatever reason, a relay carries the connection so data still flows. The public relays we run at number0 handle this for free, on a best-effort basis, shared by everyone.
An unauthenticated relay is an open door. Anyone who learns the URL can point their endpoints to it start sending traffic through it.
If you run your own relays, you can set up your own authentication scheme - iroh is unopinionated about that.
But until now, we did not have an easy to authenticate endpoints to relays on the iroh services managed dedicated relays, and ensure you control who connects to them.
Deploy a dedicated relay, free for 30 days.
How it works
Every relay connection starts with an HTTP handshake, the same one that upgrades to the websocket. Authentication travels in a standard header:
Authorization: Bearer
The token is a signed capability token. It carries four things:
- who issued it: your project's API key
- who it's for: the public key of the endpoint presenting it
- what it grants: permission to use the relay, and nothing else
- when it expires: can be set to a short time window, so if it is compromised it can't be used for long
When an endpoint connects, iroh's relay handshake first proves the endpoint actually owns its key. It does this for every connection, authenticated or not. Then the relay checks the token: is the signature valid, is it unexpired, does it grant relay use, is it addressed to this exact endpoint, and was it issued by one of your project's API keys? If every answer is yes, the endpoint is admitted.
Two properties fall out of this that we like.
A leaked URL is harmless. Without a token issued by your API key, dialing it gets you nothing.
A leaked token enables connections, but not impersonations. The token is addressed to one specific endpoint's public key, so presenting it from a different endpoint fails: the handshake would still have to prove ownership of that endpoint's secret key, which the token alone does not give you.
Revocation follows the same path. Your API key is the identity the relay recognizes, so rotating or deleting a key stops honoring tokens it issued, and connections riding those tokens are dropped.
Connecting an endpoint
You don't assemble any of this by hand. The iroh_services preset mints the token from your API secret and attaches it to every relay connection for you. Building an authenticated endpoint is the same few lines you would write anyway:
use iroh::Endpoint;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let preset = iroh_services::preset()
.relays(["https://us-east1.your-project.iroh.link"])?
.api_secret_from_env()? // reads IROH_SERVICES_API_SECRET
.build()?;
// The endpoint now reaches your managed relays, authenticated.
let endpoint = Endpoint::bind(preset).await?;
Ok(())
}
Your API secret never leaves your process. The preset uses it to derive a relay-scoped token, and that derived token is what travels to the relay. Point .relays(...) at the relay URLs from your project dashboard, set IROH_SERVICES_API_SECRET, and that's it.
What's next
Today, each endpoint gets the same capabilities. In the future, we'll add the ability to mint tokens with different scopes, so you can grant some endpoints more permissions than others. Additionally, we will be allowing you to revoke access to endpoints individually, and an API to do all of this outside of the dashboard. If any of this sounds interesting to you, please reach out on Discord and let us know.
If you're running relays today, deploy at least two in different regions so one region going down doesn't strand your endpoints. The managed relays guide walks through the full setup.
Questions, or want to talk through your relay setup? Join us on Discord or schedule a call with us. We love to talk about relays, and we want to make sure you get the most out of them.
To get started, take a look at our docs, dive directly into the code, or chat with us in our discord channel.