Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 66 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 133 additions & 0 deletions doc/guide/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
title: moq-authentication
description: Authentication for the moq-relay
---

# MoQ authentication

The MoQ Relay authenticates via JWT-based tokens. Generally there are two different approaches you can choose from:
- asymmetric keys: using a public and private key to separate signing and verifying keys for more security
- symmetric key: using a single secret key for signing and verifying, less secure

## Symmetric key

1. Generate a secret key:
```bash
moq-token --key root.jwk generate --algorithm HS256
```
:::details You can also choose a different algorithm
- HS256
- HS384
- HS512
:::

2. Configure relay:
:::code-group
```toml [relay.toml]
[auth]
# public = "anon" # Optional: allow anonymous access to anon/**
key = "root.jwk" # JWT key for authenticated paths
```
:::

3. Generate tokens:
```bash
moq-token --key root.jwk sign \
--root "rooms/123" \
--publish "alice" \
--subscribe "" \
--expires 1735689600 > alice.jwt
```

## Asymmetric keys

Generally asymmetric keys can be more secure because you don't need to distribute the signing key to every relay instance, the relays only need to verifying (public) key.

1. Generate a public and private key:
```bash
moq-token --key private.jwk generate --public public.jwk --algorithm RS256
```
:::details You can also choose a different algorithm
- RS256
- RS384
- RS512
- PS256
- PS384
- PS512
- EC256
- EC384
- EdDSA
Comment on lines +50 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix algorithm names in the asymmetric list.
EC256/EC384 aren’t standard JWT algorithm identifiers; the usual names are ES256/ES384.

✍️ Suggested edit
-- EC256
-- EC384
+- ES256
+- ES384
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
:::details You can also choose a different algorithm
- RS256
- RS384
- RS512
- PS256
- PS384
- PS512
- EC256
- EC384
- EdDSA
:::details You can also choose a different algorithm
- RS256
- RS384
- RS512
- PS256
- PS384
- PS512
- ES256
- ES384
- EdDSA
🤖 Prompt for AI Agents
In `@doc/guide/authentication.md` around lines 50 - 59, Update the asymmetric
algorithm list to use the correct JWT identifiers: replace the occurrences of
"EC256" and "EC384" with "ES256" and "ES384" respectively in the list shown
under the "You can also choose a different algorithm" details block so the
options are RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, and EdDSA.

:::

2. Now the relay only requires the public key:
:::code-group
```toml [relay.toml]
[auth]
# public = "anon" # Optional: allow anonymous access to anon/**
key = "public.jwk" # JWT key for authenticated paths
```
:::

3. Generate tokens using the private key:
```bash
moq-token --key private.jwk sign \
--root "rooms/123" \
--publish "alice" \
--subscribe "" \
--expires 1735689600 > alice.jwt
```

## JWK set authentication

Instead of storing a public key locally in a file, it may also be retrieved from a server hosting a JWK set. This can be a simple static site serving a JSON file, or a fully OIDC compliant Identity Provider. That way you can easily implement automatic key rotation.

::: info
This approach only works with asymmetric authentication.
:::

To set this up, you need to have an HTTPS server hosting a JWK set that looks like this:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Docs should match HTTP/HTTPS behavior.
The code accepts http:// and https://, so “HTTPS server” reads stricter than the implementation. Consider softening to “HTTP(S)” with HTTPS recommended.

✍️ Suggested edit
-To set this up, you need to have an HTTPS server hosting a JWK set that looks like this:
+To set this up, you need to have an HTTP(S) server hosting a JWK set (HTTPS recommended) that looks like this:
🤖 Prompt for AI Agents
In `@doc/guide/authentication.md` at line 88, Update the sentence that currently
reads "HTTPS server hosting a JWK set" to reflect that the implementation
accepts both http:// and https://; change it to "HTTP(S) server hosting a JWK
set" or "an HTTP or HTTPS server (HTTPS recommended) hosting a JWK set" so the
docs align with the code; locate the phrase "HTTPS server hosting a JWK set" in
authentication.md and replace accordingly.

```json
{
"keys": [
{
"kid": "2026-01-01",
"alg": "RS256",
"key_ops": [
"verify"
],
"kty": "RSA",
"n": "zMsjX1oDV2SMQKZFTx4_qCaD3iIek9s1lvVaymr8bEGzO4pe6syCwBwLmFwaixRv7MMsuZ0nIpoR3Slpo-ZVyRxOc8yc3DcBZx49S_UQcM76E4MYbH6oInrEP8QL2bsstHrYTqTyPPjGwQJVp_sZdkjKlF5N-v5ohpn36sI8PXELvfRY3O3bad-RmSZ8ZOG8CYnJvMj_g2lYtGMMThnddnJ49560ahUNqAbH6ru---sHtdYHcjTIaWX4HYP6Y_KjA6siDZTGTThpaEW45LKcDQWM9sYvx_eAstaC-1rz8Z_6fDgKFWr7qcP5U2NmJ0c-IGSu_8OkftgRH4--Z5mzBQ",
"e": "AQAB"
},
{
"kid": "2025-12-01",
"alg": "EdDSA",
"key_ops": [
"verify"
],
"kty": "OKP",
"crv": "Ed25519",
"x": "2FSK2q_o_d5ernBmNQLNMFxiA4-ypBSa4LsN30ZjUeU"
}
]
}
```

:::tip The following must be considered:
- Every JWK MUST be public and contain no private key information
- If your JWK set contains more than one key:
1. Every JWK MUST have a `kid` so they can be identified on verification
2. Your JWT tokens MUST contain a `kid` in their header
3. `kid` can be an arbitrary string
:::

Configure the relay:
:::code-group
```toml [relay.toml]
[auth]
# public = "anon" # Optional: allow anonymous access to anon/**

key = "https://auth.example.com/keys.json" # JWK set URL for authenticated paths
refresh_interval = 86400 # Optional: refresh the JWK set every N seconds, no refreshing if omitted
```
:::
2 changes: 1 addition & 1 deletion rs/moq-relay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ futures = "0.3"
http-body = "1"
moq-lite = { workspace = true, features = ["serde"] }
moq-native = { workspace = true, features = ["aws-lc-rs"] }
moq-token = { workspace = true }
moq-token = { workspace = true, features = ["jwks-loader"] }
rustls = { version = "0.23", features = [
"aws-lc-rs",
], default-features = false }
Expand Down
Loading
Loading