diff --git a/.claude/CLAUDE-KNOWLEDGE.md b/.claude/CLAUDE-KNOWLEDGE.md index 73f0d7262..7580fcaf5 100644 --- a/.claude/CLAUDE-KNOWLEDGE.md +++ b/.claude/CLAUDE-KNOWLEDGE.md @@ -535,3 +535,6 @@ A: The workflow needs a full checkout using the fine-grained `NPM_PUBLISH_VERSIO ## Q: How should the Mintlify docs homepage reuse the generated setup prompt? A: Import `generatedSetupPromptText` from `docs-mintlify/snippets/home-prompt-island.jsx` in `docs-mintlify/index.mdx`, render it directly in a `
{generatedSetupPromptText}
` block, and keep the home copy button wired to that imported value. Clipboard failures can happen when the browser document is not focused, so the button should surface the actual error text instead of only saying "Copy failed". + +## Q: Where should Mintlify docs for restricted users live? +A: Put restricted-user docs at `docs-mintlify/guides/apps/authentication/restricted-users.mdx` and register the page in the Authentication group in `docs-mintlify/docs.json`. The page should cover `includeRestricted: true`, `user.isRestricted`, `user.restrictedReason`, anonymous users being restricted by definition, and JWKS `include_restricted=true` for services that intentionally accept restricted-user tokens. diff --git a/.vscode/settings.json b/.vscode/settings.json index 72e3892e8..f10c333cb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -121,9 +121,11 @@ "xact", "zustand" ], - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit", - "source.organizeImports": "explicit" + "[typescript]": { + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "explicit" + }, }, "terminal.integrated.wordSeparators": " (){}',\"`─‘’“”|", "editor.formatOnSave": false, diff --git a/docs-mintlify/code-language-labels.js b/docs-mintlify/code-language-labels.js new file mode 100644 index 000000000..49cd67470 --- /dev/null +++ b/docs-mintlify/code-language-labels.js @@ -0,0 +1,59 @@ +(function () { + const REACT_ICON_URL = "https://d3gk2c5xim1je2.cloudfront.net/devicon/react.svg"; + const LANGUAGE_BUTTON_SELECTOR = "button[aria-haspopup='menu']"; + const LANGUAGE_ITEM_SELECTOR = "[role='menuitem']"; + + function getVisibleLabelElement(root) { + const labelCandidates = Array.from(root.querySelectorAll("p, span, div")); + return labelCandidates.find((element) => element.children.length === 0 && element.textContent?.trim().toLowerCase() === "tsx") ?? null; + } + + function applyReactIcon(root) { + const icon = root.querySelector("svg"); + if (icon == null) { + return; + } + + icon.style.WebkitMaskImage = `url(${REACT_ICON_URL})`; + icon.style.WebkitMaskRepeat = "no-repeat"; + icon.style.WebkitMaskPosition = "center"; + icon.style.maskImage = `url(${REACT_ICON_URL})`; + icon.style.maskRepeat = "no-repeat"; + icon.style.maskPosition = "center"; + icon.style.maskSize = "100%"; + icon.style.backgroundColor = "currentColor"; + } + + function relabelTsxControl(root) { + if (root.dataset.stackReactLabelApplied === "true") { + return; + } + + const labelElement = getVisibleLabelElement(root); + if (labelElement == null) { + return; + } + + labelElement.textContent = "React"; + applyReactIcon(root); + root.setAttribute("aria-label", root.getAttribute("aria-label")?.replace(/\btsx\b/i, "React") ?? "React"); + root.dataset.stackReactLabelApplied = "true"; + } + + function relabelTsxControls() { + for (const element of document.querySelectorAll(`${LANGUAGE_BUTTON_SELECTOR}, ${LANGUAGE_ITEM_SELECTOR}`)) { + relabelTsxControl(element); + } + } + + function installWhenReady() { + relabelTsxControls(); + window.setTimeout(relabelTsxControls, 250); + } + + if (typeof window !== "undefined" && typeof document !== "undefined") { + window.requestAnimationFrame(installWhenReady); + const observer = new MutationObserver(() => relabelTsxControls()); + observer.observe(document.documentElement, { childList: true, subtree: true }); + } +})(); diff --git a/docs-mintlify/docs.json b/docs-mintlify/docs.json index 7fb096f4c..7410dcd03 100644 --- a/docs-mintlify/docs.json +++ b/docs-mintlify/docs.json @@ -46,7 +46,6 @@ "tab": "Documentation", "pages": [ "index", - "guides/faq", { "group": "Getting Started", "pages": [ @@ -75,6 +74,7 @@ "pages": [ "guides/apps/authentication/overview", "guides/apps/authentication/user-onboarding", + "guides/apps/authentication/restricted-users", "guides/apps/authentication/connected-accounts", "guides/apps/authentication/jwts", "guides/apps/authentication/sign-up-rules", @@ -228,7 +228,7 @@ } }, "settings": { - "customScripts": ["/apps-sidebar-filter.js"] + "customScripts": ["/apps-sidebar-filter.js", "/code-language-labels.js"] }, "redirects": [] } diff --git a/docs-mintlify/guides/apps/authentication/restricted-users.mdx b/docs-mintlify/guides/apps/authentication/restricted-users.mdx new file mode 100644 index 000000000..0ccc11ae4 --- /dev/null +++ b/docs-mintlify/guides/apps/authentication/restricted-users.mdx @@ -0,0 +1,114 @@ +--- +title: "Restricted Users" +description: "Understand and handle users with limited access" +sidebarTitle: "Restricted Users" +--- + +Restricted users are signed-in users whose account exists, but has not been granted normal application access yet. Stack marks these users with `user.isRestricted === true` and provides a `user.restrictedReason` explaining why. + +By default, Stack Auth treats restricted users like unauthenticated users in most SDK calls. This prevents accounts that still need verification, review, or conversion from accidentally getting access to protected product flows. + +## When users are restricted + +Users can be restricted for a few reasons: + +- **Email not verified**: the project requires email verification before full access. +- **Anonymous user**: anonymous users can interact with the app, but are always restricted until converted. +- **Restricted by administrator**: the user was restricted manually or by a [sign-up rule](/guides/apps/authentication/sign-up-rules). + +You can inspect the reason from the SDK: + +```ts my-app.ts +import { stackServerApp } from "../src/stack/server"; + +const user = await stackServerApp.getUser({ includeRestricted: true }); + +if (user?.isRestricted) { + console.log(user.restrictedReason?.type); +} +``` + +The current `restrictedReason.type` values are: + +| Type | Meaning | +| --- | --- | +| `email_not_verified` | The user still needs to verify their email address. | +| `anonymous` | The user is an anonymous user. | +| `restricted_by_administrator` | The user was restricted manually or by a sign-up rule. | + +## Loading restricted users + +Most calls exclude restricted users unless you explicitly opt in. Use `includeRestricted: true` when you are building onboarding, email verification, account review, or anonymous-user conversion flows. + + +```ts my-app.ts +import { stackServerApp } from "../src/stack/server"; + +const user = await stackServerApp.getUser({ includeRestricted: true }); + +if (user?.isRestricted) { + console.log("Needs onboarding:", user.restrictedReason?.type); +} +``` + +```tsx my-react-component.tsx +"use client"; +import { stackClientApp } from "../src/stack/client"; + +export default function OnboardingGate() { + const user = stackClientApp.useUser({ includeRestricted: true }); + + if (!user) { + return Sign in; + } + + if (user.isRestricted) { + return ; + } + + return
Welcome back, {user.displayName ?? user.primaryEmail}
; +} +``` +
+ + + Anonymous users are restricted by definition. Passing `{ or: "anonymous" }` automatically includes restricted users, and cannot be combined with `{ includeRestricted: false }`. + + +## Handling restricted users + +Treat restricted users as a separate state from both "signed out" and "fully signed in". A good default is to show a page that tells the user what they need to do next. + +```tsx restricted-user-message.tsx +function RestrictedUserMessage({ reason }: { reason: string | undefined }) { + if (reason === "email_not_verified") { + return
Please verify your email address to continue.
; + } + + if (reason === "anonymous") { + return Create an account to save your progress.; + } + + return
Your account is waiting for review.
; +} +``` + +For API routes or backend actions, keep using the default behavior unless the endpoint is specifically meant to serve restricted users. This helps prevent partially onboarded accounts from reaching product APIs. + +## Restricted users in JWTs + +Restricted users receive tokens with `is_restricted` and `restricted_reason` claims. If your backend verifies Stack Auth JWTs directly, make sure you reject restricted users unless the endpoint intentionally supports them. + +When fetching Stack Auth's JWKS, restricted-user signing keys are excluded by default. Include them only for services that intentionally accept restricted users: + +```txt jwks-url.txt +/.well-known/jwks.json?include_restricted=true +``` + +If you also accept anonymous users, use `include_anonymous=true`; anonymous keys imply restricted-user keys. + +## Admin and sign-up review + +Sign-up rules can restrict a user instead of rejecting the sign-up outright. This is useful when you want the account to exist, but need manual review before granting access. + +For more details on creating rules that restrict users, see [Sign-up Rules](/guides/apps/authentication/sign-up-rules). diff --git a/docs-mintlify/guides/getting-started/user-fundamentals.mdx b/docs-mintlify/guides/getting-started/user-fundamentals.mdx index 77ce2a1f5..035b663b3 100644 --- a/docs-mintlify/guides/getting-started/user-fundamentals.mdx +++ b/docs-mintlify/guides/getting-started/user-fundamentals.mdx @@ -6,52 +6,45 @@ sidebarTitle: User Fundamentals import { UserFieldsTable } from "/snippets/user-fields-table.jsx"; - 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 -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. +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. - - - Use the `useUser()` hook: + +```ts my-app.ts +import { stackClientApp } from "../src/stack/client"; - ```tsx title="my-client-component.tsx" - "use client"; - import { useUser } from "@stackframe/stack" +const user = await stackClientApp.getUser(); +if (user) { + console.log("Signed in: " + (user.displayName ?? user.primaryEmail ?? "")); +} else { + console.log("Not signed in"); +} +``` - export function MyClientComponent() { - const user = useUser(); - return
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
; - } - ``` +```tsx my-react-component.tsx +"use client"; +import { stackClientApp } from "../src/stack/client"; - 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). -
- - Since `useUser()` is a stateful hook, you can't use it in Server Components. Instead, import `stackServerApp` from `stack/server.ts` and call `getUser()`: +// Like most `getXyz()` or `listXyz()` functions, Stack Auth provides a `useUser()` hook equivalent to `getUser()`. +// It behaves the same, but returns the user directly instead of a Promise, and updates when the user object changes. +// Note: In Server Components, you can still use `await stackServerApp.getUser()`. +export default async function MyReactComponent() { + const user = stackClientApp.useUser(); + if (user) { + return
Hello, {user.displayName ?? user.primaryEmail ?? "anon"}
; + } else { + return
You are not logged in
; + } +} +``` + - ```tsx title="my-server-component.tsx" - import { stackServerApp } from "@/stack/server"; - - export default async function MyServerComponent() { - const user = await stackServerApp.getUser(); - return
{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}
; - } - ``` - - 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. -
-
- - - 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. - - -### Requiring a signed-in user +### 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`. @@ -59,76 +52,26 @@ You can also use `{ or: "throw" }` to throw an error instead — useful in API r In both cases, the return type is non-nullable, so you don't need to handle `null`. -```tsx -const user = useUser({ or: "redirect" }); + +```ts my-app.ts +import { stackClientApp } from "../src/stack/client"; + +const user = await stackClientApp.getUser({ or: "redirect" }); // user is guaranteed to be non-null here -return
{`Hello, ${user.displayName ?? "anon"}`}
; +console.log("Signed in: " + (user.displayName ?? user.primaryEmail ?? "")); ``` -## Protecting a page +```tsx my-react-component.tsx +"use client"; +import { stackClientApp } from "../src/stack/client"; -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. - -On Client Components, the `useUser({ or: 'redirect' })` hook will redirect the user to the sign-in page if they are not logged in. Similarly, on Server Components, call `await getUser({ or: "redirect" })` to protect a page (or component). - -Middleware can be used whenever it is easy to tell whether a page should be protected given just the URL, for example, when you have a `/private` section only accessible to logged-in users. - - - - ```tsx title="my-protected-client-component.tsx" - "use client"; - import { useUser } from "@stackframe/stack"; - - export default function MyProtectedClientComponent() { - useUser({ or: 'redirect' }); - return

You can only see this if you are logged in

- } - ``` -
- - ```tsx title="my-protected-server-component.tsx" - import { stackServerApp } from "@/stack/server"; - - export default async function MyProtectedServerComponent() { - await stackServerApp.getUser({ or: 'redirect' }); - return

You can only see this if you are logged in

- } - ``` -
- - ```tsx title="middleware.tsx" - 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 = { - // You can add your own route protection logic here - // Make sure not to protect the root URL, as it would prevent users from accessing static Next.js files or Stack's /handler path - matcher: '/protected/:path*', - }; - ``` - -
- - - If you have sensitive information hidden in the page HTML itself, be aware of Next.js differences when using Server vs. Client Components. - - - **Client Components**: Client components are always sent to the browser, regardless of page protection. This is standard Next.js behavior. For more information, please refer to the [Next.js documentation](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment). - - - **Server Components**: If a component is protected, it is guaranteed that its bundled HTML will not be sent to the browser if the user is not logged in. However, this is not necessarily true for its children and the rest of the page, as Next.js may split components on the same page and send them to the client separately for performance. - - For example, if your page is ``, where `Parent` is protected and `Child` is not, Next.js may still send `` to the browser even if the user is not logged in. (Normal browsers will never display it, but attackers may be able to retrieve it.) Notably, this also applies to unprotected pages inside protected layouts. - - To remediate this, every component/page that contains sensitive information should protect itself, instead of relying on an outer layout. This is good practice anyways; it prevents you from accidentally exposing the data. - - - **Middleware**: Prior to Next.js v15.2.3, Next.js allowed attackers to see unprotected components if you only protect on a middleware level. Since v15.2.3, this is no longer possible, and you don't have to worry about leaking sensitive information when using middleware to protect a route. - - No matter which method you use, attackers will never be able to, say, impersonate a user. - +export default function MyReactComponent() { + const user = stackClientApp.useUser({ or: "redirect" }); + // user is guaranteed to be non-null here + return
{`Hello, ${user.displayName ?? user.primaryEmail ?? "anon"}`}
; +} +``` +
## User data @@ -144,7 +87,15 @@ For the full list of fields and methods, see the [User SDK reference](/sdk/types You can update attributes on a user object with the `user.update()` function. -```tsx title="my-client-component.tsx" + +```ts my-app.ts +import { stackClientApp } from "../src/stack/client"; + +const user = await stackClientApp.getUser(); +await user.update({ displayName: "New Name" }); +``` + +```tsx my-client-component.tsx 'use client'; import { useUser } from "@stackframe/stack"; @@ -155,18 +106,31 @@ export default function MyClientComponent() { ; } ``` + ### 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. +- **`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`: -```tsx title="theme-toggle.tsx" + +```ts my-app.ts +import { stackClientApp } from "../src/stack/client"; + +const user = await stackClientApp.getUser(); +await user.update({ + clientMetadata: { + theme: "dark", + }, +}); +``` + +```tsx my-client-component.tsx 'use client'; import { useUser } from "@stackframe/stack"; @@ -188,112 +152,108 @@ export default function ThemeToggle() { ); } ``` + And storing sensitive data in `serverMetadata` (server-side only): -```tsx title="server-example.ts" -const user = await stackServerApp.getUser({ or: "throw" }); + +```ts my-app.ts +import { stackServerApp } from "../src/stack/server"; + +const user = await stackServerApp.getUser(); await user.update({ serverMetadata: { - ...user.serverMetadata, - stripeCustomerId: "cus_abc123", + internalFlag: true, }, }); ``` + -For more details, see the [Custom User Data](/guides/going-further/user-metadata) documentation. +For more details, see the [User Metadata](/guides/going-further/user-metadata) documentation. ## Signing out -You can sign out the user by redirecting them to `/handler/sign-out` or simply by calling `user.signOut()`. They will be redirected to the URL [configured as `afterSignOut` in the `StackServerApp`](/sdk/objects/stack-app). +You can sign out the user by calling `user.signOut()`. They will be redirected to the URL [configured as `afterSignOut` in the Stack App](/sdk/objects/stack-app). - - - ```tsx title="sign-out-button.tsx" - "use client"; - import { useUser } from "@stackframe/stack"; + +```ts my-app.ts +import { stackClientApp } from "../src/stack/client"; - export default function SignOutButton() { - const user = useUser(); - return user ? : "Not signed in"; - } - ``` - - - ```tsx title="sign-out-link.tsx" - import { stackServerApp } from "@/stack/server"; +const user = await stackClientApp.getUser(); +await user.signOut(); +``` - export default async function SignOutLink() { - // stackServerApp.urls.signOut is equal to /handler/sign-out - return Sign Out; - } - ``` - - +```tsx my-client-component.tsx +'use client'; +import { useUser } from "@stackframe/stack"; + +export default function MyClientComponent() { + const user = useUser(); + return ; +} +``` + ## 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`: - - - ```tsx title="app/profile/page.tsx" - 'use client'; - import { useUser, useStackApp, UserButton } from "@stackframe/stack"; + +```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 ( +export default function PageClient() { + const user = useUser(); + const app = useStackApp(); + return ( +
+ {user ? (
- {user ? ( -
- -

Welcome, {user.displayName ?? "unnamed user"}

-

Your e-mail: {user.primaryEmail}

- -
- ) : ( -
-

You are not logged in

- - -
- )} + +

Welcome, {user.displayName ?? "unnamed user"}

+

Your e-mail: {user.primaryEmail}

+
- ); - } - ``` - - - ```tsx title="app/profile/page.tsx" - import { stackServerApp } from "@/stack/server"; - import { UserButton } from "@stackframe/stack"; + ) : ( +
+

You are not logged in

+ + +
+ )} +
+ ); +} +``` +```tsx my-client-component.tsx +"use client"; +import { stackClientApp, UserButton } from "../src/stack/client"; - export default async function Page() { - const user = await stackServerApp.getUser(); - return ( +export default function MyClientComponent() { + const user = stackClientApp.useUser(); + const app = stackClientApp.useStackApp(); + return ( +
+ {user ? (
- {user ? ( -
- -

Welcome, {user.displayName ?? "unnamed user"}

-

Your e-mail: {user.primaryEmail}

-

Sign Out

-
- ) : ( -
-

You are not logged in

-

Sign in

-

Sign up

-
- )} + +

Welcome, {user.displayName ?? "unnamed user"}

+

Your e-mail: {user.primaryEmail}

+

- ); - } - ``` - - + ) : ( +
+

You are not logged in

+

+

+
+ )} +
+ ); +} +``` +
After saving your code, you can see the profile page on [http://localhost:3000/profile](http://localhost:3000/profile). @@ -301,13 +261,29 @@ For more examples on how to use the `User` object, check the [the SDK documentat ## 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. +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. -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. +In most ways, anonymous users are just like any other, however, there are some key differences: -```tsx title="my-client-component.tsx" +- 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](/guides/apps/authentication/jwts), which means they cannot access protected routes or API endpoints. +- Anonymous users are always [restricted](/guides/apps/authentication/restricted-users). + +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. + + +```ts 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 ?? "")); +``` + +```tsx my-client-component.tsx "use client"; -import { useUser } from "@stackframe/stack"; +import { stackClientApp } from "../src/stack/client"; export default function MyComponent() { const user = useUser({ or: "anonymous" }); @@ -315,21 +291,6 @@ export default function MyComponent() { return
Your user ID: {user.id}
; } ``` +
-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
You're browsing as a guest. Create an account to save your progress.
; -} -return
Welcome back, {user.displayName}!
; -``` - - - 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 }`. - - -## Next steps - -In the next guide, we will show you how to put [your application into production](/guides/apps/launch-checklist/overview). +Anonymous users have an `isAnonymous` property set to `true`. diff --git a/docs-mintlify/index.mdx b/docs-mintlify/index.mdx index 419f671c2..50b41e18e 100644 --- a/docs-mintlify/index.mdx +++ b/docs-mintlify/index.mdx @@ -4,7 +4,6 @@ description: "Stack Auth documentation for setup, components, SDK usage, and RES sidebarTitle: "Overview" --- -import { generatedSetupPromptText } from "./snippets/home-prompt-island.jsx"; export const SectionLink = ({ href, children }) => ( {children} @@ -108,6 +107,8 @@ export const copyGeneratedSetupPrompt = async (event) => { Go to dashboard @@ -199,7 +200,7 @@ export const copyGeneratedSetupPrompt = async (event) => { - + Manage projects, keys, providers, and authentication settings.