Back

SvelteKit SSR Auth with OAuth

  • 0
  • Accounts
  • Web
Engineous
8 Jan, 2024, 10:10

Currently, in my SvelteKit Web Application, I'm using Appwrite as my DB and Authentication/User management backend. I'm using Discord OAuth with Appwrite to log the user in. Since I'm using OAuth, I can't follow this Appwrite SSR Auth with Svelte: https://github.com/Meldiron/appwrite-svelte-ssr because my server does not see the set-cookies headers, which contain the auth secret. As a result, I've had to come up with a workaround. As seen in the diagram attached, I end up making the client create a JWT which the server can use for SSR (very simplified). There are a few issues with this though:

  1. The JWT lasts for 15 minutes and then it expires due because of the way Appwrite works (https://appwrite.io/docs/references/cloud/client-web/account#createJWT)
  2. After 15 minutes, the client will still be logged in since it has the cookies from Appwrite, but the server will not because the JWT will have expired resulting in pretty bad desync
  3. When using the JWT on the server, there is no session linked (I can't use #getSession('current');), forcing me to add a Session Id cookie in order to get session info

These issues mean that my app is slower and users are limited to a ~15 minute session (because I don't want desync). In an ideal world, the cookie that Appwrite sets on the client (with the auth secret) would also be available to the server so that it can authenticate with the same thing. I'd like to know if there is a better way to do authentication with Appwrite, SvelteKit, and Discord OAuth. Or, if there is a way to not limit users to a 15 minute session. Also, I am aware of the third-party cookies stuff (https://appwrite.io/docs/advanced/platform/custom-domains#third-party-cookies), but I don't think that the solutions offered there would help in this case.

I may be wrong in some of my assumptions, so please correct me. If you could offer any help, it would be much appreciated!

TL;DR
The user is experiencing issues with SSR authentication using SvelteKit, Appwrite, and Discord OAuth. They are currently using a workaround involving creating a JWT on the client, but it has a 15-minute expiration time, causing server-client desync. The user is looking for a better authentication solution or a way to extend the session time. They are aware of third-party cookie limitations but don't believe it would help in this case. Another user suggests a potential workaround by creating a new JWT for each POST request, although it increases overhead. A PR to improve the SSR framework experience with OAuth is mentioned. The user cannot share their project repository
Engineous
8 Jan, 2024, 10:18

Sorry, in my diagram between the 2nd and 3rd step the client is redirected to Appwrites OAuth route, which then redirects to Discord's OAuth Gateway. This, though, does not really affect anything else I mentioned or have issues with.

Aditya Oberai
8 Jan, 2024, 11:41

@Engineous we are currently working on a solution to improve the SSR framework experience with OAuth https://github.com/appwrite/appwrite/pull/5777

I can try helping further but I might need a little more clarity on how exactly your server function is being called and how the interaction takes place, to figure out a workaround to the JWT expiration limit

Can you share your project repository by any chance?

Engineous
8 Jan, 2024, 19:35

Unfortunately, I'm not allowed to share the repo at this time. But I can share some snippets of code: +page.ts load function

TypeScript
        let id: string;
        let jwt: string;

        const sessionPromise = appwrite.account.getSession('current').then((result) => {
            id = result?.$id;
            if (id) console.log('Got session id');
            else throw new Error('Failed to get session');
        });

        const jwtPromise = appwrite.account.createJWT().then((result) => {
            jwt = result?.jwt;
            if (jwt) console.log('Created JWT');
            else throw new Error('Failed to create JWT');
        });

        // Running in parallel so it's faster
        await Promise.all([sessionPromise, jwtPromise]);

        const response = await fetch(url.href, {
            method: 'POST',
            headers: new Headers({
                'Content-Type': 'application/json'
            }),
            body: JSON.stringify({ jwt, id })
        });
        console.log('3');

        return;

+page.server.ts post endpoint

TypeScript
export const POST: RequestHandler = async ({ cookies, request }) => {
    const { jwt, id } = await request.json();

    const account = new Account(appwrite.client.setJWT(jwt));

    const session = await account.getSession(id);

    if (session?.$id !== id) throw new Error('Invalid session');

    // Set cookie to expire in 15 minutes, since the JWT will anyways
    cookies.set('jwt', jwt, {
        expires: new Date(
            Date.now() + 15 * 60 * 1000
        ),
        path: '/',
        secure: true,
        sameSite: 'lax'
    });

    cookies.set('id', id, {
        expires: new Date(
            Date.now() + 15 * 60 * 1000
        ),
        path: '/',
        secure: true,
        sameSite: 'lax'
    });

    return new Response();
};

Also, thanks for making me aware of that PR; when would you estimate it to be accepted and merged?

Aditya Oberai
9 Jan, 2024, 17:03

The timeline is expected in the very near future

One hack I can suggest is creating a new JWT everytime you need to create a POST request. This does increase the overhead for each request but it would prevent the 15 minute lifetime of the JWT from interfering with your functionality

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more