#[Solved] Security Concern regarding the tutorial for Next.js Auth

12 messages · Page 1 of 1 (latest)

feral dust
#

In the tutorial we have:

// src/lib/server/appwrite.js
"use server";
import { Client, Account } from "node-appwrite";
import { cookies } from "next/headers";

export async function createSessionClient() {
  const client = new Client()
    .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
    .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT);

  const session = cookies().get("my-custom-session");
  if (!session || !session.value) {
    throw new Error("No session");
  }

  client.setSession(session.value);

  return {
    get account() {
      return new Account(client);
    },
  };
}

export async function createAdminClient() {
  const client = new Client()
    .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
    .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT)
    .setKey(process.env.NEXT_APPWRITE_KEY);

  return {
    get account() {
      return new Account(client);
    },
  };
}

This essentially makes the createAdminClient (and all other exported functions) into an endpoint anyone could use. Is this on purpose?

Source: https://appwrite.io/docs/tutorials/nextjs-ssr-auth/step-3

Add authentication to a Next.js project using Appwrite.

charred tundra
feral dust
#

No, in Next.js 14+, using "use server" ensures that functions run on the server. But all the exported functions in the file are still accessible from the client unless you secure and protect their usage (i.e. check role and permissions before allowing full execution).

This means sensitive logic, like createAdminClient (I assume this is sensitive) and createSessionClient, should likely not be exposed here and should be moved to a protected API route or require proper authorization checks to avoid misuse.

Also: using the pages directory for API routes is becoming outdated in newer Next.js versions. It's now recommended to use the app directory structure, which aligns with modern Next.js practices for server-side logic and better organizationn

#

For now until I learn more about Appwrite SDK (server), I got this to work by not exposing these two Appwrite functions (I just kept them in appwrite.ts. Also installed and added added import "server-only" as a safety measure to throw an error if this somehow becomes leaked to the client.

Then I only exposed a another "use server" file with a single exported method for checking if user is logged in, and to get the users' roles.

charred tundra
feral dust
#

To keep it simple: Would there be potential harm exposing/returning the Account from either of these methods to the client? If there is no harm, then this is fine. If this was not intentional to expose these two exported endpoints, then it needs to be addressed

charred tundra
radiant cypress
# feral dust No, in Next.js 14+, using `"use server"` ensures that functions run on the serve...

I think that isn't true. Next.js 14+ does not create an endpoint for each server action. You need to explicitly expose the function action. That is why you have the app/api (https://nextjs.org/docs/pages/building-your-application/routing/api-routes) or Route Handlers (https://nextjs.org/docs/app/building-your-application/routing/route-handlers)

I have test creating a server action and try to call it from the browser, and it doesn't work

You can check more information here:

https://github.com/vercel/next.js/discussions/66701
https://www.linearloop.io/blog/nextjs-use-client-vs-use-Server
https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations

feral dust
#

With Next.js 14+, we don’t need to explicitly set up an API route or handler to use a server action function. The use server directive allows server actions to be invoked directly from components, which means that when a function is marked with use server, it can still be accessed if called from the client-side, even without an API route.

From the API Reference: 'use server' marks server-side functions that can be called from client-side code.

That’s why I was concerned about the potential exposure of sensitive functions like createAdminClient, because while these server actions run on the server, they can still be triggered by the client-side. If there's any sensitive logic in them, it could pose a risk if not properly protected with authorization or role checks.

However, if there is no harm in exposing those two functions (or rather, if it’s completely safe to expose the returned object from those functions), then this is all good.

My goal is not to be right or wrong, but to determine whether or not the objects are safe to expose to the client. If they are safe, I’ll move on. If not, I’ll continue testing. 😅

charred tundra
radiant cypress
# feral dust Can we?

As developer you can expose a server componet, and pass a server action, but the server action it won't be visible to the user (the code). So it isn't a security problem, you can test that.
If for some reason you expose an API key, you can remove the API key from the console and it will make it invalid.

Talking specifically from appwrite examples, it's secure to use and you won't be exposing any API key to the client if you follow that tutorial. Make sure not to use NEXT_PUBLIC_ to store your key in .env