Next.js Discord

Discord Forum

Auth state in Server-Side with Appwrite and NextJS App Router

Unanswered
Pacific herring posted this in #help-forum
Open in Discord
Pacific herringOP
Well I know it's a recurring topic but beginner on NextJS and not being very familiar with the notions Server-Side and Client-Side I need your help. So I have a NextJS app using Appwrite for the backend (alternative to Firebase and Supabase). Here is my user.tsx hook file:

11 Replies

Pacific herringOP
"use client"

import React, {createContext, useContext, useState, useEffect } from 'react'
import { account, databases } from '@/utils/appwrite'

export interface UserState {
    user: any;
    userLoading: boolean;
    login: (email: string, password: string) => Promise<void>;
    logout: () => Promise<void>;
    signup: (email: string, name: string, username: string, password: string) => Promise<void>;
}

const defaultState: UserState = {
    user: null,
    userLoading: true,
    login: async () => {},
    logout: async () => {},
    signup: async () => {},
}

// create the context
const UserContext = createContext<UserState>(defaultState);

// create the provider component
export const UserProvider = ({ children } : { children: any }) => {
    const [ user, setUser ] = useState<null | any>(null);
    const [ userLoading, setUserLoading ] = useState(true);

    useEffect(() => {
        const chekcUser = async () => {
            try {
                const userRequest = await account.get();
                const userDetails = await databases.getDocument(String(process.env.NEXT_PUBLIC_APPWRITE_DATABASE_USERS), String(process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USER), userRequest.$id)
                setUser({
                    ...userRequest,
                    username: userDetails.username,
                    avatar: userDetails.avatar,
                    language: userDetails.language,
                })
            } catch (error) {
                setUser(null)
            } finally {
                setUserLoading(false)
            }
        }
        chekcUser();
    }, [])

    const login = async (email: string, password: string) => {
        try {
            await account.createEmailSession(email, password);
            const userRequest = await account.get();
            const userDetails = await databases.getDocument(String(process.env.NEXT_PUBLIC_APPWRITE_DATABASE_USERS), String(process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USER), userRequest.$id)
            setUser({
                ...userRequest,
                username: userDetails.username,
                avatar: userDetails.avatar,
                language: userDetails.language,
            })
        } catch (error) {
            throw error
        }
    }

    const logout = async () => {
        try {
            await account.deleteSession('current');
            setUser(null);
        } catch (error) {
            throw error
        }
    }

    const signup = async (
        email: string, 
        name: string, 
        username: string, 
        password: string
    ) => {
        try {
            const {$id} = await account.create('unique()', email, password, name)
            await account.createEmailSession(email, password);
            await databases.createDocument(String(process.env.NEXT_PUBLIC_APPWRITE_DATABASE_USERS), String(process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USER),$id, {
                "userId": $id,
                "username": username
            });
            await account.createVerification(process.env.NEXT_PUBLIC_URL + '/verifyEmail')
            const userRequest = await account.get();
            const userDetails = await databases.getDocument(String(process.env.NEXT_PUBLIC_APPWRITE_DATABASE_USERS), String(process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_USER), userRequest.$id)
            setUser({
                ...userRequest,
                username: userDetails.username,
                avatar: userDetails.avatar,
                language: userDetails.language,
            })
        } catch (error) {
            throw error
        }
    }
    return (
        <UserContext.Provider value={{ user, userLoading, login, logout, signup }}>
            {children}
        </UserContext.Provider>
    )
}

// create the custom hook
export const useUser = () => useContext(UserContext);

Sorry for the length (I'm trying to give as much context as possible)
To get the auth state in my pages I use :
const { user } = useUser();

But its client side, how can I do to load the user state in server-side ? Because I have component which flash time to get user state. And I also want to create a middleware to disable access to pages for non-logged in people
you need to move your logic away from localstorage to do so. cookies, or database sessions etc
@DirtyCajunRice | AppDir you need to move your logic away from localstorage to do so. cookies, or database sessions etc
Pacific herringOP
Seems to be quite complicated haha. But if necessary I would do it but is it advisable to have the auth state in the server-side rather than the client-side? I mean is this the common way it should be
@DirtyCajunRice | AppDir yep. pretty common. and complicated is relative to the person i guess.
Pacific herringOP
yeah im a beginner ahah
@DirtyCajunRice | AppDir yep. pretty common. and complicated is relative to the person i guess.
Pacific herringOP
Im asking if its common because its weird that Appwrite dont gave a function like Supabase to check the user state in server-side
Pacific herringOP
Well ive discuss about the idea with appwrite team and seems pretty useless to use SSR with Appwrite. Its pretty hard to impletment and add skeleton when loading user state is propabbly easier
@DirtyCajunRice | AppDir sounds like a team stuck in the past
Pacific herringOP
a member of the appwrtie team made this example :
https://github.com/Meldiron/appwrite-next13-ssr/tree/main
And he told me " SSR is very very complex and doesn't give as much benefits."