Conversation
|
Why does the client need to re-try after auth if they already sent the message? Adding a reason for auth challenge is not a terrible idea, but relays should buffer pending messages per connection until auth is taken care of. I feel like we need a better problem statement, this feels like a band-aid. Maybe auth needs to be re-worked from first principles. Some user stories off the top of my head:
We've talked about |
|
Buffering is great for the client.
The only problem I see is: for how long should the relay wait for a client-AUTH response before timing out and sending a premature EOSE (or failure OK message)? What if the NIP-07 extension asks user's permission to sign an auth event and it takes 2 min to choose? Example: Client sends a broad filter That's why i thought it could be better for the relay to release the DB connection, send an AUTH referencing the subscription id, which the client could consider a failed REQ it should retry after replying with AUTH. |
Why can't it release the DB connection and keep a queue of requests not yet handled that it references once AUTH comes in? |
|
If client asked for 1000 events, relay sent 10 then it found out the 11th event needs authentication, what the relay is supposed to do? If it releases the DB connection its gonna have to re-run the query from the start after client authenticates and the query result may have changed a bit in the meantime. Well it could kinda work if the relay stores the event ids it had already sent to the client to skip them. |
|
My previous example takes into account the fact that not always the relay will be able to tell if a filter would fetch an event that needs authentication (e.g.: a kind 4 event may appear even for filters without If the relay don't use a type of DB streaming, it would be holding all the 990 events (from above example) in memory until client authenticates. Or it would have to re-run the full query. If the relay is gonna have to re-run the query anyway, using this PR makes it so the relay code doesn't change much and the responsibility to ask to re-run the query is shifted to the client. But if you guys think buffering is better I can change the text. |
42.md
Outdated
| - `["AUTH", <challenge-string>, "sub:<subscription_id>"]`: It references a previous client `REQ` message with a specific subscription id as third array element. | ||
| It means client subscription requested atleast one event that requires prior authentication to be accessed. | ||
| MUST be sent before the `EOSE` message with same subscription id. The relay SHOULD send no events before `EOSE` because the client is expected to retry the `REQ` after authentication; | ||
| - `["AUTH", <challenge-string>, "evt:<event_id>"]`: It references a previous client `EVENT` message with a specific event id as third array element. |
There was a problem hiding this comment.
Can we separate the third argument into command and identifier? That way the AUTH message payload more explicitly points to a specific command that triggered auth. This could be extended cleanly to other things, like HASH or COUNT for example. So something like:
["AUTH", <challenge-string>, "REQ", <subscription_id>]
["AUTH", <challenge-string>, "EVENT", <event_id>]
| *Note: The challenge string is the same during the whole WebSocket connection. Multiple relay `AUTH` messages on the same connection | ||
| carry the same challenge string.* |
There was a problem hiding this comment.
I admit this is theoretical, but I think it could be useful to authenticate multiple times during a session without closing the connection and re-opening it (although that's probably a fine approach too). What about this:
The challenge string SHOULD be the same for the duration of the client session. Relays MAY change the challenge string if they wish to indicate that a new session with different authentication requirements has been initiated (for example when changing identities or making a claim with a separate identity).
For now, it's probably best to just keep this open-ended and say:
The challenge string SHOULD be the same for the duration of the client session.
Separately, it would be good to clarify that the relay can send multiple AUTH messages specifying different messages the client attempted to send:
Relays SHOULD issue the same challenge multiple times, each time indicating a different message the client has sent that was not accepted due to AUTH.
There was a problem hiding this comment.
...for example when changing identities...
I think this was ditched in the past in favor of simply reconnecting. For example, #891 shouldn't be used as a way of switching accounts.
I prefer lowering complexity but I will change it to your version as a middle ground.
There was a problem hiding this comment.
I prefer lowering complexity but I will change it to your version as a middle ground.
No, I think we should leave this out for now. I think we'll want it eventually, but it's better to hew to YAGNI when possible. Re-connecting is a fine way to solve this in the near term.
There was a problem hiding this comment.
Ok didn't change it
|
See my comment on #846, I think there's complexity in either direction, and this is probably the better approach. |
42.md
Outdated
| If applicable, it MUST be sent right after WebSocket `connection`. | ||
| Client may have already sent a message before receiving this one, in that case relay MUST also send an `AUTH` message in one of the other forms below; | ||
| - `["AUTH", <challenge-string>, "sub:<subscription_id>"]`: It references a previous client `REQ` message with a specific subscription id as third array element. | ||
| It means client subscription requested atleast one event that requires prior authentication to be accessed. |
There was a problem hiding this comment.
can we change this to "It means client subscription potentially requested at least one event"?
relays shouldn't be expected to run queries which could require auth. if clients are writing properly restricted filters, this should be easy for relays to immediately discern whether authentication is needed. if client's filters are too broad (ie don't specify kind) then that should be the client's problem, not the relay's problem.
42.md
Outdated
| MUST be sent before the `EOSE` message with same subscription id. The relay SHOULD send no events before `EOSE` because the client is expected to retry the `REQ` after authentication; | ||
| - `["AUTH", <challenge-string>, "evt:<event_id>"]`: It references a previous client `EVENT` message with a specific event id as third array element. | ||
| It means relay requires authentication before publishing any or atleast this kind of event. | ||
| MUST be sent before `OK` message with same event id. |
There was a problem hiding this comment.
the behavior here should be consistent with REQ auth flow. can we add "Client is expected to retry the EVENT after authentication"?
also maybe specify that OK message should have value of false.
|
agree with @staab this is the better approach of the two PRs. thanks for your persistence in trying to improve nip42 @arthurfranca ! |
5a49f01 to
0ccad0f
Compare
|
@arthurfranca @mikedilger @staab instead of changing It could be something like or (The fourth parameter would depend on the reason prefix of the third or something like that). |
|
Not bad. But what if a paid relay requires auth for everything, including EVENT and COUNT? |
|
OK, so we can forget about the fourth parameter, this makes things even easier: query: publishing an event: Clients can just store a single Receiving a |
|
whats the advantage of this strategy over adding third auth element? if you think we need some kind of "NO" message anyway and this is a good place to utilize it I would tend to agree. rather than "NO" I think "ERR", "FAIL", "REJ", or "DENIED" would be more descriptive message labels. might also be beneficial to have standardized error codes so clients can handle different errors precisely? otherwise people will likely start writing whatever messages they want when rejecting a REQ (as some NOTICEs are actually more appropriate as a REQ rejection). |
I wouldn't mind a more completely specified machine-readable version of NOTICE, which is currently only machine-readable because of relay implementation details. But AUTH is the way to send a challenge. Correlating NO messages and AUTH challenges to create a good UX seems like unnecessary busy work. If AUTH with a challenge wasn't already in use I could see doing something like: But this is essentially the same as this proposed extension to AUTH, except that it includes more information. I can't think of an example of when a relay would want to grant entry using any other mechanism than auth. |
true, but I can think of examples for when a relay would deny a req for another reason other than AUTH:
|
The advantage is what you pointed yourself in your next comment: that it supports other kinds of request failures that today go completely unaccounted for.
doesn't matter. I think
I just described how to do that in pseudocode above and it wasn't hard at all as long as the |
|
Basically we have two distinct problems:
adding a third element to creating a new message solves 2 and making |
|
It does work with
Now that we are using regular OK msg for client EVENT msg response, I guess maybe we don't really need to specify the command name anymore and just rely on REQ/COUNT/ANY_FUTURE_CLIENT_MESSAGE's (subscription) id. |
|
I do like @staab 's suggestion of having a machine-readable-reason. |
Those are all arguably programmer errors, and should be covered by NOTICE. If a client dev is going to the trouble of parsing those errors and handling them, they should just cover those edge cases instead.
Not hard, just unnecessary busy work. Ironically I think I'm defending fiatjaf's usual position of avoiding premature abstraction. I don't see a need for a generic machine-readable error mechanism, because AUTH covers all the use cases where a user can actually do something. Even if we admit some of the use cases above (rate limiting maybe), now we're specifying something extremely abstract, and should be careful not to create another overly-broad overloaded solution. |
its impossible to cover all edge cases when the edge cases vary from relay to relay. and right now I doubt any client dev is parsing those errors and handling them because its impossible to maintain due to arbitrary notice messages. having machine readable reason would at least allow this as a possibility. |
I appreciate that, but I think it won't hurt at all to have a message akin to Before the invention of Anyway, I don't think the introduction of I think having a generic message for failures in |
|
I've published #902, which I think solves everything. It also solves another problem that I have faced myself: what to do when your relay doesn't support ongoing subscriptions, but just immediate sync queries? The answer is: return all the events from the sync queries, then an |
|
Closing in favor of #902 |
|
On Mon, Nov 27, 2023 at 10:54:05AM -0800, fiatjaf_ wrote:
I appreciate that, but I think it won't hurt at all to have a message
akin to `OK` but specifically for `REQ`s.
This was something I was always concerned about in the command result
spec. I didn't have an immediate use for it in my client so I didn't
feel the need to spec it, but I felt like something should probably
exist in some situations.
|
Currently the relay can send an AUTH message at any moment and client can't know what (or if a) client message triggered it.
This PR tries to bring order by telling exactly when and how the relay can send an AUTH message. It also introduces an optional third array element that can reference a previous client message. This referencing and timing assists the client retry logic.
This is a new attempt to fix NIP-42 instead of adding NIP-43.