Better Auth with websockets

im trying to use better auth with websockets, where i get the user's session when they connect with api.getSession and use the bun websocket data to associate that with the connection (a new token is returned for the client to auth messages in that connection tho), is everything better auth needs to get a session from headers included in the initial request to open a websocket? cookies seem to be passed but i am getting a 401 on the initial request My frontend is astro, my backend is using Bun for the websocket and http api (was using express but the websocket stuff in bun is really nice and i am using mongoDB
23 Replies
Ping
Ping4w ago
If everything in the headers is correct it should be authorized correctly through a get-session call
lifeisfakenews
lifeisfakenewsOP4w ago
what headers are required? and does using ws instead of wss / localhost interfere with those just discovered i hadnt actually added the handler for the /api/auth routes - how can i do that if im using bun web server since the handler returned by toNodeHandler wants an argument for res which i dont have (also req is of the wrong type) - do i need to use a different intergration and if so which one? i have no idea what to do the express docs arent that great (altho ig i am using it an unintended way) pls help
LightTab2
LightTab24w ago
I am using jwt with session data for something similiar and pass it to the websocket connection, it seems like safer solution, it cannot be attacked via man in the middle
lifeisfakenews
lifeisfakenewsOP4w ago
using the jwt plugin?
LightTab2
LightTab24w ago
Yes If you support reconencting you need to remember to create a new JWT if previous one already expired though With socket.io it's considerably easier and I recommend using it, but if you want to stay with plain websockets you'd do something like this: client:
const ws = new WebSocket(`wss://[address]/ws?token=${token}`);
const ws = new WebSocket(`wss://[address]/ws?token=${token}`);
server: handle websocket upgrade event
Bun.serve({
port: 3000,
fetch(req, server) {
if (server.upgrade(req)) return;
return new Response("WebSocket server running");
},
websocket: {
open(ws) {
...
},
message(ws, message) {
...
},
},
upgrade(req, server) {
const url = new URL(req.url);
const token = url.searchParams.get("token");

try {
const JWKS = createRemoteJWKSet(new URL('http://[addressToBetterAuthServer]/api/auth/jwks'));
const { payload } = await jwtVerify(token, JWKS,
{ issuer: [your_issuer],
audience: [your_audience] });
return server.upgrade(req, { data: { user: payload } });
} catch {
return false; // reject connection
}
}
});
Bun.serve({
port: 3000,
fetch(req, server) {
if (server.upgrade(req)) return;
return new Response("WebSocket server running");
},
websocket: {
open(ws) {
...
},
message(ws, message) {
...
},
},
upgrade(req, server) {
const url = new URL(req.url);
const token = url.searchParams.get("token");

try {
const JWKS = createRemoteJWKSet(new URL('http://[addressToBetterAuthServer]/api/auth/jwks'));
const { payload } = await jwtVerify(token, JWKS,
{ issuer: [your_issuer],
audience: [your_audience] });
return server.upgrade(req, { data: { user: payload } });
} catch {
return false; // reject connection
}
}
});
lifeisfakenews
lifeisfakenewsOP4w ago
socket.io looks interesting but i will try using plain websockets first because im (in theory) most of the way there already
LightTab2
LightTab24w ago
Depends on what you are building, it might save you a lot of time implementing some of the things yourself (and networking is always painfully easy to overlook something). Migration is not so bad, safetyping is better as well, but yeah if you dont need it, you just dont need it. JWT here might be overkill too, but if you value time, I think it'd be faster to workaround your problem this way
lifeisfakenews
lifeisfakenewsOP4w ago
its effectivetly just to send notifications and display users status
LightTab2
LightTab24w ago
If you don't need robust reconnections, acks and very strong typing. I think it's okay to go with websockets here, but I am no expert
lifeisfakenews
lifeisfakenewsOP4w ago
thats what i was thinking, it isnt core to what im building i just need it to work having looked over this i have just realised is doesnt solve the problem of not being able to bind the better auth routes to Bun.serve (and ideally the api and the websocket stuff run on the same port/url/whatever)
LightTab2
LightTab24w ago
I didn't read your description with enough comprehension and thought websocker server is a separate thing to the server with better-auth, my bad
lifeisfakenews
lifeisfakenewsOP4w ago
it can be if it needs to but i would rather keep them together if possible since i would likely send things to the websocket from an api endpoint i thought i got it working, using auth.handler(req), but auth.api.getSession seems to not be sending requests to /api/auth/get-session - if i visit /api/auth/get-session, i get a 200 response with null and it is logged but when i call getSession it just returns null? does the backend bit not actually call the endpoints? am i fully yapping with this ^ does auth.api.getSession sned a request to the /api/auth/get-session endpoint? or are the endpoints only for the client methods
Ping
Ping4w ago
using the auth instance shouldn't make a request to your server
lifeisfakenews
lifeisfakenewsOP4w ago
so it doesnt actually matter that the /api/auth endpoints arent served by my api if i only use auth.api (server side stuff) -# ive wasted so much time
Ping
Ping4w ago
yeah
lifeisfakenews
lifeisfakenewsOP4w ago
what does it need from headers? just the better-auth.session_token cookie?
Ping
Ping4w ago
For endpoints that only require a session in headers, yeah
lifeisfakenews
lifeisfakenewsOP4w ago
is get session one of those i think it is
Ping
Ping4w ago
Yes
lifeisfakenews
lifeisfakenewsOP4w ago
would it being localhost and therefore http cause a problem - ive just noticed when deployed the cookie is called __Secure and secure attribute is true
Ping
Ping4w ago
If you don't want inconsistencies between localhost and prod then you can force enable secure on localhost too:
No description
Ping
Ping4w ago
Then treat everything with __Secure Not sure what you're doing, but this may help
lifeisfakenews
lifeisfakenewsOP4w ago
im deving on localhost ill try that it works now so thats good

Did you find this page helpful?