Hi all,
Before I go into the depths of writing a module for a per seat licence for one of my projects, has anyone got anything they have done from concept to gotcha's? Im all ears.
Im looking at providing a system of single session or token per user seat. Currently multiple people can log in with the same user credentials and I want it to be able to not allow this to happen. I have a system wide subscription module for an old project in CI3 which I am looking to develop into a TG system and this will run hand in hand.
Thanks in advance
Keith
Per seat licence
19 days ago
19 days ago
#1
19 days ago
#2
Hello Keith,
I have done that before in one of my commercial projects. It can become very problematic once paid customers start to log in from different browsers on multiple computers (and mobile devices) from different locations.
In order for it to work, you have to keep track of the logged in user in your web application. I did that by creating a database table to store the user_id, a unique machine_key and the last_action (time) for the logged in user. I updated the last_action field every time the user clicked something or loaded a page. I also did a ping-back every 30 seconds if they let the browser open with the app running but were just browsing data.
If someone with the same credentials tried to log in and the last_action time was less than 60 seconds ago, I displayed a nice message that someone else is logged in and is using the app with the same credentials. If the last action had been taken more than 60 seconds ago or the user had logged out, then I let the new login succeed.
This is where it gets problematic: the same user can use the app on his computer and just close the browser (without logging out properly). They open it up on their phone (within 60 seconds) and the app won't let them in. They don't understand what's going on. "It works on the computer but not on the phone." "But yesterday it was the other way around!" They start calling customer support and complain.
The other scenario that often happened is that the user let the browser open with the app running (at home) and the next morning tried to log in from a different computer in the office. Because of the ping-back on the home computer, they couldn't log in from the office. And vice versa, if the let the app running in the office, they couldn't use it from home.
You simply cannot expect the users to properly log out every time they finish using the app. They won't. This entire issue ate up most of the resources of customer support and we eventually decided to backtrack. I removed the ping-back logic and kept logging and checking the clicks and page loads only. That way things improved although it became entirely possible for two users (with the same license) to use the app at the same time if they managed to bypass the 60-second action limit.
All in all, it caused too much headache for everyone: developers, users and customer support alike. I wouldn't recommend doing it if there's any other way. I think the "per seat license" model would be easier to implement in a desktop app (it used to be popular back in the day). But in a web app it's not worth the trouble and honestly, users are simply not used to it.
This was just my experience and others might have solved it better. Also, I shared this entirely from memory so it may not be accurate. I hope you get something out of this.
I have done that before in one of my commercial projects. It can become very problematic once paid customers start to log in from different browsers on multiple computers (and mobile devices) from different locations.
In order for it to work, you have to keep track of the logged in user in your web application. I did that by creating a database table to store the user_id, a unique machine_key and the last_action (time) for the logged in user. I updated the last_action field every time the user clicked something or loaded a page. I also did a ping-back every 30 seconds if they let the browser open with the app running but were just browsing data.
If someone with the same credentials tried to log in and the last_action time was less than 60 seconds ago, I displayed a nice message that someone else is logged in and is using the app with the same credentials. If the last action had been taken more than 60 seconds ago or the user had logged out, then I let the new login succeed.
This is where it gets problematic: the same user can use the app on his computer and just close the browser (without logging out properly). They open it up on their phone (within 60 seconds) and the app won't let them in. They don't understand what's going on. "It works on the computer but not on the phone." "But yesterday it was the other way around!" They start calling customer support and complain.
The other scenario that often happened is that the user let the browser open with the app running (at home) and the next morning tried to log in from a different computer in the office. Because of the ping-back on the home computer, they couldn't log in from the office. And vice versa, if the let the app running in the office, they couldn't use it from home.
You simply cannot expect the users to properly log out every time they finish using the app. They won't. This entire issue ate up most of the resources of customer support and we eventually decided to backtrack. I removed the ping-back logic and kept logging and checking the clicks and page loads only. That way things improved although it became entirely possible for two users (with the same license) to use the app at the same time if they managed to bypass the 60-second action limit.
All in all, it caused too much headache for everyone: developers, users and customer support alike. I wouldn't recommend doing it if there's any other way. I think the "per seat license" model would be easier to implement in a desktop app (it used to be popular back in the day). But in a web app it's not worth the trouble and honestly, users are simply not used to it.
This was just my experience and others might have solved it better. Also, I shared this entirely from memory so it may not be accurate. I hope you get something out of this.
19 days ago
#3
Hello,
It seems to me that the first issue is login. Have a simple if statement that says if logged in --Display a message saying cannot have more than one user logged in with same credentials-- and then redirect back to the login page.
Dan
It seems to me that the first issue is login. Have a simple if statement that says if logged in --Display a message saying cannot have more than one user logged in with same credentials-- and then redirect back to the login page.
Dan
18 days ago
#4
Hi Dan,
Yes, that does seem simple enough. However, the real challenge is reliably determining whether a user is active/logged in at any given moment.
To address this, I used a ping-back method and tracked user-initiated clicks and page loads (as detailed in my post above). I can't help but wonder if there is an easier, cleaner, or more elegant solution to handle this?
Yes, that does seem simple enough. However, the real challenge is reliably determining whether a user is active/logged in at any given moment.
To address this, I used a ping-back method and tracked user-initiated clicks and page loads (as detailed in my post above). I can't help but wonder if there is an easier, cleaner, or more elegant solution to handle this?
18 days ago
#5
Hi Keith,
I'd separate the licensing logic from the authentication logic.
Rather than trying to determine whether a user is "active", I'd track authenticated sessions in a database table (for example: "user_id", "session_token", "last_activity", "expires_at"). A successful login creates a session, logout removes it, and expired sessions are cleaned up automatically.
If your goal is to prevent account sharing, allow only one active session per user account.
If your goal is a true per-seat licence, simply count active sessions against the purchased seat limit before allowing another login.
I wouldn't rely on frequent heartbeat/ping requests, as they add complexity and can keep abandoned sessions alive. Updating "last_activity" on normal requests, combined with a sensible inactivity timeout, is usually sufficient.
This approach also makes it straightforward to provide an admin page showing active sessions and allowing them to be terminated if required.
Cheers,
Si
P.S. In Trongate V2, an interceptor method could be a simple place to validate the user's licence session and update the last activity timestamp during normal requests, with a sensible interval (for example, only updating once every 60 seconds) to avoid unnecessary database writes.
I'd separate the licensing logic from the authentication logic.
Rather than trying to determine whether a user is "active", I'd track authenticated sessions in a database table (for example: "user_id", "session_token", "last_activity", "expires_at"). A successful login creates a session, logout removes it, and expired sessions are cleaned up automatically.
If your goal is to prevent account sharing, allow only one active session per user account.
If your goal is a true per-seat licence, simply count active sessions against the purchased seat limit before allowing another login.
I wouldn't rely on frequent heartbeat/ping requests, as they add complexity and can keep abandoned sessions alive. Updating "last_activity" on normal requests, combined with a sensible inactivity timeout, is usually sufficient.
This approach also makes it straightforward to provide an admin page showing active sessions and allowing them to be terminated if required.
Cheers,
Si
P.S. In Trongate V2, an interceptor method could be a simple place to validate the user's licence session and update the last activity timestamp during normal requests, with a sensible interval (for example, only updating once every 60 seconds) to avoid unnecessary database writes.
18 days ago
#6
Hi DaFa
I use interceptor methods already for a database migration module so thats a great shout and be a good method of preflight verification.
All excellent ideas guys, thank you muchly
Keith
I use interceptor methods already for a database migration module so thats a great shout and be a good method of preflight verification.
All excellent ideas guys, thank you muchly
Keith