how to set a cookie from server component into a client context
Unanswered
Wool sower gall maker posted this in #help-forum
Wool sower gall makerOP
import {createContext, ReactNode, useContext, useState} from 'react';
interface AuthContextProps {
isAuthenticated: boolean;
login: () => void;
logout: () => void;
}
const AuthContext = createContext<AuthContextProps | undefined>(undefined);
interface AuthProviderProps {
children: ReactNode;
}
export const AuthProvider = ({children}: AuthProviderProps) => {
const [isAuthenticated, setAuthenticated] = useState(false);
const login = () => {
setAuthenticated(true);
console.log("setAuthenticated to true");
};
const logout = () => {
setAuthenticated(false);
console.log("setAuthenticated to false");
};
return (
<AuthContext.Provider value={{isAuthenticated, login, logout}}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};70 Replies
Wool sower gall makerOP
export default async function Auth() {
// const {isAuthenticated, login, logout} = useAuth();
const cookieStore = cookies();
const cookie = cookieStore.get("bestCookieEver");
if (cookie === undefined) return;
const x = await fetch("http://localhost:3001/api/auth/status", {
method: 'GET',
credentials: 'include',
cache: 'no-store',
headers: {
'Content-Type': 'application/json',
'Cookie': `${cookie.name}=${cookie.value}`
},
});
if (x.ok) {
// login();
}
console.log("yo", x.status);
return (
<>
{/*<p>My cookie value: {cookie}</p>*/}
{cookieStore.getAll().map((cookie) => (
<div key={cookie.name}>
<p>Name: {cookie.name}</p>
<p>Value: {cookie.value}</p>
</div>
))}
</>
)so im getting my cookie but i cannot use my useAuth() hook then how can i solve the problem?
@Wool sower gall maker so im getting my cookie but i cannot use my useAuth() hook then how can i solve the problem?
why you cannot use
useAuth() hook?Wool sower gall makerOP
because next js tells me i need a client component to use it
@Wool sower gall maker because next js tells me i need a client component to use it
what are you trying to do?
Wool sower gall makerOP
./src/components/auth-provider.tsx
Error:
× You're importing a component that needs createContext. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.you can make a client component and pass the data from server component
and you use useAuth hook in it
Wool sower gall makerOP
so i have an api where i login via discord. then the api sets a cookie in my browser now i want to check if the cookie is there if so im logged in
@Ray you can make a client component and pass the data from server component
Wool sower gall makerOP
okay how would that look like in a basic example just a component add it in the Auth() comopnent?
well, you can do it on serverside
async function getAuth() {
const cookieStore = cookies();
const cookie = cookieStore.get("bestCookieEver");
if (cookie === undefined) return;
const x = await fetch("http://localhost:3001/api/auth/status", {
method: 'GET',
credentials: 'include',
cache: 'no-store',
headers: {
'Content-Type': 'application/json',
'Cookie': `${cookie.name}=${cookie.value}`
},
});
return x
}Wool sower gall makerOP
i just want that
if (x.ok) {
// login();
}ah you mean i put this into a function then make the component a "use client"?
no you don't need context at all. create a server action for login and logout
Wool sower gall makerOP
okay ill try
export default async function Page() {
const auth = await getAuth()
if (!auth) redirect('/login')
return (
...
)
}@Ray ts
export default async function Page() {
const auth = await getAuth()
if (!auth) redirect('/login')
return (
...
)
}
Wool sower gall makerOP
but this should be a client component then so i cannot use await in there
@Wool sower gall maker but this should be a client component then so i cannot use await in there
no this is serer component
Wool sower gall makerOP
hmm okay i need to understand the workflow first xD
good course with the code example
Wool sower gall makerOP
yea i already did it but i dont know feeling kinda stupid
also i dont understand because i tried something
a "use client" is also a se3rver component in the beginning
if you disable js in the browser i see my client components already
so after that next js do some magic
because client component are also prerendering on server
that's what page router does
Wool sower gall makerOP
thank u so much ray
@Ray no prob
Wool sower gall makerOP
hey ray I solved the problem but now i have the problem if i delete the cookie and select a different page where i check if im authed on my api next js is not sending a request its cached by the link component how can i disable this?
only if i do a page reload after the token got deleted im logged out as expected
but i also want to logged out when i press somewhere else on my webpage
export default async function DashboardPage() {
const auth = await getAuth();
if(!auth) redirect("/login");
return (<>Dashboard</>)
} like this if i press the dashboard link on my page the getAuth isnt calledexport function MainNav({items, auth}: MainNavProps) {
const pathname = usePathname()
return (
<div className="flex gap-6 md:gap-10">
<Link href="/" className="hidden md:flex items-center space-x-2">
<Icons.logo className="mr-2 h-4 w-4"/>
<span className="inline-block font-bold">{siteConfig.name}</span>
</Link>
{items?.length ? (
<nav className="hidden md:flex gap-6">
{items?.map(
(item, index) =>
item.href && (!item.requiresAuth || (item.requiresAuth && auth)) && (
<Link
key={`${index}-${item.title}`}
href={item.href}
className={cn(
"flex items-center text-sm font-medium text-muted-foreground transition-colors hover:text-foreground/80",
pathname === `${item.href}` ? "text-foreground border-b-2" : "text-foreground/60",
item.disabled ? "bg-red-500" : "",
)}
>
{item.title}
</Link>
)
)}
</nav>
) : null}
</div>
)
} because these are links and i guess they get cachedWool sower gall makerOP
just deleting it in the browser
the case when the user deletes his browser data
and he is currently logged in on the webpage
@Wool sower gall maker just deleting it in the browser
if you delete with server action, it should revalidate the router cache
Wool sower gall makerOP
yea this works
if you delete from browser, you gotta refresh the page
Wool sower gall makerOP
yea but how do i know xD
if it got deleted
can i just disable the cache on the navbar links?
router cache is impossible to disable atm
30s for dynamic page
@Wool sower gall maker ts
export default async function DashboardPage() {
const auth = await getAuth();
if(!auth) redirect("/login");
return (<>Dashboard</>)
}
like this if i press the dashboard link on my page the getAuth isnt called
well if you are building dashboard and SEO is not important, you could wrap the page with a client component like this
'use client'
export function CheckAuth({children}) {
const [loading, setLoading] = useState(true)
const router = useRouter();
useEffect(() => {
const abortController = new AbortController()
fetch("/api/auth", { signal: abortController.signal })
.then((res) => res.json())
.then((auth) => {
if (!auth) router.push("/");
setLoading(false)
});
return () => {
abortController.abort()
}
}, [router]);
if (loading) return <div>loading...</div>
return (
<>
{children}
</>
)
}
// page.tsx
export default async function DashboardPage() {
return (
<CheckAuth>
<main></main>
</CheckAuth>
)
}Wool sower gall makerOP
yea seo is not important
@Wool sower gall maker yea seo is not important
and wrap every page with the
<CheckAuth />Wool sower gall makerOP
thx
@Ray and wrap every page with the `<CheckAuth />`
Wool sower gall makerOP
the problem is now how can i access the cookie in the CheckAuth ?
do i need to pass it to the client component?
i dont know why but i only get the cookie in a server component i tried different librarys js-cookie react-cookie always undefinded cookie despite he is present in the browser
@Wool sower gall maker the problem is now how can i access the cookie in the CheckAuth ?
the cookie should send alone with the request
have you tried fetching it
Wool sower gall makerOP
yea my api tells me not authorized
Accessing: /api/auth/status
User not authenticatedthis is the console.log of my api
but the cookie is present
in the browser
does your backend check for header or cookies
Wool sower gall makerOP
thats a good question i dont know how passport with discord strategy is doing it
@Wool sower gall maker do i need to pass it to the client component?
simple pass it from server componet
Wool sower gall makerOP
ok
Wool sower gall makerOP
well i just ignore it for now its not working i dont know why
middleware function
export const authenticateUser = (
req: Request,
res: Response,
next: NextFunction
) => {
console.log("Accessing:", req.originalUrl);
if (req.user) {
console.log("Successfully authenticated user");
next();
} else {
console.log("User not authenticated");
res.sendStatus(403);
}
}this is what my api does
and i dont know whats happening exactly in req.user how passport is checking the cookie - I basically copy pasted the code from the passport tutorial.