Return challenge field on subscription with Java (EventSub)

Good afternoon to everyone,

Sorry if this is already something answered, but after googling, I didn’t find anything similar to this issue. I’m new with EventSub, and I’ve been this days fighting to prepare it so my Java client can create a ServerSocket with SSL using LetsEncrypt, but the issue comes when I try to return the challenge.

On the EventSub documentation, says that once I get the verification as a POST request using the ServerSocket, and I got that, also the challenge. After getting it, says that I have to return it as a raw value. I checked the challenge, and didn’t seem to be a text that should require an encoding, but I used that in case:

String challenge = URLEncoder.encode(element.asObject().getObject("challenge").asData().getAsString(), "UTF-8");

The problem is that I can’t seem to find a way to send it back, in a way that Twitch returns me another answer than the same verification. I saw that it should give you like a ‘failed’ answer in case you didn’t give a correct answer, but it keeps returning me the ‘pending’ state. This is my actual way to send it back to Twitch in Java:

String challenge = URLEncoder.encode(element.asObject().getObject("challenge").asData().getAsString(), "UTF-8");
System.out.println(challenge);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(event.getSocket().getOutputStream()));
writer.write(challenge);
writer.flush();
writer.close();

Just wondering if I should add something else like headers or something, or if I should instance another kind of connection like URLConnection or anything else than Socket. The only answers I saw on other posts is that it should be a return made on the same connection, cause this I’m using the same Socket, also as I searched inside the BarryCarlyon’s code for nodejs, where uses the reponse given in the callback to answer only with the challenge using ‘res.send(encodeURIComponent(req.body.challenge))’, but I don’t know if Express creates a new connection instead of using the same one.

You echo it out like you would HTML on a webpage.

Just instead of sending HTML you send just the challenge.

No, no headers are required.

Express just spits it out like if you were sending HTML/using express to serve a website

So

res.send('<html><head><title>My WebPage</title></head><body><p>My cool website</p></html>');

Is the same as

res.send(the_challenge);

encodeURIComponent used to help combat CWE-79/CWE-116 against Cross Site Scripting (this commit CWE-79/CWE-116 advice for Cross Site Scripting. · BarryCarlyon/twitch_misc@926de5a · GitHub )

In express res.send replies to the inbound HTTP Request for “gimmie this webpage” just for this request for eventsub it’s just the challenge you spit out and not a full webpage

The problem is that it’s what I’m actually doing with the second code I shared. The event.getSocket() is the same socket created by Twitch when making the POST request to my Callback server, and the getOutputStream the output channel it’s creating. I try on the next three lines to use the output channel, write there the challenge I obtained from the request made by Twitch and I flush it, but doesn’t seem to be valid, and keeps sending me pending verifications.

Try using the twitch-cli to test your callback https://github.com/twitchdev/twitch-cli/blob/main/docs/event.md#verify-subscription

And/or visiting your callback URL yourself to test it works as expected.

I’ll try to test it later, as I have to do something.

I prepared the code to send an HTML code if that was the case, a sample that they shouldn’t use it with GET at the moment. I have lot to learn, as I could check that with the actual code, with a normal client, it gets stuck waiting for the content of the request. Also for Twitch, I saw that it takes long, like 4 seconds or more, until it gets the content after getting all the headers. At the end, with a normal web client, it got the HTML.

Thank you so much, today I’ve learned something new. The basic problem is that I didn’t know that Content-Length would be really important, I thought that it was like just a parity control, but I didn’t knew that there wasn’t a EOF for the InputStream. This was freezing the connection until the socket gets closed. Cause this, the code wasn’t sending an answer, as it was reading the JSON, but not stopping the reading, was waiting for an end. I used the Content-Length and 0 in case it’s not there to just read that amount of bytes, and I could make it send properly the challenge. Anyway I have to face two issues, the first one is an issue in Java, that causes connections to get stuck, in a way that I can’t make consecutives connections, so I’ll have to check what happens.

The second issue I’m facing is this one:

The challenge is send on the same way as you said, only I got the challenge as an String, I writted it in the output stream and I sent it. It gives me like the format of the challenge is bad.

Does you code output

asdklasdjklasdjlasjd

or

“askldjaskldjasjdaskld”

The latter is incorrect.

Outputs without ", I don’t know the reason why it shows with “”, I thought it would be something from twitch.exe

Thats why I asked to check.

Connection broken sounds like it’s not “ending”/flushing normally and just dieing

I’ve ended up finding the solution. As it’s manual, it requires more steps. The CLI and Twitch asks for a valid HTTP response, not a raw one. In raw means that at least the HTTP response has to be text/plain, but it still requires the entire structure, so probably the send method on your nodejs code also includes the required headers for a response. I still have to learn more about the HTTP standard to make manual sendings, but I could repair it with this headers:

writer.write("HTTP/1.0 200 OK\r\n"
+ "Content-type: text/plain; charset=UTF-8\r\n"
+ "Content-Length: " + challenge.length() + "\r\n\r\n"
+ challenge);

Thats likely being handled by NodeJS express under thd hood.

Since, the challenge response, is just the challenge and no other characters in the normal web transfer.

Normal web transfer will also include a HTTP Header and the type/length headers, which express just does under the hood.

res.send('whatever') equivalent to res.status(200).send('whatever') (and the header for length)

Most libraries just do that under the hood, since this is webhooks and it’s “like loading a webpage”, so I didn’t think to mention headers since it’s basically just buidling and API/Form responder (like you would if building an admin system and sending a response to a users login form).

So, I’ll note to mention the header for headers/contentLength next time someone has a similar issue

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.