Open kacperkwapisz opened 1 month ago
I had the same issue. I fixed it as follows. This code could use some clean up, but it works.
import type { TypedPocketBase } from "@/types/pocketbase-types";
import type { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
import { cookies } from "next/headers";
import PocketBase from "pocketbase";
export const parseCookie = (str: string) =>
Object.fromEntries(
str.split("; ").map((v) => v.split(/=(.*)/s).map(decodeURIComponent)),
);
export const setAuthCookie = (pb: PocketBase) => {
const authCookie = parseCookie(
pb.authStore.exportToCookie({ httpOnly: false }),
);
cookies().set("pb_auth", authCookie.pb_auth, {
httpOnly: false, // This is important!!!
path: "/",
expires: new Date(authCookie.Expires),
});
};
export function createServerClient(cookieStore?: ReadonlyRequestCookies) {
if (!process.env.NEXT_PUBLIC_POCKETBASE_API_URL) {
throw new Error("Pocketbase API url not defined !");
}
if (typeof window !== "undefined") {
throw new Error(
"This method is only supposed to call from the Server environment",
);
}
const client = new PocketBase(
process.env.NEXT_PUBLIC_POCKETBASE_API_URL,
) as TypedPocketBase;
if (cookieStore) {
const authCookie = cookieStore.get("pb_auth");
if (authCookie) {
client.authStore.loadFromCookie(`${authCookie.name}=${authCookie.value}`);
}
}
return client;
}
let singletonClient: TypedPocketBase | null = null;
export function createBrowserClient() {
if (!process.env.NEXT_PUBLIC_POCKETBASE_API_URL) {
throw new Error("Pocketbase API url not defined !");
}
console.log(
"process.env.NEXT_PUBLIC_POCKETBASE_API_URL",
process.env.NEXT_PUBLIC_POCKETBASE_API_URL,
);
const cookie = parseCookie(document.cookie).pb_auth;
if (!cookie) {
throw new Error("Auth cookie not found");
}
const createNewClient = () => {
const client = new PocketBase(
process.env.NEXT_PUBLIC_POCKETBASE_API_URL,
) as TypedPocketBase;
client.authStore.loadFromCookie(`pb_auth=${cookie}`);
return client;
};
const _singletonClient = singletonClient ?? createNewClient();
if (typeof window === "undefined") return _singletonClient;
if (!singletonClient) singletonClient = _singletonClient;
singletonClient.authStore.onChange(() => {
document.cookie = singletonClient!.authStore.exportToCookie({
httpOnly: false,
});
});
return singletonClient;
}
Also, set the cookie on login.
./login/page.tsx
import { login } from "./page.action";
import classes from "./page.module.css";
export default function Page() {
return (
<main className={classes.main}>
Login form
<form className={classes.form} action={login}>
<label className={classes.label}>
E-mail
<input name="email" type="email" />
</label>
<label className={classes.label}>
Password
<input name="password" type="password" />
</label>
<button type="submit">Login</button>
</form>
</main>
);
}
./login/page.action.ts
"use server";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import { setAuthCookie } from "@/utils/pocketbase";
import PocketBase from "pocketbase";
export async function login(formData: FormData) {
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_API_URL);
const authData = await pb.admins.authWithPassword(email, password);
const isValid = pb.authStore.isValid;
console.log(`is valid: ${isValid}`);
if (!isValid) {
redirect("/?error=invalid-credentials");
return;
}
setAuthCookie(pb);
redirect("/dashboard");
}
export async function logout() {
const pb = new PocketBase(process.env.POCKETBASE_URL);
pb.authStore.clear();
redirect("/");
}
./login/page.module.css
.main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;
}
.form {
display: flex;
flex-direction: column;
gap: 10px;
max-width: 300px;
}
.label {
display: flex;
flex-direction: column;
gap: 5px;
}
Hi so, I have been struggling for the last 3-4 days trying to get everything set up. Yesterday I noticed that createBrowserClient seems not to be initiated correctly and does not have the auth store set.
This is my login function:
After that, I want to access the pocketbase authStore on a client component with createBrowserClient but the authStore is empty.
Would love your help here because if not, I will need to switch to something else, I really wanted to use pocketbase.