Getting a valid session for a Socket.IO app

Plugin Development
  • 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.

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

  • 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.

  • 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.

  • 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

  • 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.

  • @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. 🙂

  • 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();
            }
        }
    }
    
    


Suggested Topics


  • 2 Votes
    11 Posts
    789 Views
  • 0 Votes
    6 Posts
    560 Views
  • 0 Votes
    1 Posts
    1217 Views
  • 0 Votes
    3 Posts
    1620 Views
  • 0 Votes
    9 Posts
    2523 Views