Getting a valid session for a Socket.IO app


  • Community Rep

    With v1.0.0, Socket.IO now requires a valid session cookie. My apps no longer work since they are not in a browser and I don't know how/if I can get a valid cookie? I'm using socket.io-client-java.


  • Community Rep

    I think I just need to set a header with the nodebb secret in it.


  • Community Rep

    Okay! That made express add signedCookies to my request, but I'm not sure what cookie to send with it. The only cookie in the response is io, and nodebb is looking for express.sid. Nevermind I don't think that actually did anything.


  • Community Rep

    Hmm, I'm stuck. I have a feeling there's no way to connect to the forum using socket.io only now from my Java app. Maybe it will work if I send an initial connection via http... but this is a bit inconvenient since I only send messages to my plugins.* namespace.


  • Plugin & Theme Dev

    I'm working on a similar project in NodeJS and i came up with a fairly simple solution that involves making an HTTP request to get the session cookie and then telling the socket to use that session

    demonstration code (JS)

    'use strict';
    
    const request = require('request');
    const io = require('socket.io-client');
    const jar = request.jar();
    const forum = 'https://community.nodebb.org';
    
    request.get({
        url: forum,
        jar: jar
    }, function () {
        const cookies = jar.getCookieString(forum);
        const socket = io(forum, {
            extraHeaders: {
                'Cookie': cookies
            }
        });
        socket.on('connect', () => {
            console.log('connected');
            socket.on('pong', (ms) => console.log('pong', ms));
            socket.emit("topics.loadMore", {
                "tid": 8046,
                "after": 1,
                "direction": 1
            }, (e, result) => console.log(result));
        });
    });
    

    Assuming you're using the official socket.io-client for Java it looks like you'll be able to get at the cookies in Java a bit of a different way:
    https://github.com/socketio/socket.io-client-java#transports-and-http-headers


  • Community Rep

    Thanks! Yeah, figured I would have to go this way. It's just kind of a bummer because before now I could just make requests to my socket namespace without the extra hassle.


  • Plugin & Theme Dev

    @yariplus no problem,

    It's a bit annoying, yes. but at least the way to do the header fiddling was actually documented for you in the Java client.

    I had to trace the code to figure out that that extraHeaders object was even a thing for the javascript client.

    All I was able to find through googling was workarounds that involved monkey patching XMLHttpRequest in ways that were either extremely version specific or just didn't work.

    I literally headdesked when i found out it was really as simple as adding an as yet undocumented key to the socket configuration. :-)


  • Community Rep

    Okay! It works perfect now that I GET the Cookie first. It was pretty easy using the OkHttp3 library, which was already a dependent of SocketIO, so I didn't have to add any more dependencies.

    I'm not sure if this is useful to anyone else, but here is my test app.

    package com.radiofreederp.nodebbapp;
    
    import io.socket.client.Ack;
    import io.socket.client.IO;
    import io.socket.client.Manager;
    import io.socket.client.Socket;
    import io.socket.emitter.Emitter;
    import io.socket.engineio.client.Transport;
    import okhttp3.*;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.IOException;
    import java.net.URISyntaxException;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    
    public class NodeBBApp {
        private String url;
        private OkHttpClient client = new OkHttpClient();
        private String cookie;
        private Socket socket;
    
        NodeBBApp(String url) {
            this.url = url;
        }
    
        private void getCookie() throws IOException {
            Request request = new Request.Builder().url(url).build();
            Response response = client.newCall(request).execute();
            cookie = response.headers().get("Set-Cookie");
        }
    
        private void connectSocket() throws URISyntaxException {
            socket = IO.socket(url);
    
            // Send the session cookie with requests.
            socket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Transport transport = (Transport)args[0];
    
                    transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() {
                        @Override
                        public void call(Object... args) {
                            @SuppressWarnings("unchecked")
                            Map<String, List<String>> headers = (Map<String, List<String>>)args[0];
                            headers.put("Cookie", Arrays.asList(cookie));
                        }
                    });
                }
            });
    
            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... objects) {
                    JSONObject data = new JSONObject();
                    try {
                        data.put("tid", 45);
                        data.put("after", 1);
                        data.put("direction", 1);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
    
                    socket.emit("topics.loadMore", data, new Ack() {
                        @Override
                        public void call(Object... objects) {
                            System.out.println("Response:");
                            if (objects.length == 2 && objects[0] == null) {
                                JSONObject data = (JSONObject)objects[1];
                                try {
                                    JSONArray posts = data.getJSONArray("posts");
                                    for (int i = 0; i < posts.length(); i++) {
                                        System.out.println(((JSONObject)posts.get(i)).get("content"));
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
    
                            socket.close();
                        }
                    });
                }
            });
    
            socket.connect();
        }
    
        public static void main(String [] args)
        {
            NodeBBApp app = new NodeBBApp("http://www.yaricraft.com/");
    
            try {
                app.getCookie();
                app.connectSocket();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
    }
    
    

Log in to reply
 


Looks like your connection to NodeBB was lost, please wait while we try to reconnect.