Delete user session when a user gets deleted from SG

We have a use-case where we revoke access to users/devices that previously connected. When a call to the admin API endpoint to delete a user was done ({db}/_user/{name}), it seems the sessions still stay active inside the database.
I was not yet able to verify if these sessions still work or not (that’s next on my list).

Just a simple question, because we can easily work around this by calling the endpoint to delete all user’s session, but I was wondering if there is a reason why these sessions do not get deleted when a user gets deleted?

As a follow-up, it seems after deleting the sessions using the Admin endpoint, partial access is removed.
Data does not get replicated to the device anymore, which is perfect. However, it seems we are still able to push data to the database from this device?

Are you stating that the user has been removed from Sync Gateway but is still pushing up documents using those user credentials ? Or is the client using the previously deleted session Id?

Can you provide more details of sequence of calls that was made including replicator setup code on client side.

The client is using the previously deleted session Id. Our setup does not let clients log in directly through the Sync Gateway, we have an application server running that provides the session details to the clients when we verified their access. Part of this application server allows us to revoke access to previously granted devices, currently we remove both the User and all it’s sessions from the Sync Gateway when that happens.

The app checks in with the application server every time it starts (or when it gets an internet connection).
Some trimmed down of our client side replicator code, TokenSessionId and TokenCookieName come from the application server.

var replicatorConfig = new ReplicatorConfiguration(db, new URLEndpoint(url))
{
    Authenticator = new SessionAuthenticator(TokenSessionId, TokenCookieName),
    Continuous = true,
    ReplicatorType = ReplicatorType.PushAndPull
};
replicator = new Replicator(replicatorConfig);

After this code we attach some listeners and call .Start() on the replicator.

At first everything looked fine, but then we noticed pushed were still going through. We have a possible workaround for our application, where some client device info is synced to all clients, so we can listen for document changes on the client and the client can see it has it’s access removed and act accordingly. This might not be the case for other users with the same problem though.

Last week I actually remembered that we had asked a similar question a while ago (Session removal keeps sync active)

The session validity will be checked only when a replication is started and is set to auto expire based on original session expiration. So a session delete REST call in the middle of a replication will not detected by Sync Gateway. For performance reasons , auth check is not done on every incoming message. So deleting the session via the delete session endpoint will not cause replication to terminate. .

Unless I am misunderstanding you, I don’t see how the accessRemoved on push would work . Access removal and revocation is for document pull. Try using requireAccess() in sync function to check if user has access to channel. If user does not exist, an error should be returned by sync gateway (CC @adamf for better ideas)

Would suggest changing your logic so the CBL app closes and restarts the replicator every time it receives new session token from app server.

Thank you Priya,

We actually already use requireAccess() in our Sync function, now what I did not think about, is checking the logs on the sync gateway. If see some warnings in there after deleting the user:

2021-06-01T12:04:18.849Z [WRN] c:[2963c7e1] Error reloading user "ccb6f7089874194936876aa04bf5a2e5ae": User not found during reload -- db.(*Database).checkForUserUpdates() at changes.go:336
2021-06-02T08:38:04.624Z [WRN] c:[79513249] Error reloading user "cc0ebcd2fe274044c88b68f3dcc0433186": User not found during reload -- db.(*Database).checkForUserUpdates() at changes.go:336

Maybe this is the reason why the pushes are still going through? We are currently running SG 2.7.3, I did not find any changes related to this in the release notes, we’ll update during offhours and see if this changes anything.
The error returned from SG (when requireAccess rejects the change), is this something CBL will detect so we can hook into this to verify access is still valid?

We would have some device specific info stored on the client device itself (like the documentID referring to this client device). Due to our internal process of removing access, this client device document would get removed from all channels (so we don’t bloat client devices with lingering data), causing the AccessRemoved flag to be set on all client devices for this document. We hook into the pull events on the client devices, and we compare the documentID of the AccessRemoved with the locally stored document.

The app already restarts the replicator on different occasions, our app also asks a new token each time the replicator is being restarted (or just started), if the client device was revoked before, it won’t get a new token and the client device handles the rest of the process needed to clear it’s local database.
The only problem we’re currently still facing, is notifying the client device is revoked during an active sync.

OK. That should work. In latest version of CBL, when a document is removed from all of user’s channels, then that document should get auto purged on the CBL device. So you shouldn’t even have to do the purge manually.

you will see an error in the listener of document is rejected due to an error . Don’t recall the exact code - 403 Forbidden perhaps. Log the error code in listener.

But what I don’t get is that you indicate that you have removed the user from the sync gateway. If that is the case, and you are replicating in the context of the user. the replication should return to see a 403 forbidden or equivalent error. In fact, you can do a quick test - start a replication with a non existent user and you will see an error.

This seems to work perfectly indeed, in the end we might go with a different route, as it seems the AccessRemoved might not come in if the document was not synced yet before it was removed from the user’s channels.
EDIT: After internal brainstorming, we’re going to go this route anyway, the chances of this happening are low enough to accept.

I was able to get the 403 error code now, so we will be able to continue with that. However, to get it working, I changed our code to only remove the user’s active sessions and not the user itself. Ideally we’d like to remove the user from the SG as well, as there’s no use keeping them around anyway.
If we enable the removal of the user again, we’re getting the same errors as listed in my previous comment and pushes still go through.

Maybe some info on how we got this to happen:
In our system, we support multiple customers, each have their own data and can have any number of client devices connected. The customer specific data is distributed using channels on the SG, each customer has 1 Role on the SG, this role gets access to all the customer channels.
Each client device has their own User on the SG, this user gets assigned the customer role, and thus gets access to the customer data from all channels.
Push access is validated by the requireAccess() on the main channel for customer data.
Removing only the User sessions starts giving 403 codes on the client.
Removing the User from the SG throws the error warning, but it seems the data is still going through. Maybe this has something to do with the user Roles?