+
+ ```tsx title="app/dashboard/page.tsx"
+ import { stackServerApp } from "@/stack/server";
+
+ export default async function DashboardPage() {
+ const user = await stackServerApp.getUser();
+
+ if (!user) {
+ return You are not signed in.
;
+ }
+
+ return Hello, {user.displayName ?? user.primaryEmail ?? user.id}
;
+ }
+ ```
+
+
+ ```tsx title="app/app/page.tsx"
+ import { stackServerApp } from "@/stack/server";
+
+ export default async function AppHomePage() {
+ const user = await stackServerApp.getUser({ or: "redirect" });
+ return Hello, {user.displayName ?? user.primaryEmail ?? user.id}
;
+ }
+ ```
+
+
+ ```tsx title="components/greeting.tsx"
+ "use client";
+
+ import { useUser } from "@stackframe/stack";
+
+ export function Greeting() {
+ const user = useUser();
+
+ if (!user) {
+ return Please sign in.
;
+ }
+
+ return Hello, {user.displayName ?? user.primaryEmail ?? user.id}
;
+ }
+ ```
+
+
+ ```tsx title="components/greeting.tsx"
+ "use client";
+
+ import { useUser } from "@stackframe/stack";
+
+ export function Greeting() {
+ const user = useUser({ or: "redirect" });
+ return Hello, {user.displayName ?? user.primaryEmail ?? user.id}
;
+ }
+ ```
+
+
+
+### Server action that requires a user
+
+`{ or: "throw" }` is useful when a redirect would be wrong (for example, from a form POST). The example below only needs Stack for identity; your own persistence layer stores product data keyed by `user.id`.
+
+```tsx title="app/actions/onboarding.ts"
+"use server";
+
+import { stackServerApp } from "@/stack/server";
+
+export async function completeOnboardingStepAction(formData: FormData) {
+ const user = await stackServerApp.getUser({ or: "throw" });
+ const step = String(formData.get("step") ?? "").trim();
+ if (!step) {
+ throw new Error("Step is required");
+ }
+
+ // TODO: write to your database using user.id as the tenant key (or your own model).
+ return { userId: user.id, step };
+}
+```
+
+### Route Handler (App Router API)
+
+```tsx title="app/api/me/route.ts"
+import { stackServerApp } from "@/stack/server";
+import { NextResponse } from "next/server";
+
+export async function GET() {
+ const user = await stackServerApp.getUser();
+ if (!user) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ return NextResponse.json({
+ id: user.id,
+ displayName: user.displayName,
+ primaryEmail: user.primaryEmail,
+ });
+}
+```
+
+### Middleware for a `/app` (or `/private`) section
+
+Match only the routes that should be gated, and **exclude** `/handler` so Stack’s auth pages keep working:
+
+```tsx title="middleware.ts"
+import { NextRequest, NextResponse } from "next/server";
+import { stackServerApp } from "@/stack/server";
+
+export async function middleware(request: NextRequest) {
+ const user = await stackServerApp.getUser();
+ if (!user) {
+ return NextResponse.redirect(new URL("/handler/sign-in", request.url));
+ }
+ return NextResponse.next();
+}
+
+export const config = {
+ matcher: "/app/:path*",
+};
+```
+
+More detail on protection patterns and sensitive HTML is in [User fundamentals](/guides/getting-started/user-fundamentals).
+
+