Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Periodic reauthentication #752

Open
haines opened this issue Nov 20, 2023 · 8 comments
Open

Periodic reauthentication #752

haines opened this issue Nov 20, 2023 · 8 comments
Assignees

Comments

@haines
Copy link
Contributor

haines commented Nov 20, 2023

The problem I am facing
We check that the user is authorized to edit the document during the initial authentication handshake. But if the user's access is revoked while they have a connection open, they can continue to edit the document until they reconnect.

The solution I would like
I would like the server to keep track of the last time it received an authentication message, to be able to configure a timeout after which a client who has not reauthenticated would be disconnected, and to be able to configure the provider to reauthenticate on a given interval.

@solirpa
Copy link
Contributor

solirpa commented Nov 21, 2023

you can use debounce on onChange hook, for example:

import { debounce } from "debounce";
import { Server } from "@hocuspocus/server";

let debounced;

const server = Server.configure({
  async onChange(data) {
    const reauth = () => {
        // your logic
    };

    debounced?.clear();
    debounced = debounce(reauth, 30000);
    debounced();
  },
});

server.listen();

@haines
Copy link
Contributor Author

haines commented Nov 21, 2023

That wouldn't work for us, unfortunately. We have short-lived access tokens stored in the user's session cookie and we need to refresh those and update the cookie, which requires some participation of the provider rather than just doing it in the server.

Our token function in the provider performs an HTTP request to issue a token, and the auth logic is handled within that HTTP handler. So if we could just have the provider call the token function on an interval and send an authentication message to the server, that'd be ideal.

@mortenson
Copy link

I think @solirpa's solution would work for me, but having a re-auth period as a configuration option would feel a bit cleaner

@janthurau
Copy link
Collaborator

In order to re-evaluate the permissions of a user before applying a message, you can use the beforeHandleMessage hook. It's called before every received message, so you might want to cache expensive permission checks.

I'll keep this open to track progress on resending authentication information from the provider side, which we currently don't officially support.

@p1nox
Copy link

p1nox commented Jan 13, 2024

In order to re-evaluate the permissions of a user before applying a message, you can use the beforeHandleMessage hook. It's called before every received message, so you might want to cache expensive permission checks.

I'll keep this open to track progress on resending authentication information from the provider side, which we currently don't officially support.

In case the process to re-evaluate the permissions of each user while is using editing the doc is fetching a record in a relational database (or course, a future improvement would be to replicate this in something like Redis), which hook would you recommend @janthurau ? beforeHandleMessage mentioned by you, or onChange mentioned by @solirpa ? What could be the different between those two? I guess that performance should be the variable to take in account for answering this question.

Separate question, depending of which hook is used, if the check passes nothing happens, but if the user is no longer authorized to read-write that doc, an error is returned to the client side, and I guess the connection is closed in the provider? And then how can this be handled in the client side? In which listener this error is received?

@talhazubairbutt
Copy link
Contributor

You can use stateless messages to send newly issued tokens(by your API) from the client to the server via the socket. The token can be persisted/associated with the connection on the server side and then used to apply/discard updates or even drop the connection when needed.

@BrentFarese
Copy link
Collaborator

@p1nox stumbled across this ticket b/c we're trying to periodically re-authenticate too. Our approach was to use beforeHandleMessage but we strap on a lastAuthCheck onto context in the onAuthenticate hook first. Then, we only re-check authentication every N seconds based on lastAuthCheck (which is updated every time re-authentication happens). This is pretty effective since it's performant (only checking authentication using out API every N seconds), but it also ensures a user that is working with a document maintains access/is re-authenticated on a decent frequency.

@RubaXa
Copy link
Contributor

RubaXa commented May 2, 2024

I'll keep this open to track progress on resending authentication information from the provider side, which we currently don't officially support.

Now this logic is sorely lacking, there is only one output, invoke disconnect on server 🙁

Ideally, I need

  • connection.getToken() method, which will send an event to the provider and receive a token from it
  • or authenticationRecheckFrequency (msec) option + onAuthenticationRecheck where I can close the connection, or change readOnly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants