Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fredpedersen's avatar

Authenticate a request forwarded as json

I have a websocket server running on nodejs, which connects to laravel via a webhook. The nodejs server sends the original request headers it received as json in the body of the subsequent request to the laravel webhook, including the cookies. I am trying to get the authenticated user from the cookies that were sent with the original request, which includes the session cookie and csrf token. Is this possible?

In other words, can I retrieve the authenticated user with only the laravel_session cookie, and XSRF-TOKEN?

I have tried creating a middleware which sets the cookies manually on the request, ready for the StartSession middleware however I've not been able to get this working. Is there a better approach?

0 likes
12 replies
martinbean's avatar

@fredpedersen Can you explain more what you’re trying to do and the problem you’re trying to solve? Because trying to parse cookies from a web sockets response in order to authenticate a user does not sound right at all.

fredpedersen's avatar

It sounds a bit mad yes. Essentially, I have a laravel website which uses hocuspocus to enable collaborative editing of a text document. Hocuspocus has a provider which is a JS library running on the web browser, which connects to the hocuspocus server via websockets. The hocuspocus server is written in JS and therefore must be run on Node.js or similar. I need to protect the websocket behind authentication so only registered users can access the text document.

Hocuspocus server provides two options for authentication - a manually written js hook, or via the webhook extension. The webhook extension can be configured to connect to a laravel api route to authenticate a user. The server passes the websocket request headers as well as any custom parameters set on the provider to the webhook as a json payload.

One more obvious option would be for laravel to create a token using sanctum or passport, pass this to the hocuspocus provider via something like window.accessToken, and authenticate using this in the webhook. This seems like a security issue however, as the access token would be available in plain text in the webpage html source. If an account was compromised, the hacker would be able to obtain the token. The user might reset their password however the token would still be functional. It also doubles the ways to access the data - via the token, and via username/password - doubling potential security issues. I'd prefer, given the cookies are sent in the websocket connection request anyway, to be able to authenticate the user using the cookies in the same way for normal web requests.

Does that make sense? It's a bit complex.

fredpedersen's avatar

@Sinnbeck Yep, they're using the access token approach, however as I described above this seems to be adding security vulnerabilities to the app. Anyone who gets hold of the access token has complete access, and the access token has to be sent in plaintext in the webpage html. Additionally, they've created their own token system instead of just using laravel sanctum which I'd imagine is more battle tested. Worth noting that library is marked as a draft and hasn't been updated since.

Sinnbeck's avatar

@fredpedersen you mean they can connect to the websocket server I assume? Just reading up on the package and hokuspokus. As far as I can see both the client key and a secret key on the server are sent to the backend and verified together

And I wouldn't use a draft package either :) just for inspiration

fredpedersen's avatar

@Sinnbeck yes exactly, which is a gateway to the vunerable data. The client/secret key is used to authenticate the connection between the nodejs server and the laravel webhook so you know the request has come from your nodejs server rather than somewhere else - I have no issue with this system. My problem is authenticating the connection between the frontend and the laravel webhook, which is going via the nodejs server.

Sinnbeck's avatar

@fredpedersen I cannot think of any way currently where there isn't a key of some sort in the users browser. My best idea currently is to make a unique key for a user and document combination. Then send this key along with an identifier for the document, to the websocket server. This can then be sent along with a secret to laravel which ensures all 3 are valid and the key + document identifier match. This was, if a key is ever obtained, it will only give access to one document. Furthermore all keys could expire after 12 hours or similar or perhaps even refresh on every page reload

fredpedersen's avatar

@Sinnbeck Yeah me too. There are keys already in the browser however, the session/csrf cookies. My understanding is that a normal laravel webpage request is authenticated using nothing more than these two keys, they also have built in expiry, can be disabled by the user logging out ect.

Fundamentally, laravel receives only the session/csrf cookies (via http headers) and returns the authenticated user. I'm hoping to utilise that system that's already in place and well tested. My theory was to simply write a middleware that would alter the request to insert the cookies into the headers, from the json payload, making the request compatible with the other built-in laravel middlewares that handle authentication and sessions. Would this work do you think or am I missing something?

Sinnbeck's avatar

@fredpedersen laravel uses an encrypted session to store the authentication details (user id). Csrf is just to prevent request tampering (and external requests) when doing post/put/patch./delete requests. But as you can verify a request comes from your websocket server using a secret, csrf can be disabled for this request. This is how we work with external webhooks as well.

Regarding the session. You cannot use this on your websocket server as its a session between the users browser and the backend server. If you allow tampering with this, you will most likely run into bigger security issues

fredpedersen's avatar

@Sinnbeck I've no need to use the session on the websocket server, it just needs to pass along the encrypted session to the backend laravel server. I was hoping to find a way to get the authentication details from the encrypted session in laravel. Normally this would be simple as the session is passed in the headers, and the middleware would take care of it. In this case, the session is being passed in the payload. Any idea how I can get the authentication details from it?

Sinnbeck's avatar

@fredpedersen do you mean you want to send the complete session from the browser to the websocket, which then sends it back to laravel, which then decrypts it and gets the id?

fredpedersen's avatar

@Sinnbeck Yes, essentially. Cookies get sent from the users browser to the websocket server (happens anyway), the websocket server passes these cookies onto the laravel server via a webhook. My script in the laravel server needs to then be able to access the authenticated user sending the original request.

I've actually just managed to get this working using a short middleware script that simply moves the cookies from the json payload in the $request->content to $request->cookies before any other middleware are applied. Then I'm using the 'web', 'auth', 'verified' middlewares to authenticate the user. This approach seems to work, my laravel script now has access to the user object in the normal way ($request->user())

Additionally, I've added a csrf token generated by laravel (csrf_token()) sent from the webscocket client, passed on by the websocket server, and then added to the $request->headers by my custom middleware. This is because websockets are vunerable to csrf hacks with the session cookie alone.

I think this is the best approach to authentication that I can see - it essentially keeps auth to the very tried and tested method of sending a session cookie in the http (in this case wss) request, with an additional csrf token.

Please or to participate in this conversation.