mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Update mintlify docs in various spots throughout. (#1305)
<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md -->
This commit is contained in:
parent
13fccd32b6
commit
3fa081f1e3
@ -57,32 +57,43 @@
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"docs/getting-started/setup",
|
||||
"docs/getting-started/components",
|
||||
"docs/getting-started/users",
|
||||
"docs/getting-started/components",
|
||||
"docs/getting-started/production",
|
||||
"docs/getting-started/vite-example"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Apps",
|
||||
"pages": [
|
||||
"docs/apps/api-keys",
|
||||
"docs/apps/emails",
|
||||
"docs/apps/oauth",
|
||||
"docs/apps/orgs-and-teams",
|
||||
"docs/apps/permissions",
|
||||
"docs/apps/webhooks",
|
||||
"docs/apps/payments",
|
||||
"docs/apps/analytics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Concepts",
|
||||
"group": "Going Further",
|
||||
"pages": [
|
||||
"docs/going-further/working-with-ai",
|
||||
"docs/concepts/stack-app",
|
||||
"docs/concepts/backend-integration",
|
||||
"docs/going-further/local-development",
|
||||
{
|
||||
"group": "Component Customization",
|
||||
"pages": [
|
||||
"docs/customization/custom-pages",
|
||||
"docs/customization/custom-styles",
|
||||
"docs/customization/dark-mode",
|
||||
"docs/customization/internationalization",
|
||||
{
|
||||
"group": "Page Examples",
|
||||
"pages": [
|
||||
"docs/customization/page-examples",
|
||||
"docs/customization/page-examples/forgot-password",
|
||||
"docs/customization/page-examples/password-reset",
|
||||
"docs/customization/page-examples/sign-in",
|
||||
"docs/customization/page-examples/sign-up"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"docs/concepts/custom-user-data",
|
||||
"docs/concepts/sign-up-rules",
|
||||
"docs/concepts/jwt",
|
||||
"docs/concepts/user-onboarding",
|
||||
"docs/concepts/team-selection",
|
||||
{
|
||||
"group": "Auth Providers",
|
||||
"pages": [
|
||||
@ -102,39 +113,45 @@
|
||||
"docs/concepts/auth-providers/two-factor-auth",
|
||||
"docs/concepts/auth-providers/x-twitter"
|
||||
]
|
||||
},
|
||||
"docs/concepts/stack-app",
|
||||
"docs/concepts/team-selection",
|
||||
"docs/concepts/user-onboarding"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Customization",
|
||||
"group": "Apps",
|
||||
"pages": [
|
||||
"docs/customization/custom-pages",
|
||||
"docs/customization/custom-styles",
|
||||
"docs/customization/dark-mode",
|
||||
"docs/customization/internationalization",
|
||||
{
|
||||
"group": "Page Examples",
|
||||
"group": "Authentication",
|
||||
"icon": "lock",
|
||||
"pages": [
|
||||
"docs/customization/page-examples",
|
||||
"docs/customization/page-examples/forgot-password",
|
||||
"docs/customization/page-examples/password-reset",
|
||||
"docs/customization/page-examples/sign-in",
|
||||
"docs/customization/page-examples/sign-up"
|
||||
"docs/apps/auth-providers",
|
||||
"docs/apps/oauth"
|
||||
]
|
||||
}
|
||||
},
|
||||
"docs/apps/emails",
|
||||
"docs/apps/payments",
|
||||
"docs/apps/analytics",
|
||||
"docs/apps/api-keys",
|
||||
"docs/apps/data-vault",
|
||||
"docs/apps/launch-checklist",
|
||||
"docs/apps/permissions",
|
||||
"docs/apps/orgs-and-teams",
|
||||
"docs/apps/webhooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Integrations",
|
||||
"pages": [
|
||||
"docs/others/supabase",
|
||||
"docs/others/convex",
|
||||
"docs/others/mcp-setup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Other",
|
||||
"pages": [
|
||||
"docs/others/cli-authentication",
|
||||
"docs/others/self-host",
|
||||
"docs/others/supabase",
|
||||
"docs/others/convex",
|
||||
"docs/others/mcp-setup"
|
||||
"docs/others/cli-authentication",
|
||||
"docs/going-further/showcase"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
---
|
||||
title: Auth Providers
|
||||
description: Configure authentication providers for your application
|
||||
icon: shield
|
||||
---
|
||||
|
||||
Stack Auth supports a variety of authentication providers to give your users flexible sign-in options. You can configure these providers through the Stack Auth dashboard.
|
||||
|
||||
7
docs-mintlify/docs/apps/data-vault.mdx
Normal file
7
docs-mintlify/docs/apps/data-vault.mdx
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: "Data Vault"
|
||||
description: "Securely store and manage sensitive data for your application"
|
||||
icon: "vault"
|
||||
---
|
||||
|
||||
This page is under construction. Check back soon for documentation on using the Data Vault.
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "Emails"
|
||||
description: "Send custom emails to your users with Stack Auth's email system."
|
||||
icon: "mail"
|
||||
icon: "envelope"
|
||||
---
|
||||
|
||||
Stack Auth provides emails that allows you to send custom emails to your users. The system supports both custom HTML emails and template-based emails with theming.
|
||||
|
||||
7
docs-mintlify/docs/apps/launch-checklist.mdx
Normal file
7
docs-mintlify/docs/apps/launch-checklist.mdx
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: "Launch Checklist"
|
||||
description: "Everything you need to verify before going live with Stack Auth"
|
||||
icon: "clipboard-check"
|
||||
---
|
||||
|
||||
This page is under construction. Check back soon for the launch checklist.
|
||||
@ -1,7 +1,6 @@
|
||||
---
|
||||
title: "OAuth"
|
||||
description: "Managing third-party OAuth access tokens"
|
||||
icon: "globe"
|
||||
---
|
||||
|
||||
Stack has good support for working with OAuth and OIDC providers, such as Google, Facebook, Microsoft, and others.
|
||||
|
||||
@ -1,54 +1,72 @@
|
||||
---
|
||||
title: Users
|
||||
title: User Fundamentals
|
||||
description: Access and manage user information within custom components
|
||||
sidebarTitle: Users
|
||||
sidebarTitle: User Fundamentals
|
||||
icon: "users"
|
||||
---
|
||||
|
||||
import { UserFieldsTable } from "/snippets/user-fields-table.jsx";
|
||||
|
||||
# Users
|
||||
|
||||
You will inevitably build custom components that access the user in one way or another. In this section, we will take a closer look at the functions and hooks that let you do this.
|
||||
You've set up Stack Auth. Now let's understand the most important object in your application: the **User**.
|
||||
|
||||
## Client Component basics
|
||||
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.
|
||||
|
||||
The `useUser()` hook returns the current user in a Client Component. By default, it will return `null` if the user is not signed in.
|
||||
## Getting the current user
|
||||
|
||||
```tsx title="my-client-component.tsx"
|
||||
"use client";
|
||||
import { useUser } from "@stackframe/stack"
|
||||
The way you retrieve the current user depends on whether you're in a Client Component or a Server Component. Both return `null` if the user is not signed in.
|
||||
|
||||
export function MyClientComponent() {
|
||||
const user = useUser();
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
<Tabs>
|
||||
<Tab title="Client Component">
|
||||
Use the `useUser()` hook:
|
||||
|
||||
The `useUser()` hook is simply a shorthand for `useStackApp().useUser()`. `useStackApp()` also contains other useful hooks and methods for clients, which will be described later.
|
||||
```tsx title="my-client-component.tsx"
|
||||
"use client";
|
||||
import { useUser } from "@stackframe/stack"
|
||||
|
||||
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`.
|
||||
export function MyClientComponent() {
|
||||
const user = useUser();
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
const user = useUser({ or: "redirect" });
|
||||
return <div>{`Hello, ${user.displayName ?? "anon"}`}</div>;
|
||||
```
|
||||
The `useUser()` hook is simply a shorthand for `useStackApp().useUser()`. `useStackApp()` also contains other useful hooks and methods for clients, which will be described later. Since it's a React hook, your component will automatically re-render when the user changes (e.g. on sign-out).
|
||||
</Tab>
|
||||
<Tab title="Server Component">
|
||||
Since `useUser()` is a stateful hook, you can't use it in Server Components. Instead, import `stackServerApp` from `stack/server.ts` and call `getUser()`:
|
||||
|
||||
## Server Component basics
|
||||
```tsx title="my-server-component.tsx"
|
||||
import { stackServerApp } from "@/stack/server";
|
||||
|
||||
Since `useUser()` is a stateful hook, you can't use it on server components. Instead, you can import `stackServerApp` from `stack/server.ts` and call `getUser()`:
|
||||
export default async function MyServerComponent() {
|
||||
const user = await stackServerApp.getUser();
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx title="my-server-component.tsx"
|
||||
import { stackServerApp } from "@/stack/server";
|
||||
|
||||
export default async function MyServerComponent() {
|
||||
const user = await stackServerApp.getUser(); // or: stackServerApp.getUser({ or: "redirect" })
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
Unlike `useUser()`, `getUser()` fetches the user once at request time and does not re-render on changes. You can also call `useStackApp().getUser()` on the client side to get the user in a non-component context.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info>
|
||||
Since `useUser()` is a hook, it will re-render the component on user changes (eg. signout), while `getUser()` will only fetch the user once (on page load). You can also call `useStackApp().getUser()` on the client side to get the user in a non-component context.
|
||||
</Info>
|
||||
|
||||
### 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`.
|
||||
|
||||
```tsx
|
||||
const user = useUser({ or: "redirect" });
|
||||
// user is guaranteed to be non-null here
|
||||
return <div>{`Hello, ${user.displayName ?? "anon"}`}</div>;
|
||||
```
|
||||
|
||||
## Protecting a page
|
||||
|
||||
There are three ways to protect a page: in Client Components with `useUser({ or: "redirect" })`, in Server Components with `await getUser({ or: "redirect" })`, or with middleware.
|
||||
@ -116,6 +134,16 @@ Middleware can be used whenever it is easy to tell whether a page should be prot
|
||||
|
||||
## 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:
|
||||
|
||||
<UserFieldsTable />
|
||||
|
||||
For the full list of fields and methods, see the [User SDK reference](../sdk/types/user).
|
||||
|
||||
### Updating a user
|
||||
|
||||
You can update attributes on a user object with the `user.update()` function.
|
||||
|
||||
```tsx title="my-client-component.tsx"
|
||||
@ -130,7 +158,52 @@ export default function MyClientComponent() {
|
||||
}
|
||||
```
|
||||
|
||||
You can also store custom user data in the `clientMetadata`, `serverMetadata`, or `clientReadOnlyMetadata` fields. More information [here](../concepts/custom-user-data).
|
||||
### 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 Stripe customer IDs, 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`:
|
||||
|
||||
```tsx title="theme-toggle.tsx"
|
||||
'use client';
|
||||
import { useUser } from "@stackframe/stack";
|
||||
|
||||
export default function ThemeToggle() {
|
||||
const user = useUser({ or: "redirect" });
|
||||
const currentTheme = user.clientMetadata?.theme ?? "light";
|
||||
|
||||
return (
|
||||
<button onClick={async () => {
|
||||
await user.update({
|
||||
clientMetadata: {
|
||||
...user.clientMetadata,
|
||||
theme: currentTheme === "light" ? "dark" : "light",
|
||||
},
|
||||
});
|
||||
}}>
|
||||
Switch to {currentTheme === "light" ? "dark" : "light"} mode
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
And storing sensitive data in `serverMetadata` (server-side only):
|
||||
|
||||
```tsx title="server-example.ts"
|
||||
const user = await stackServerApp.getUser({ or: "throw" });
|
||||
await user.update({
|
||||
serverMetadata: {
|
||||
...user.serverMetadata,
|
||||
stripeCustomerId: "cus_abc123",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
For more details, see the [Custom User Data](../concepts/custom-user-data) documentation.
|
||||
|
||||
## Signing out
|
||||
|
||||
@ -228,6 +301,37 @@ After saving your code, you can see the profile page on [http://localhost:3000/p
|
||||
|
||||
For more examples on how to use the `User` object, check the [the SDK documentation](../sdk/types/user).
|
||||
|
||||
## 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.
|
||||
|
||||
To get an anonymous user, pass `{ or: "anonymous" }` to `useUser()` or `getUser()`. If the current visitor isn't signed in, Stack will automatically create an anonymous account for them behind the scenes.
|
||||
|
||||
```tsx title="my-client-component.tsx"
|
||||
"use client";
|
||||
import { useUser } from "@stackframe/stack";
|
||||
|
||||
export default function MyComponent() {
|
||||
const user = useUser({ or: "anonymous" });
|
||||
// user is always non-null — either a real user or an anonymous one
|
||||
return <div>Your user ID: {user.id}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
Anonymous users have an `isAnonymous` property set to `true` and are also considered restricted (`isRestricted` is `true`). You can check this to show different UI for anonymous vs. signed-in users:
|
||||
|
||||
```tsx
|
||||
const user = useUser({ or: "anonymous" });
|
||||
if (user.isAnonymous) {
|
||||
return <div>You're browsing as a guest. <a href="/handler/sign-up">Create an account</a> to save your progress.</div>;
|
||||
}
|
||||
return <div>Welcome back, {user.displayName}!</div>;
|
||||
```
|
||||
|
||||
<Info>
|
||||
When using `{ or: "anonymous" }`, the `includeRestricted` option is automatically set to `true`, since all anonymous users are restricted by definition. You cannot use `{ or: "anonymous" }` with `{ includeRestricted: false }`.
|
||||
</Info>
|
||||
|
||||
## Next steps
|
||||
|
||||
In the next guide, we will show you how to put [your application into production](./production).
|
||||
|
||||
6
docs-mintlify/docs/going-further/local-development.mdx
Normal file
6
docs-mintlify/docs/going-further/local-development.mdx
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Local Development"
|
||||
description: "Set up and run Stack Auth locally for development and testing"
|
||||
---
|
||||
|
||||
This page is under construction. Check back soon for instructions on setting up Stack Auth for local development.
|
||||
6
docs-mintlify/docs/going-further/showcase.mdx
Normal file
6
docs-mintlify/docs/going-further/showcase.mdx
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Showcase"
|
||||
description: "See what others have built with Stack Auth"
|
||||
---
|
||||
|
||||
This page is under construction. Check back soon for a showcase of projects and applications built with Stack Auth.
|
||||
6
docs-mintlify/docs/going-further/working-with-ai.mdx
Normal file
6
docs-mintlify/docs/going-further/working-with-ai.mdx
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Working with AI"
|
||||
description: "Use AI-powered tools and integrations with Stack Auth to accelerate your development workflow"
|
||||
---
|
||||
|
||||
This page is under construction. Check back soon for guidance on integrating Stack Auth with AI-powered development tools.
|
||||
39
docs-mintlify/snippets/user-fields-table.jsx
Normal file
39
docs-mintlify/snippets/user-fields-table.jsx
Normal file
@ -0,0 +1,39 @@
|
||||
export const UserFieldsTable = () => {
|
||||
const fields = [
|
||||
{ name: "id", type: "string", description: "Unique identifier — always use this for lookups, not email" },
|
||||
{ name: "displayName", type: "string | null", description: "The user's display name" },
|
||||
{ name: "primaryEmail", type: "string | null", description: "The user's email address (not guaranteed unique)" },
|
||||
{ name: "primaryEmailVerified", type: "boolean", description: "Whether the email has been verified" },
|
||||
{ name: "profileImageUrl", type: "string | null", description: "URL to the user's profile image" },
|
||||
{ name: "signedUpAt", type: "Date", description: "When the user created their account" },
|
||||
{ name: "clientMetadata", type: "any", description: "Custom data, readable/writable from client and server" },
|
||||
{ name: "clientReadOnlyMetadata", type: "any", description: "Custom data, readable from client, writable only from server" },
|
||||
{ name: "serverMetadata", type: "any", description: "Custom data, server-only (only on server-side user objects)" },
|
||||
{ name: "hasPassword", type: "boolean", description: "Whether the user has a password set" },
|
||||
{ name: "isAnonymous", type: "boolean", description: "Whether this is an anonymous user" },
|
||||
{ name: "isRestricted", type: "boolean", description: "Hasn't completed onboarding requirements (e.g. email not verified)" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="not-prose my-6 overflow-hidden rounded-2xl border border-zinc-950/10 dark:border-white/10">
|
||||
<div className="border-b border-zinc-950/10 bg-zinc-950/[0.03] px-4 py-3 text-sm font-medium text-zinc-950/80 dark:border-white/10 dark:bg-white/[0.03] dark:text-white/80">
|
||||
User object fields
|
||||
</div>
|
||||
<div className="divide-y divide-zinc-950/[0.06] dark:divide-white/[0.06]">
|
||||
{fields.map((field) => (
|
||||
<div key={field.name} className="flex items-baseline gap-4 px-4 py-2.5">
|
||||
<code className="shrink-0 text-[13px] font-semibold text-zinc-950 dark:text-white">
|
||||
{field.name}
|
||||
</code>
|
||||
<code className="shrink-0 text-[12px] text-zinc-500 dark:text-zinc-400">
|
||||
{field.type}
|
||||
</code>
|
||||
<span className="text-[13px] leading-snug text-zinc-600 dark:text-zinc-400">
|
||||
{field.description}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user