So I made an app and the end user can log in and log out in it. My problem is where a user completely closes all tabs and reopens them and is still logged in. I need a way to detect when all tabs are closed and log out the user automatically.
I store the user with put_session/3 in the conn struct.
By the design of the web it is impossible to know when the tabs are closed.
Some common workarounds are things like keeping a websocket open and closing the session when it dies, but that will cause people to be randomly logged out with spotty connections or if their computer/phone/whatever suspends or switches apps.
You can just do it based on a time limit, say 10 minutes auto-logout from the time they last did anything on the site.
You could just not use a session, encode all the data into the page itself (the old PHP session ID in the url style), however this can leak data out so it’s generally not recommended.
I think this is more of an XYProblem. Rather for what reason are you trying to log them out when they ‘stop using the service’ or so?
1 Like
Okay so I tried using websockets and I can detect when the page is left and send it to phoenix but I can’t figure out a way to get to the conn struct from there.
Oh and to explain for what reason I want that.
I am basically implementing webrtc for voice chat but it gets some data from an external server via websockets (this part is done) and I want it to be a single-session-chat. The user would have to go through the process of logging in every time they want to re-enter the channel.
You shouldn’t be getting the conn
struct, conn
is for an HTTP request. If you want to clear the session then you’ll need to clear it out of your database or so.
Why don’t they just get a unique token for just that chat then, and when they go back they need a new token, which can be like the login screen.
1 Like
Okay I managed to make it work similar to what I intended. When the user logs in they get a :logout
key with the value of false
and then when they load the page right after they log in the value is set to true
. After that I added a plug to my router file:
Disconnect plug:
defmodule Voicer.Plugs.Disconnect do
import Phoenix.Controller, only: [redirect: 2]
import Plug.Conn, only: [halt: 1, clear_session: 1]
import Voicer.Helpers
alias Voicer.Router.Helpers, as: Helper
def init(default), do: default
def call(conn, _opts) do
if should_be_logged_out?(conn) do
conn
|> clear_session()
|> redirect(to: Helper.session_path(conn, :new))
|> halt()
else
conn
end
end
end
Helpers file:
defmodule Voicer.Helpers do
alias Plug.Conn, as: Connection
def is_logged_in?(conn) do
Connection.get_session(conn, :username) != nil
end
def should_be_logged_out?(conn) do
if is_logged_in?(conn) do
Connection.get_session(conn, :logout)
else
false
end
end
def get_username!(conn) do
Connection.get_session(conn, :username)
end
end
But I am still giving you a solution because mentioning websockets you gave me the idea to send the page leave event to my remote server, so thanks!
1 Like