HyperSaaS
FrontendData Fetching

Server Actions

Server-side functions for auth and data operations.

Server actions are async functions marked with "use server" that run on the server. HyperSaaS uses them primarily for authentication flows.

Auth Actions

loginAction

// lib/auth/actions.ts
"use server";

export async function loginAction(formData: LoginFormData) {
  const validated = userLoginSchema.safeParse(formData);
  if (!validated.success) {
    return { error: "Invalid input" };
  }

  const result = await signIn("credentials", {
    email: validated.data.email,
    password: validated.data.password,
    redirect: false,
  });

  if (result?.error) {
    return { error: "Invalid email or password" };
  }

  return { success: true };
}

Used by the login form:

const result = await loginAction({ email, password });
if (result.error) {
  toast.error(result.error);
} else {
  router.push("/dashboard");
}

signOutAction

export async function signOutAction() {
  await signOut({ redirectTo: "/" });
}

Data Fetching Functions

While not technically "use server" actions, these async functions run on the server in server components:

getCurrentUserServer

Fetches the authenticated user's profile:

// lib/auth/session.ts
export async function getCurrentUserServer(): Promise<UserDetails | null> {
  const token = await getAccessToken();
  if (!token) return null;

  const res = await fetch(`${BACKEND_URL}/auth/users/me/`, {
    headers: { Authorization: `JWT ${token}` },
    cache: "no-store",
  });

  if (!res.ok) return null;
  return res.json();
}

getUserWorkspaces

Fetches all workspaces the user belongs to:

export async function getUserWorkspaces(): Promise<Workspace[]> {
  const { data } = await fetchApiListData("/api/workspaces/", workspaceSchema);
  return data ?? [];
}

getWorkspaceChatSessions

Fetches all chat sessions in a workspace:

export async function getWorkspaceChatSessions(
  workspaceId: string
): Promise<ChatSession[]> {
  const { data } = await fetchApiListData(
    `/api/workspaces/${workspaceId}/chats/`,
    chatSessionSchema
  );
  return data ?? [];
}

API Route Authentication Helper

API routes use a combined parse-and-authenticate helper:

// lib/auth/utils.ts
export async function parseContextAndAuthenticate(
  params: Promise<Record<string, string>>,
  paramsSchema: z.ZodSchema,
  req: Request,
  bodySchema?: z.ZodSchema
) {
  // 1. Parse URL params
  const resolvedParams = await params;
  const parsedParams = paramsSchema.parse(resolvedParams);

  // 2. Get JWT token
  const accessToken = await getAccessToken();
  if (!accessToken) throw new Error("Unauthorized");

  // 3. Parse request body (if provided)
  let parsedBody = undefined;
  if (bodySchema && req.method !== "GET") {
    const body = await req.json();
    parsedBody = bodySchema.parse(body);
  }

  return { ...parsedParams, accessToken, parsedBody };
}

Used in API route handlers:

export async function POST(req: Request, { params }) {
  const { workspaceId, accessToken, parsedBody } =
    await parseContextAndAuthenticate(
      params,
      z.object({ workspaceId: z.string().uuid() }),
      req,
      chatCreateSchema
    );

  const res = await fetch(`${BACKEND_URL}/api/workspaces/${workspaceId}/chats/`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `JWT ${accessToken}`,
    },
    body: JSON.stringify(parsedBody),
  });

  return Response.json(await res.json(), { status: res.status });
}

On this page