Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.hexclave.com/llms.txt

Use this file to discover all available pages before exploring further.

You’ve set up Stack Auth. Now let’s understand the most important object in your application: the User. The user object represents whoever is currently interacting with your app — their identity, profile, and metadata. Almost everything you build will revolve around it: retrieving the current user, protecting pages from unauthorized access, updating profile information, signing out, and more.

Getting the current user

On both client and server, you can use the getUser() function to get the current user (or null if not signed in). In React apps, there is also a useUser() hook which automatically updates when the value changes.
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser();
if (user) {
  console.log("Signed in: " + (user.displayName ?? user.primaryEmail ?? "<Unnamed>"));
} else {
  console.log("Not signed in");
}

Protecting a page & requiring a signed-in user

Sometimes, you want to retrieve the user only if they’re signed in, and redirect to the sign-in page otherwise. In this case, simply pass { or: "redirect" }, and the function will never return null. You can also use { or: "throw" } to throw an error instead — useful in API routes and server actions where a redirect doesn’t make sense. In both cases, the return type is non-nullable, so you don’t need to handle null.
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser({ or: "redirect" });
// user is guaranteed to be non-null here
console.log("Signed in: " + (user.displayName ?? user.primaryEmail ?? "<Unnamed>"));

User data

What’s on a user object?

Before diving into updates, here’s an overview of the most important fields available on every user: For the full list of fields and methods, see the User SDK reference.

Updating a user

You can update attributes on a user object with the user.update() function.
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser();
await user.update({ displayName: "New Name" });

Custom metadata

Beyond built-in fields like displayName and primaryEmail, you’ll often need to store your own data on a user. Stack Auth provides three metadata fields for this:
  • clientMetadata — Readable and writable from both the client and the server. Use this for non-sensitive user preferences like theme, locale, or UI state.
  • serverMetadata — Readable and writable only from the server. Use this for sensitive or internal data like internal flags, or anything users shouldn’t be able to see or modify.
  • clientReadOnlyMetadata — Readable from the client, writable only from the server. Use this for data the client needs to display but shouldn’t be able to change, like subscription plans or role labels.
For example, storing a user’s theme preference in clientMetadata:
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser();
await user.update({
  clientMetadata: {
    theme: "dark",
  },
});
And storing sensitive data in serverMetadata (server-side only):
my-app.ts
import { stackServerApp } from "../src/stack/server";

const user = await stackServerApp.getUser();
await user.update({
  serverMetadata: {
    internalFlag: true,
  },
});
For more details, see the User Metadata documentation.

Signing out

You can sign out the user by calling user.signOut(). They will be redirected to the URL configured as afterSignOut in the Stack App.
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser();
await user.signOut();

Example: Custom profile page

Stack automatically creates a user profile on sign-up. Let’s build a page that displays this information. In app/profile/page.tsx:
my-app.tsx
"use client";
import { useUser, useStackApp, UserButton } from "../src/stack/client";

export default function PageClient() {
  const user = useUser();
  const app = useStackApp();
  return (
    <div>
      {user ? (
        <div>
          <UserButton />
          <p>Welcome, {user.displayName ?? "unnamed user"}</p>
          <p>Your e-mail: {user.primaryEmail}</p>
          <button onClick={() => user.signOut()}>Sign Out</button>
        </div>
      ) : (
        <div>
          <p>You are not logged in</p>
          <button onClick={() => app.redirectToSignIn()}>Sign in</button>
          <button onClick={() => app.redirectToSignUp()}>Sign up</button>
        </div>
      )}
    </div>
  );
}
After saving your code, you can see the profile page on http://localhost:3000/profile. For more examples on how to use the User object, check the the SDK documentation.

Anonymous users

Stack Auth supports anonymous users - users who can interact with your app without signing up. This is useful for features like guest checkouts, try-before-you-sign-up flows, or collecting analytics before a user creates an account. If you have the analytics app enabled, anonymous users will automatically be created and visible in the Users table. In most ways, anonymous users are just like any other, however, there are some key differences:
  • Unless opted in, anonymous users cannot access any backend functions that require a signed-in user.
  • By default, anonymous users are not returned by getUser(), useUser().
  • Anonymous users have a different set of JWT keys, which means they cannot access protected routes or API endpoints.
  • Anonymous users are always restricted.
To get an anonymous user, pass { or: "anonymous" } to useUser() or getUser(). This will create an anonymous user if the user isn’t signed in.
my-app.ts
import { stackClientApp } from "../src/stack/client";

const user = await stackClientApp.getUser({ or: "anonymous" });
// user is guaranteed to be non-null here
console.log("Signed in: " + (user.displayName ?? user.primaryEmail ?? "<Unnamed>"));
Anonymous users have an isAnonymous property set to true.