SvelteKit authentication issues with persistency

427 Views Asked by At

Issue Description:

  • I'm building a web application using Svelte and Node.js.
  • The application has user authentication using JWT tokens, and you store these tokens and user information in cookies.
  • The authentication status is not persisting between page refreshes. Even though you're seeing the tokens and user data in your console, the UI doesn't reflect the correct login/logout state.

Although I'm getting authToken, refreshToken cookies and userId each time I refresh my webpage, it's not being persistent

  1. Not logged In - I supposed to see Login/Registration
  2. Logged in - I supposed to see Logoug/Profile

When trying to logging in, I get to see Logout button, but on refresh it's gone (showing login/register again) although my console.log is showing that cookies and user data on page refresh are present

I tried to write stores to differentiate, but it's not helping. I'm connected to NodeJS server by the way. My Postman(backend) works like a charm, but frontend doesn't work well.


stores.ts

     import { writable } from 'svelte/store';
    
 export const UserId = writable(null);

export const setUserId = (id) => {
    UserId.set(id);
    return UserId;
};

// ---------------------------------------------

export const Authenticated = writable(false);

// Function to update the Authenticated store
export const setUserAuthenticated = (auth) => {
    Authenticated.set(auth);
    return Authenticated;
};

Navbar.svelte

     {#if $Authenticated}
                <div class="button-container">
                    <Button
                            element="a"
                            href="/profile"
                            variant="outline"
                            color="green">Profile
                    </Button>
                </div>
                <div class="button-container" on:click={handleSubmit}>
                    <Button
                            element="a"
                            href="/"
                            variant="outline"
                            color="red">Logout
                    </Button>
                </div>
            {:else }
                <div class="button-container">
                    <Button
                            element="a"
                            href="/login"
                            variant="outline"
                            color="green">Login
                    </Button>
                </div>
                <div class="button-container">
                    <Button
                            element="a"
                            href="/register"
                            variant="outline"
                            color="red">Registration
                    </Button>
                </div>
            {/if}

+layout.server.ts

import type { LayoutServerLoad } from './$types';
import jwt from "jsonwebtoken";
import {setUserAuthenticated, UserId} from "$helpers/stores";

export const load: LayoutServerLoad = async ({ cookies }) => {
    const authToken = cookies.get('auth-token');
    const refreshToken = cookies.get('refresh-token');

    console.log('Auth token in LAYOUT.SERVER::::::::: ', authToken);
    console.log('Refresh token in LAYOUT.SERVER::::::::: ', refreshToken);

    function handleAuthentication(authToken) {
        let userId = null;

        UserId.subscribe((uid) => {
            userId = uid;
        });

        if (!authToken) {
            console.log('No authToken present');
            setUserAuthenticated(false);
            return {
                user: null,
            };
        }

        try {
            const secretKey = 'farmTokenSecrets';
            const decodedAuthToken = jwt.verify(authToken, secretKey);
            userId = decodedAuthToken.userId ?? userId;
            setUserAuthenticated(true); // Update the Authenticated store
            console.log('User ID in LAYOUT.SERVER::::::::: ', userId);
            return {
                user: {
                    userId: userId,
                },
            };
        } catch (error) {
            console.error('Error decoding auth-token:', error);
            setUserAuthenticated(false);
            return {
                user: null,
            };
        }
    }


    return handleAuthentication(authToken);
};

Output on page refresh

1

There are 1 best solutions below

0
Mihai P. On

After digging around in the docs a bit, I believe this chapter in the docs should be exactly what you need. I mentioned in the comments that you shouldn't use stores in the load but I didn't mention what's the alternative (because I didn't know it for sure myself), but using the svelte context in combination with stores should be what you are looking for.