Skip to content

Add relay access requests#1079

Merged
fiatjaf merged 3 commits into
nostr-protocol:masterfrom
coracle-social:claims
Oct 30, 2025
Merged

Add relay access requests#1079
fiatjaf merged 3 commits into
nostr-protocol:masterfrom
coracle-social:claims

Conversation

@staab

@staab staab commented Feb 23, 2024

Copy link
Copy Markdown
Member

The use case here is private relays that can be joined by a user with minimal friction. The idea is that a user can auth using an invite code instead of a challenge. Relays should then save that code and use the normal challenge flow in the future. Currently implemented in Coracle and Triflector/Khatru.

@vitorpamplona

vitorpamplona commented Feb 23, 2024

Copy link
Copy Markdown
Collaborator

Are you using claim just because the challenge has different semantics like the one below?

The challenge is valid for the duration of the connection or until another challenge is sent by the relay.

For clients, it doesn't matter if it is a claim or challenge. They could be just one tag. If the challenge comes from the relay in one connection, its duration is for the connection. If the challenge comes from an external source, the challenge might be long-lived.

I assume relays store the claim and as soon as somebody joins with a valid claim, it accepts that pub key as invited. That could work with challenge as well. As long as the relay has it stored somewhere, it doesn't need to be the temporary challenge it creates for the connection.

I am not sure what is the benefit of separating the two.

Otherwise, looks good.

@staab

staab commented Feb 23, 2024

Copy link
Copy Markdown
Member Author

Interesting. I've gone through about 4 designs with "claim" before getting here, so it hadn't occurred to me that they could be the same thing. But I think it would be good to keep them separate, because a claim grants access, while a challenge only prevents replay attacks.

@fiatjaf

fiatjaf commented Feb 24, 2024

Copy link
Copy Markdown
Member

Why not use a different dedicated event kind and send these claims with a simple ["EVENT", ...]?

I imagine the idea behind using AUTH is that these events won't be broadcasted, but a relay that supports the claim protocol would also not broadcast these events -- and even if it did the claim would already have been claimed at the time anyone else got it.

@monlovesmango

monlovesmango commented Feb 25, 2024

Copy link
Copy Markdown
Member

just created #1082 for authentication delegation. I think could accomplish what you are trying to doing with claim? but is also supposed to be more general purpose and extensible as we think of new things we want to delegate authentication for.

didn't properly understand claims

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

Why not use a different dedicated event kind and send these claims with a simple ["EVENT", ...]?

I imagine the idea behind using AUTH is that these events won't be broadcasted, but a relay that supports the claim protocol would also not broadcast these events -- and even if it did the claim would already have been claimed at the time anyone else got it.

I originally did add a new event kind, but switched to auth because of broadcasting. It's up to relays to decide whether they want to invalidate claims, the use case I'm working on uses static/reusable invite codes, so broadcasting the join even would be bad. It could be ok to use a new event kind though, since relays that support the nip wouldn't broadcast, and they'd be the only ones receiving such events unless there is a client bug. I'll look into making that work with khatru.

@monlovesmango

Copy link
Copy Markdown
Member

I think new event kind makes sense, but why not send it back in a ["AUTH", ...] message instead? would prevent non-supporting relays from storing these, and would fit into supporting relays' auth flow better.

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

I also went down that path, but it's much harder to add support to relays for new verbs than for new events.

@monlovesmango

Copy link
Copy Markdown
Member

for relays that have not implemented the "AUTH" verb, what use case do claims have?

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

for relays that have not implemented the "AUTH" verb, what use case do claims have?

None, I had originally used a new JOIN verb, should have explained that.

@fiatjaf I went back to using a new event kind. The re-broadcasting scenario is handled by making the client check the NIP 11 document for support before sending.

@monlovesmango

Copy link
Copy Markdown
Member

for relays that have not implemented the "AUTH" verb, what use case do claims have?

None

then why not use "AUTH" verb instead? if you use "EVENT", relays will have to add access handling to "EVENT" messages and clients are forced to check NIP11.

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

It actually adds a lot of complexity. Auth is invalid if there is no claim, and no challenge, but it can be valid if either is valid, but what if one is invalid? Using a separate verb or event is much cleaner.

@monlovesmango

Copy link
Copy Markdown
Member

how is "AUTH" with new event kind more complex than "EVENT" with new event kind? the only difference between the two is that "EVENT" handling will now need to inject itself into access control flow and for un-authenticated connections it will now have to check the event kind before being able to reject the event.

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

That's something that happens anyway when requesting DMs etc for a particular user, auth is triggered based on event inspection.

@monlovesmango

Copy link
Copy Markdown
Member

requesting DMs would use "REQ" message, not "EVENT" message.

right now authenticated relays can automatically reject any "EVENT" message if connection is not authenticated. this would add additional logic there. not the end of the world, but using new event kind with "AUTH" message would be simpler and make more sense from design perspective (since claim use case only applies to authenticated relays).

@staab

staab commented Feb 26, 2024

Copy link
Copy Markdown
Member Author

requesting DMs would use "REQ" message, not "EVENT" message.

Right, confused myself, but the same is true about selectively accepting events.

using new event kind with "AUTH" message

I finally understand what you're saying, this does actually make sense. You're saying use the AUTH verb with the new event, and the broadcast policy will already be in place?

@monlovesmango

Copy link
Copy Markdown
Member

yes!

@staab

staab commented Feb 28, 2024

Copy link
Copy Markdown
Member Author

Interesting. I suppose that doesn't seem any worse than anything else, but I don't think we can assume that relays will handle a new event kind properly. @fiatjaf told me, and I think I agree, that he thinks the AUTH verb was a mistake (at least the one that clients publish), because it doesn't really carry any semantics on its own. This is especially true if we add more kinds to the auth verb. I'm inclined to use EVENT, and not expand the weirdness of what AUTH means.

@alexgleason

Copy link
Copy Markdown
Member

I was planning to also do something very similar to this. But I was thinking of doing a DVM flow so you can get feedback events including the ability to charge for access.

@staab

staab commented Feb 28, 2024

Copy link
Copy Markdown
Member Author

You're saying the DVM would be in the relay? I like that a lot.

@alexgleason

Copy link
Copy Markdown
Member

You're saying the DVM would be in the relay? I like that a lot.

Yes exactly. It would work really well for this. Invite code is an optional param. Feedback events are also basically needed for a flow like this, because they could demand an access code (or not), or tell you if the access code expired, or any number of other things. Then you also get the "success" event baked into the flow.

Check also: nostr-protocol/data-vending-machines#25

In Ditto, a traditional "registration" would be a combination of a NIP05 request and a relay access request.

@vitorpamplona

vitorpamplona commented Feb 28, 2024

Copy link
Copy Markdown
Collaborator

Doing authorization tasks via events makes more sense than coding separate schemes in the Nostr protocol. Claim is an authorization protocol, not authentication. Authentication probably should remain in the core protocol, but authorization can be managed by a separate DVM-like thing.

But maybe the DVM spec is too general and not general enough for authorization. Making a NIP designed to run "jobs" into a more general "bot that replies to stuff" is challenging and one of the reasons NIP-46 and NIP-47 are not DVMs.

@alexgleason

Copy link
Copy Markdown
Member

DVMs in the 59xx range are appropriate for just about anything that would normally be done over HTTP (request and response), except even better because you can get multiple responses over an extended period of time.

@vitorpamplona

vitorpamplona commented Feb 28, 2024

Copy link
Copy Markdown
Collaborator

Yes, but HTTP-like calls fit just the bare minimum of computer science needs. In practice, it's more like forcing everything to be async, atomic, and UDP-like (DVMs might not reply to a request). Sure, devs can make anything work in that setting, you just need to deal with the side effects manually.

For instance, there is no concept of a transaction involving multiple calls. The way we solved it via DVMs was to have a temporary replaceable event kind to assemble the atomic call. Multiple DVM requests change that event and clients can watch the event changing to make sure the DVM processed the request. When everything is ready, the user can hit the button and make another DVM run the replaceable event atomically. It's like coding in Assembly in 2024.

Authorization in production is one of these things that frequently requires adjusting many permissions in an all-or-nothing way.

@alexgleason

Copy link
Copy Markdown
Member

@vitorpamplona I think I understand what you're saying, but is it actually a response to using a NIP-90 flow for registering an account on a relay? If so I don't get the objection to it, if any. It seems like you're just saying you can't use DVMs to do literally everything. But you can use it for this.

@vitorpamplona

vitorpamplona commented Feb 28, 2024

Copy link
Copy Markdown
Collaborator

Yes. It's not an objection. It's just like sometimes we use the word DVM to represent any type of Bot in Nostr for lack of a better term. And blindly applying the concept of DVMs into these bots can sometimes create more problems than solutions.

@vitorpamplona

vitorpamplona commented Feb 28, 2024

Copy link
Copy Markdown
Collaborator

However, I have to say that I don't like the idea of bloated relays (relay + DVM together) in general. I think they are inevitable for some applications but it's way too centralizing, giving too much power to relay operators, for my taste.

Case in mind: A hospital's private relay that no one outside the hospital has access to is not that different from the massively centralized EHRs we have today in the US. Nostr is not really helping anything over there.

@fiatjaf

fiatjaf commented Oct 16, 2024

Copy link
Copy Markdown
Member

I like this but now I don't understand what is the difference between 28934 and 28935. Also how can you claim access to anything with an invoice? If you're paying to join the relay shouldn't the relay be giving you the invoice and you be paying it?

Maybe add a more concrete flow example of how and when the events can be used to help others that are as stupid as I.

@staab

staab commented Oct 16, 2024

Copy link
Copy Markdown
Member Author

They're basically the same event, and you could use the same kind for both, but semantically they're different so I opted for a new kind. In the case of an invite, you'd do a REQ for a 28935, share the url+claim (rather than the event), and then it could be used as the payload of a 28934 sent to that same relay. For invoices, you'd do the same thing, but pay the invoice before sending the claim. The relay would then look up the invoice and see whether it was paid. But I'm not sure about that flow, it's not something I'm currently working on, and overloading the claim field would require parsing the claim, which seems like a bad idea to me.

@staab

staab commented Oct 16, 2024

Copy link
Copy Markdown
Member Author

I've removed the invoice stuff, we can add new use cases with new tags if we need them.

@fiatjaf

fiatjaf commented Oct 16, 2024

Copy link
Copy Markdown
Member

So Bob does a REQ for a 28935, the relay supposedly gives him a thing it just generated on the fly, Bob takes the claim tag out of that, then shares it with Alice, Alice makes a 28935 with that claim tag and sends to the relay as an EVENT?

Looks pretty good to me.

@staab

staab commented Sep 30, 2025

Copy link
Copy Markdown
Member Author

Updated to include membership lists, join/remove events, and leave requests (like nip 29).

@staab

staab commented Oct 27, 2025

Copy link
Copy Markdown
Member Author

@fiatjaf

fiatjaf commented Oct 29, 2025

Copy link
Copy Markdown
Member

I don't understand one thing: if you get an invite 28934 by querying the relay, how can you get a 28935 later in order to use that invite? The spec says the 28935 must be signed by the relay key.

@staab

staab commented Oct 29, 2025

Copy link
Copy Markdown
Member Author

It sounds like you have the kinds backwards, 28935 are requested from the relay and include an invite code, which can later be used as the claim in a 28934 which is signed by the user and sent to the relay.

@fiatjaf

fiatjaf commented Oct 29, 2025

Copy link
Copy Markdown
Member

You are totally right!

I got confused, but still my question is: who signs the event that is sent when claiming the access?

@fiatjaf

fiatjaf commented Oct 29, 2025

Copy link
Copy Markdown
Member

Should clients rely on 43 being signaled in NIP-11 before they display a "create invite" button?

@staab

staab commented Oct 29, 2025

Copy link
Copy Markdown
Member Author

I got confused, but still my question is: who signs the event that is sent when claiming the access?

The relay who wants to issue a claim is the one who signs the 28935 with the relay's self pubkey. The 28935 should include a newly generated (or cached, or static) claim tag that can be shared. The user who wants to gain access is the one who signs the 28934 with the previously shared claim tag.

Should clients rely on 43 being signaled in NIP-11 before they display a "create invite" button?

It depends, in flotilla I generate an invite link without a claim if nip 43 isn't supported and tell the user who requested it that "additional steps might be required".

Comment thread 43.md Outdated
Comment thread 43.md
@staab

staab commented Oct 29, 2025

Copy link
Copy Markdown
Member Author

Pushed an update with slightly modified versions of your suggestions

@fiatjaf

fiatjaf commented Oct 30, 2025

Copy link
Copy Markdown
Member

This is implemented in https://github.com/fiatjaf/pyramid now.

@fiatjaf
fiatjaf merged commit 8054526 into nostr-protocol:master Oct 30, 2025
pats2sats pushed a commit to sudonym-btc/accommodation-nip that referenced this pull request May 20, 2026
Co-authored-by: Jonathan Staab <shtaab@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants