I do SSR auth. What's the best way to set up an authenticated client-side Realtime connection?
- 0
- Auth
- Web
- Realtime
- Cloud

I am currently handling authentication entirely server-side via an /api/auth
endpoint, so I don't have any Appwrite client instances running client-side.
However, Realtime requires being authenticated on the client side to stream events the user has access to.
My challenge is how to leverage the SSR auth I already have in place to securely authenticate a client-side Appwrite instance to subscribe to Realtime events. So far, I see two possible approaches:
- Return the session cookie in my server's
/api/auth
endpoint response and use it to authenticate the client-side Appwrite instance. - Reimplement client-side authentication, separate from my current SSR setup, to authenticate the Appwrite client directly.
For the first approach, I'm concerned that exposing the session cookie to JavaScript (even if it was originally set as httpOnly) opens up security vulnerabilities to XSS attacks or malicious browser extensions. For the second approach, it feels like a step backward in terms of developer experience. Additionally, maintaining both SSR and client-side authentication seems to violate DRY principles.
What’s the best approach to securely set up an authenticated client-side Appwrite Realtime connection without giving up on SSR auth?

i would suggest creating a cookie that will be sent to both your backend and Cloud. So in order to do that, assuming your have:
- appwrite endpoint: appwrite.myapp.com
- app: myapp.com
you'll need to create a cookie with
- name:
a_session_<project id>
- domain:
.myapp.com
I'm pretty sure the cookie will be sent to both your myapp.com and appwrite.myapp.com

Hi Steven, thank you for your response and suggestion.
I do currently have an implementation that gives me access to the session cookie on my backend and on the client. I am just concerned about the potential security risks of returning the session cookie to the client as part of my endpoint response (which theoretically makes it JavaScript-accessible, unlike returning it as a secure set-cookie header configured to be httpOnly
).
Another concern I have is that having an authenticated client-side Appwrite client instance (necessary to subscribe to Realtime events) eliminates the control I have over filtering and transforming the data I return to users through my Nuxt server functions. If clients can communicate directly with my Appwrite database without a server endpoint as an intermediary, the only control I have over what they get are explicit Appwrite resource permissions, which are a great baseline, but not as flexible as custom functions. But, I guess that's a different topic altogether. The only issue I currently have with the sharing of the session cookie approach is the risks it opens up.

you can make it so it's not accessible by javascript client-side

Do you mind sharing a pointer on how to go about that, please?

there are options on the cookie. like the httpOnly

Yes, but if I do that then I can't access the cookie with my client-side code, and so I can't use it to authenticate the client-side Appwrite client. That is precisely the reason I opened this thread. If the cookie is set to httpOnly
, it is secure, but can't be used client-side. On the other hand, if I return it as part of my API auth response payload, that breaches the security protections of httpOnly
, no?
Or maybe I'm wrong? Like, do you know if the data objects server endpoints in Next or Nuxt return can be accessed by malicious browser extensions or via an XSS attack? (assuming the fetch requests happen over https and the fetched data is never rendered, just used by Next or Nuxt internally)

you wouldn't access it with client-side code. the browser should send the cookie automatically

That's right. Currently, on my api/auth
endpoint, I get the cookie from the request to determine if a user is already authenticated, and use it to set a session in a server-side Appwrite client instance.
// this is a server-side util:
export function createSessionClient(event: H3Event<EventHandlerRequest>) {
const runtimeConfig = useRuntimeConfig(event)
const client = new Client()
.setEndpoint(runtimeConfig.public.appwriteEndpoint)
.setProject(runtimeConfig.public.appwriteProject)
const session = getCookie(event, SESSION_COOKIE)
if (session)
client.setSession(session)
const account = new Account(client)
const databases = new Databases(client)
return { account, databases }
}
Now, to subscribe to channels with Appwrite Realtime, I need to set up the connection using a client-side Appwrite client. I would like to use the same client.setSession(SESSION_COOKIE)
technique, but to do that I need to have access to the session cookie client-side. It is not enough that the browser automatically sends the cookie along with my request this time because, unlike my server endpoint, Appwrite doesn't automatically instantiate a new client instance and set its session based on the cookies the browser sent along. So, I need to authenticate the client-side Appwrite client instance myself, and to do so, I am currently returning the session cookie along with the response payload of my server auth API endpoint. Again, the problem with that approach is that, as far as I know, it bypasses the security protections of the cookie (even if it was initially set as httpOnly
), and exposes it to potential extraction by malicious client-side code, no?

I would like to use the same
client.setSession(SESSION_COOKIE)
technique instead of doingclient.setSession()
the idea is to have the cookie automatically send because that's how cookies work
Appwrite doesn't automatically instantiate a new client instance and set its session based on the cookies the browser sent along If set up as I suggested, the cookie should automatically be sent to the request to Appwrite and be authenticated
exposes it to potential extraction by malicious client-side code, no? Honestly, if you had an XSS vulnerability, you have way bigger problems

Thank you for your explanation. I believe I misunderstood your original suggestion, my apologies.
I'm currently developing my app in localhost, have no custom domain yet, and am using Appwrite's default endpoint (https://cloud.appwrite.io/v1').
In my api/auth
server endpoint, I have a login function where I am currently setting the session cookie:
// inside an event handler in /server/api/auth.ts:
const logIn = async (email: string, password: string) => {
const session = await authAccount.createEmailPasswordSession(email, password)
setCookie(event, SESSION_COOKIE, session.secret, {
httpOnly: true,
secure: true,
sameSite: 'strict',
expires: new Date(session.expire),
path: '/',
})
// ...update payload response object with user id and email
}
I would like to follow your suggestion of configuring the cookie with domain: '.myapp.com'
, but since I don't have a domain yet, and I am using Appwrite's default endpoint, I am not sure how to proceed. I thought of calling setCookie twice, once as it is now, and another with domain: 'cloud.appwrite.io'
but, if I remember correctly, it's not possible to set cookies for a third-party domain.
I guess for now, I could just add the session cookie to the payload response object and use it with setSession()
to authenticate the client-side Appwrite client instance that will establish the Realtime subscription. And, once I have a custom domain, then configure Appwrite's endpoint to live at appwrite.mydomain.com, and update the cookie definition in my logIn function to be automatically sent to .mydomain.com
, as you suggested.
Is this reasoning correct, or am I perhaps misunderstanding the challenge of configuring the session cookie for localhost
and cloud.appwrite.io
?
Thank you for your time and support.

Maybe you can update your hosts file to fake the hostname for local development

Thank you for the pointer! I'll look into doing that. Thanks again.

Sorry to revive this thread, but what solution did you eventually go with? Im facing the same exact type of issues, and even client.setSession with the cookie i return from my nextjs backend api route doesnt work. I can see that realtime connections work with collections with read "any" but not when requiring a valid session. @deusMarte
Recommended threads
- How to reduce DB Reads?
I just noticed that I hit the 500k db reads limit on my very small next js app with the most data being present in one collection having around 50 documents. ...
- Getting issue while migrating from Self ...
i try to migrating my project but when do this error come and dont allow to crate that migration
- Pending upload some file, but not for ot...
When upload this file, always got pending. But when I upload another file, it works. Why?
