Skip to content
Merged
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
75 changes: 75 additions & 0 deletions doc/library-development/ADRs/relay-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Architecture Decision Record: Relay authentication

Title: Relay authentication - who a query, subscription or broadcast authenticates as

## status

accepted

Updated on 2026-09-02

## contributors

- Main contributor(s): nogringo

- Reviewer(s): frnandu, 1leo

- Final decision made by: frnandu, 1leo, nogringo

## Context and Problem Statement

A connection carries at most one identity, immutable for its whole lifetime
(`RelayConnectionKey`). The caller-facing half is missing: `authenticateAs: List<Account>?`
cannot say "never be attributable for this request", nor "authenticate before asking".

And the absent case is the leaky one. With no `authenticateAs`, a request that meets
`auth-required` falls back to the logged account, so the relay decides when an identity is
revealed.

## Main Proposal

### RelayAuth

```dart
sealed class RelayAuth {
const factory RelayAuth.never(); // (url, null), never sends AUTH
const factory RelayAuth.allow(Account a); // (url, null), moves to (url, a) if refused
const factory RelayAuth.require(Account a); // (url, a) from the start
}

ndk.broadcast.broadcast(
nostrEvent: report,
auth: const RelayAuth.never(),
);
```

### RelayAuthHandler

```dart
typedef RelayAuthHandler = Future<Account?> Function(RelayAuthRequest);

sealed class RelayAuthRequest {
final String relayUrl;
final Account? account;
final AuthRefusal? refusal; // null when asked before any refusal
}

class ReadAuthRequest extends RelayAuthRequest {
final Filter? filter;
final String? requestName;
}

class WriteAuthRequest extends RelayAuthRequest {
final Nip01Event event;
}

class AuthRefusal {
final AuthReason reason; // authRequired, restricted, blocked, rateLimited
final String message; // raw relay message
}
```

Configured once on the NDK config, consulted only for `allow` and `require`. With no handler,
both authenticate automatically.

Returning `null` means do not authenticate.
Loading