vipulbhj
How to use Phoenix `socket` on localhost with React Frontend?
Hello, I am trying to build a Backend system in Phoenix, this is mostly APIs but needs Websockets for a chat interface.
I researched a bit with Claude, and found out that Phoenix sockets can be a great choice for this with Channels, so I create a setup as details below.
I have two tables
chat_sessions
chat_messages
When the user lands on /api/v1/chat/sessions, I check for a few things and then create a record in this table, and I use put_session to set the id of this table in a cookie and send it back to the client.
Now I created a socket endpoint in the endpoint file similar to /live just under /live
socket "/api/chat", ProfiWeb.UserSocket,
websocket: [connect_info: [session: @session_options]],
longpoll: false
Inside the UserSocket I added
def connect(params, socket, connect_info) do
Logger.info("WebSocket connection attempt with params: #{inspect(params)}")
Logger.info("Connect info session: #{inspect(connect_info[:session])}")
with {:ok, session_id} <- extract_session_id(connect_info),
....
...
defp extract_session_id(connect_info) do
case connect_info[:session] do
%{"chat_session_id" => id} when is_binary(id) ->
Logger.info("Found chat_session_id in session: #{id}")
{:ok, id}
_ ->
Logger.info("No session found, checking params for session_id")
{:error, :no_session_id}
end
end
Backend is running on http://localhost:4000 and FE is on http://localhost:4321
I was hoping this setup would be enough and I will get the cookie since inside session options, same_site is set to “Lax”
@session_options [
store: :cookie,
key: "_profi_key",
signing_salt: "4yRHL+9g",
same_site: "Lax"
]
But when I check the request headers in browser, I don’t see the cookie, googling and going back and forth with Claude, finally landed on creating a reverse proxy on localhost:3000 and proxying both through that.
When I do that, browsers start sending the cookie, but the server still doesn’t get it.
I fought this problem a lot, with Claude a lot but nothing worked, added a ton of logs but nothing.
Does anyone know how I can do this ?
Thank you for your help, much appreciated ![]()
Phoenix Forum > Questions / Help
EDIT: If I missed any details, please let me know, I will update the post with those details.
Most Liked
Nicodemus
First, you’ve chosen one of the most difficult ways to architect a website on the modern web, owing mostly to a gauntlet of security measures you will have to properly configure and work with. What is your app, and does it require a completely separate front-end? Does it even require React? 90% of SPAs are over-engineered, fragile, and worse off for being SPAs instead of progressively enhanced classic web sites, mainly due to an over-indulgence in following trends and cargo culting.
Are you going to host it on two separate domains, as is implied by running two dev servers. If you instead configure Phoenix to serve all of your static assets, then you don’t need to configure CORS, or deal with cookies being set for two different domains (though sharing across subdomains is relatively easy.) You can still share a domain with two different services behind it, but then you’ll need an HTTP aware proxy/load balancer to know that “/api” requests go to the Phoenix cluster, and “/app” requests go to the front-end nodejs or whatever cluster. So my main question is, what are you building, and does it really require this complexity? None of it is impossible, but if you’re new to these things (assumed by use of LLMs for research, and generally for the kinds of questions you’ve asked here and on Discord, apologies if you’re not), then you might want to reevaluate trying to build something so complex without some experience with simpler setups.
Second, Phoenix.Socket will likely never allow you to access arbitrary headers or cookies as LostKobrakai said, due to Cross-Site Websocket Hijacking. This is a serious problem, and I agree with Phoenix’s hard-line stance to basically make it close to impossible to fall into this trap. There is no way around this other than implementing your own version of Phoenix Channels.
I’m honestly not sure why using a local proxy made the browser start sending cookies for the socket connection, but I suspect it was coincidental. Websocket() will send any set cookies, depending on the cookie setting. However, fetch() will not allow the server to set cookies. So if your FE is truly separate and you’re “landing on /api/v1/chat/session” with fetch(), the only way the session cookie could have been sent was if you manually made a request to your BE on localhost from your browser at some point, which set the cookie. However, if you do deploy this to two separate domains, then it’s going to be very difficult to get the session cookie from one domain to the other, anyways.
If you really want to have a separate FE and BE, on separate domains, then the simplest solution is to treat the FE like it’s a completely different application running in a completely environment. Don’t use session data or cookies at all, and instead follow the guide that Kapsy in Discord already sent you.
The only difference, is that instead of setting the token in the assigns and in the JS of the page (which works if phoenix serves your FE), you will need to make a fetch() request from the FE to the BE with authentication information to your API, which will return a token for the JS in the FE to use when connecting to the Channel.
BTW, none of this is the fault of Phoenix or Elixir… this is all due to the security requirements of the modern web, which has had to add a lot of hoops to jump through due to bad actors exploiting vulnerabilities like CSWSH and CSRF to hack web sites. That and your desire to create one of the most difficult stacks to build a web site with, requiring knowledge and experience across a wide swatch of technologies, protocols, and security standards to get right.








