Next.js Discord

Discord Forum

Need guidance with authentication

Answered
North Pacific hake posted this in #help-forum
Open in Discord
North Pacific hakeOP
Hi there I am new to NextJS, I have used React mostly for all front end related things and decided to give it a go and have been learning NextJS for a few days now. I am having trouble understanding how authentication would be done. I am using PocketBase for the database and I am having trouble authenticating.

So far when the user logs in I am sending a cookie that gets stored, however further than that I am unable to figure out how to verify the user. Can someone point me in the right direction when it comes to authenticating with PocketBase? Am I missing a library? Thank you!
Answered by Ray
db.authStore.loadFromCookie(request.cookies.get("pb_auth")?.value || "");
View full answer

52 Replies

@Ray you need to re-create the pocketbase instance with the cookies like this ts const cookieStore = cookies(); const cookie = cookieStore.get('pb_auth'); pb.authStore.loadFromCookie(cookie?.value || '');
North Pacific hakeOP
this is where i got stuck basically when i came across answers like this, for api its easier to verify but i am not sure where i would go to achieve this, i was thinking middleware but i havent been able to get it working. additionally reading github threads people say that nextjs middleware isnt like regular middleware since you cant set the data?
you can create the pb instance in middleware and verify the user there
// lib/pocketbase.ts
export const pb = new Pocketbase(
  `${
    process.env.NODE_ENV === "production"
      ? "http://pb:8080"
      : process.env.PB_URL
  }`
);

export function getPockbase(cookie?: string | undefined) {
  if (cookie) pb.authStore.loadFromCookie(cookie);
  return pb;
}

// middelware.ts
export default async function middleware(req: NextRequest) {
  const pb = getPockbase(req.cookies.get(COOKIE_NAME)?.value);

  if (req.method == "GET" && pb.authStore.isValid) {
    const res = NextResponse.next();

    pb.authStore.onChange(() => {
      res.headers.append(
        "Set-Cookie",
        `${COOKIE_NAME}=${pb.authStore.exportToCookie()}`
      );
    });

    try {
      await pb.collection("users").authRefresh();
    } catch (_) {
      pb.authStore.clear();
      return NextResponse.redirect(new URL("/login", req.url));
    }

    return res;
  }
}

i was using these code and it work fine
North Pacific hakeOP
thank you let me try this out
export function getPostById(
  id: string,
  { cookie }: { cookie?: string | undefined } = {}
) {
  const pb = getPockbase(cookie);

  return unstable_cache(
    (id: string) =>
      pb
        .collection("posts")
        .getOne(id, { expand: `user, post_reactions(post)` })
        .catch(() => null),
    ["post"],
    {
      tags: [`post-${id}`],
      revalidate: isProd ? 1800 : 1,
    }
  )(id);
}

and this code to get data
so that the client saves it
ive managed to pass the cookie to my middleware however the middleware kept saying that isValid is false
export async function login(prevState: any, formData: FormData) {
  const parsed = loginSchema.safeParse(Object.fromEntries(formData.entries()));
  if (!parsed.success) {
    return {
      errors: parsed.error.flatten().fieldErrors,
    };
  }

  const { email, password } = parsed.data;
  const pb = getPockbase();
  try {
    await pb.collection("users").authWithPassword(email, password);
  } catch (error) {
    return {
      errors: {
        email: "The email or password is incorrect",
        password: "The email or password is incorrect",
      },
    };
  }
  cookies().set(
    COOKIE_NAME,
    pb.authStore.exportToCookie({ httpOnly: true, sameSite: "lax" })
  );

  const redirectTo = formData.get("redirectTo");
  redirectTo ? redirect(String(redirectTo)) : redirect("/");
}
this is the server action for login
North Pacific hakeOP
i basically just have this in my login

    db.authStore.exportToCookie((options = {}), (key = "pb_auth"));
so you didn't set it to cookies?
North Pacific hakeOP
i guess not, previously i set the cookie by hand like so
    const response = NextResponse.json(
      { token: authData.token },
      { status: 200 }
    );
    const cookieValue = `token=${authData.token}; Path=/; HttpOnly; Secure; SameSite=Strict`;
    response.headers.set("Set-Cookie", cookieValue);
let me try your method
North Pacific hakeOP
yes for /login
yes you set it wrong there
you need to set it like this token=${db.authStore.exportToCookie((options = {}), (key = "pb_auth"));}
pb convert the user obj to cookie
not just the token
North Pacific hakeOP
i see, let me give this a go real quick
@Ray
cookies().set( COOKIE_NAME, pb.authStore.exportToCookie({ httpOnly: true, sameSite: "lax" }) );

this seems cleaner way to do it like you did it will this work for me?
it work in server action
North Pacific hakeOP
not for route?
not sure will it work in route handler but the doc said it does
North Pacific hakeOP
ok i try
does COOKIE_NAME matter?
its up to you
North Pacific hakeOP
this is how it should look like correct?
im still not able to get a isValid back as true
yes
North Pacific hakeOP
export const middleware = async (request) => {
  // console.log(`${request.method}: ${request.url}`);
  console.log(request.cookies);
  db.authStore.loadFromCookie(request.cookies.get("pb_auth") || "");
  console.log(db.authStore);
  return NextResponse.next();
};
North Pacific hakeOP
import PocketBase from "pocketbase";

const db = new PocketBase("http://127.0.0.1:8090/");

export default db;
db.authStore.loadFromCookie(request.cookies.get("pb_auth")?.value || "");
Answer
its on value
North Pacific hakeOP
worked 😅
thank you so much bossman
that's why you should use typescript :lolsob:
North Pacific hakeOP
i ended up finishing the certificate when doing fullstackopen for TS however i found it not really enjoyable to use
i guess suffer now to not suffer later
fianlly it came back to bite me in the ass for not using it
lol
North Pacific hakeOP
thank you again fellow orange name with a surprisingly specifically similar setup (nextjs + pb)
no prob