Search code examples
javascriptvue.jsnuxt.jsserver-side-renderingnuxtjs3

Using cookies in Nuxt 3 APIs and Middlewares


Is there a way to use cookies on server side in Nuxt 3? For example, I want to set cookie in API and then read its data in middleware:


// ~/server/api/testApi.ts

export default defineEventHandler(event => {
    /* setCookie('myCookie', 'myValue'); */
});

// ~/middleware/testMw.ts

export default defineNuxtRouteMiddleware((to, from) => {
    /* getCookie('myCookie'); */ // ~~> myValue
});

I tried to set cookie with useCookie in API but it is undefined in middleware. I also don't understand how to use getCookie in middleware because it needs the event object which is not present in middleware.

Context

I want to create a very simple auth system. In /api/auth.post.ts I create some kind of token which is saved in cookie. Then, in order to check, whether visitor is logged in I need to somehow retrieve this token back from cookie in /middleware/logged.ts.

I am open to other suggestions.


Solution

  • You have to define a plugin to initial values from cookies via pinia, before you use them in middlewares.


    For example, there is a value: theme in cookie

    // store/theme.ts
    
    import { defineStore } from 'pinia';
    import Cookie from 'js-cookie'; // you can use any Cookie packages you want
    
    export const useThemeStore = defineStore('theme', {
        state: () => ({
            _theme: {}
        }),
        getters: {
            theme: (state) => stats._theme
        },
        actions: {
            setTheme (value: 'light' | 'dark' | 'system') {
                // update the value in both cookie and memory
                this._theme = value;
                Cookie.set('theme', value);
            }
        }
    });
    

    define a plugin to boot the store

    // plugin/initial.ts
    
    import Cookie from 'js-cookie';
    import { useThemeStore } from '~/stores/theme';
    
    function cookieFromRequestHeaders (key: string) {
        const headers = useRequestHeaders(['cookie']);
        if ('cookie' in headers) {
            const cookie = headers.cookie?.split(';').find(
                c => c.trim().startsWith(`${key}=`)
            );
            if (cookie) {
                return cookie.split('=')[1];
            }
        }
        return undefined;
    }
    
    export default defineNuxtPlugin(async (nuxtApp) => {
    
        const theme = cookieFromRequestHeaders('theme') ?? Cookie.get('theme') ?? 'system';
    
        const themeStore = useThemeStore(nuxtApp.$pinia as Pinia);
    
        themeStore.setTheme(theme);
    });
    

    Now, you can use it in middlewares

    import { useThemeStore } from '~/stores/theme';
    
    export default defineNuxtRouteMiddleware((to) => {
    
        const themeStore = useThemeStore();
    
        if (themeStore.theme === 'dark') {
            return navigateTo('/dark-index');
        }
    });
    

    A js-version full example with auth is here, which is SSR, feel free to star it :)


    2024/06/17 update

    Using useCookie instead of a custom cookie handler could be a better choice, which is friendly for both client side and server side

    // plugin/initial.ts
    
    import { useThemeStore } from '~/stores/theme';
    
    export default defineNuxtPlugin(async (nuxtApp) => {
    
        const theme = useCookie<'system'|'light'|'dark'>('theme', {
            default: () => 'system',
        });
    
        const themeStore = useThemeStore(nuxtApp.$pinia as Pinia);
    
        themeStore.setTheme(theme);
    });