km751

km751

I have a problem with authenticating WebSocket connection.

I use Phoenix and Vue + phoenix-socket as my front-end, and everything was fine before adding authentication.

The connection can be established and data is transferred properly but after that, it starts sending errors and I don’t understand why.

My browser console looks like this:

    receive: ok feed:1 phx_reply (1) {response: {…}, status: "ok"}

    Joined successfully {feed: Array(3)}

    WebSocket connection to 'ws://localhost:4000/socket/websocket?vsn=1.0.0' failed: Error during WebSocket handshake: Unexpected response code: 403

    push: phoenix heartbeat (2) {}

    receive: ok phoenix phx_reply (2) {response: {…}, status: "ok"}

    WebSocket connection to 'ws://localhost:4000/socket/websocket?vsn=1.0.0' failed: Error during WebSocket handshake: Unexpected response code: 403

Phoenix:

[info] CONNECTED TO TweeterApiWeb.UserSocket in 0┬Ás
  Transport: :websocket
  Serializer: Phoenix.Socket.V1.JSONSerializer
  Parameters: %{"token" => "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0d2VldGVyX2FwaSIsImV4cCI6MTU5NjkxMjAxNiwiaWF0IjoxNTk0NDkyODE2LCJpc3MiOiJ0d2VldGVyX2FwaSIsImp0aSI6IjViYWFlMDRlLTBjMTYtNDEyMi05Y2VlLWZmMzQ2OWM1YWE1YiIsIm5iZiI6MTU5NDQ5MjgxNSwic3ViIjoiMSIsInR5cCI6ImFjY2VzcyJ9.-ZJMyyEBKd0_nHYUBGdaI0qdHn1nuWtpG8sEUHqikBuWTB2sKw9Sk36OsUpXBS5ozRpe2l2VXq8NI58HydIhZA", "vsn" => "1.0.0"}
[debug] QUERY OK source="tweets" db=0.0ms idle=875.0ms
SELECT t0."id", t0."content", t0."comment_count", t0."retweet_count", t0."like_count", t0."profile_id", t0."inserted_at", t0."updated_at" FROM "tweets" AS t0 WHERE (t0."profile_id" = $1) [1]
[info] JOINED feed:1 in 0┬Ás
  Parameters: %{}
[info] REFUSED CONNECTION TO TweeterApiWeb.UserSocket in 0┬Ás
  Transport: :websocket
  Serializer: Phoenix.Socket.V1.JSONSerializer
  Parameters: %{"vsn" => "1.0.0"}

It looks like the connection is refused because there is no token in params but I only check the authentication when the socket connects, so the token should be completely unnecessary once the connection is established, right?

Here is my user_socket.ex:

defmodule TweeterApiWeb.UserSocket do
      use Phoenix.Socket
    
      alias TweeterApi.Accounts
      alias TweeterApi.Accounts.Guardian
    
      ## Channels
      channel "feed:*", TweeterApiWeb.FeedChannel
    
      @impl true
      def connect(%{"token" => token}, socket, _connect_info) do
        case Guardian.resource_from_token(token) do
          {:ok, user, _claims} ->
            current_profile = Accounts.get_profile_by(user_id: user.id)
    
            {:ok, assign(socket, :current_profile_id, current_profile.id)}
    
          {:error, _reason} ->
            :error
        end
      end
    
      def connect(_params, _socket, _connect_info), do: :error
    
      @impl true
      def id(socket), do: "users_socket:#{socket.assigns.current_profile_id}"
end

The channel code:

defmodule TweeterApiWeb.FeedChannel do
      use TweeterApiWeb, :channel
    
      alias TweeterApi.Tweets
    
      def join("feed:" <> current_profile_id, _params, socket) do
        if String.to_integer(current_profile_id) === socket.assigns.current_profile_id do
          current_profile_tweets = Tweets.list_profile_tweets(current_profile_id)
    
          response = %{
            feed:
              Phoenix.View.render_many(current_profile_tweets, TweeterApiWeb.TweetView, "tweet.json")
          }
    
          {:ok, response, socket}
        else
          {:error, %{reason: "Not authorized"}}
        end
      end
    
      def terminate(_reason, socket) do
        {:ok, socket}
      end
end

and Vue.js code:

<script>
    import UserProfileSection from '@/components/sections/UserProfileSection.vue'
    import TimelineSection from '@/components/sections/TimelineSection.vue'
    import FollowPropositionsSection from '@/components/sections/FollowPropositionsSection.vue'
    import NewTweetForm from '@/components/sections/NewTweetForm.vue'
    import { mapGetters } from 'vuex'
    import { Socket } from 'phoenix-socket'
    
    export default {
        name: 'AppFeed',
        components: {
            UserProfileSection,
            TimelineSection,
            FollowPropositionsSection,
            NewTweetForm,
        },
        data() {
            return {
                tweets: [],
            }
        },
        computed: {
            ...mapGetters('auth', ['currentProfileId', 'token'])
        },
        mounted() {
            const WEBSOCKET_URL = 'ws://localhost:4000'
    
            const socket = new Socket(`${WEBSOCKET_URL}/socket`, {
                params: { token: this.token },
                logger: (kind, msg, data) => {
                    console.log(`${kind}: ${msg}`, data)
                },
            })
    
            socket.connect()
    
            this.channel = socket.channel('feed:' + this.currentProfileId, {})
    
            this.channel
                .join()
                .receive('ok', (resp) => {
                    console.log('Joined successfully', resp)
                    console.log(resp)
                    this.tweets = resp.feed
                })
                .receive('error', (resp) => {
                    console.log('Unable to join', resp)
                })
        }
    }
</script>

Marked As Solved

sb8244

sb8244

Author of Real-Time Phoenix

What does the web request that the JavaScript makes to initiate the WebSocket look like? It will include token as a GET parameter.

Your initial request makes it look like token is being passed up, but then a second request is made that fails. Do you have 2 Socket connections by chance?

Why does "token" => "eyJhbGciOiJIUzU..." differ from the second call? Why are there 2 calls at all?

Few high level thoughts are that you are on an old serializer version (1 instead of 2) and using phoenix-socket library. I would suggest making sure you’re on the latest versions possible—in general a good thing—although that is likely not the actual issue at hand.

edit: Have you tried console.log(this.token) in the mounted function? What if it is being mounted without a token?

Also Liked

kokolegorille

kokolegorille

Hello and welcome…

It seems You are using an outdated library.

This one should be better

https://www.npmjs.com/package/phoenix

BTW You did not mention your phoenix version :slight_smile:

km751

km751 OP

I had a second socket connection in my vuex module used in one of the child components.

Thank you for your help!

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews