mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Minor clarity updates
This commit is contained in:
parent
efe79f263e
commit
e1b188fede
@ -16,12 +16,11 @@ Here is an example of the sign-up page you get out of the box:
|
||||
|
||||
## Features
|
||||
|
||||
- Composable React components & hooks
|
||||
- OAuth (Google, Facebook, GitHub, etc.)
|
||||
- Email and password authentication (with email verification and password reset)
|
||||
- Easy to set up with proxied providers
|
||||
- User management & analytics
|
||||
- Pre-built React components & hooks
|
||||
- Support for static sites & single-page apps
|
||||
- User-associated metadata with client-/server-specific permissions
|
||||
- **100% open-source!**
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ To get started with Stack, you need to create a [Next.js](https://nextjs.org/doc
|
||||
|
||||
```bash
|
||||
npx create-next-app@latest --app stack-example
|
||||
cd stack-example
|
||||
```
|
||||
|
||||
Once that's done, you can install Stack with npm or yarn:
|
||||
@ -39,9 +40,9 @@ npm install @stackframe/stack
|
||||
});
|
||||
```
|
||||
|
||||
This will reads the environment variables automatically and create a server app that you can later use to access Stack from your Next.js server.
|
||||
This will read the environment variables automatically and create a server app that you can later use to access Stack from your Next.js server.
|
||||
|
||||
`StackServerApp` has many other options. Check out [StackServerApp documentation](/docs/api-documentation/app) if you want to learn more.
|
||||
Check out the [`StackServerApp` documentation](/docs/api-documentation/app) to learn more about its other options.
|
||||
|
||||
3. Create a new file in `app/handler/[...stack]/page.tsx` and paste the following code:
|
||||
|
||||
@ -57,14 +58,14 @@ npm install @stackframe/stack
|
||||
This will create pages for sign-in, sign-up, password reset, and others. Additionally, it will be used as a callback URL for OAuth. You can [replace them with your own pages](/docs/advanced-guides/customization/overview) later.
|
||||
|
||||
|
||||
4. In your `app/layout.tsx`, wrap your entire layout with a `StackProvider`. Afterwards, it should look like this:
|
||||
4. In your `app/layout.tsx`, wrap the entire body with a `StackProvider`. Afterwards, it should look like this:
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { StackProvider } from "@stackframe/stack";
|
||||
import { stackApp } from "@/lib/stack";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
@ -77,9 +78,6 @@ npm install @stackframe/stack
|
||||
}
|
||||
```
|
||||
|
||||
This lets you use the `useStackApp()` and `useUser()` hooks.
|
||||
|
||||
|
||||
5. By default, Stack uses [`Suspense`](https://react.dev/reference/react/Suspense) to handle loading states. To show a loading indicator while Stack is fetching user data, make sure there is a `loading.tsx` file in your `app` directory:
|
||||
|
||||
```tsx
|
||||
|
||||
@ -22,7 +22,7 @@ export function MyComponent() {
|
||||
const app = useStackApp();
|
||||
const user = app.useUser();
|
||||
|
||||
return <div>{user ? `Hello, ${user.displayName}` : 'You are not logged in'}</div>;
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
@ -39,7 +39,7 @@ import { stackApp } from "@/lib/stack";
|
||||
export default async function MyComponent() {
|
||||
const user = await stackApp.getUser();
|
||||
|
||||
return <div>{user ? `Hello, ${user.displayName}` : 'You are not logged in'}</div>;
|
||||
return <div>{user ? `Hello, ${user.displayName ?? "anon"}` : 'You are not logged in'}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
@ -58,98 +58,128 @@ Call `useUser` (or `getUser`) with the `{ or: 'redirect' }` option to protect th
|
||||
<TabItem value="client" label="Client Component" default>
|
||||
```tsx
|
||||
"use client";
|
||||
import { useStackApp } from "@stackframe/stack";
|
||||
import { useUser } from "@stackframe/stack";
|
||||
|
||||
export default function Protected() {
|
||||
useUser({ or: 'redirect' });
|
||||
return <h1>You can only see this if you are logged in</h1>
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="server" label="Server Component">
|
||||
<TabItem value="server" label="Server Component">
|
||||
```tsx
|
||||
import { useStackApp } from "@stackframe/stack";
|
||||
import { stackApp } from "@/lib/stack";
|
||||
|
||||
export default async function Protected() {
|
||||
await stack.getUser({ or: 'redirect' });
|
||||
await stackApp.getUser({ or: 'redirect' });
|
||||
return <h1>You can only see this if you are logged in</h1>
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Signing out
|
||||
|
||||
You can sign out the user by redirecting them to `/handler/signout` or simply by calling `user.signOut()`.
|
||||
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="client" label="user.signOut()" default>
|
||||
```tsx
|
||||
"use client";
|
||||
import { useUser } from "@stackframe/stack";
|
||||
|
||||
export default function SignOutButton() {
|
||||
const user = useUser();
|
||||
return <button onClick={() => user?.signOut()}>
|
||||
Sign Out
|
||||
</button>;
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="server" label="Redirect">
|
||||
```tsx
|
||||
import { stackApp } from "@/lib/stack";
|
||||
|
||||
export default async function SignOutLink() {
|
||||
return <a href={stackApp.urls.signOut}>
|
||||
Sign Out
|
||||
</a>;
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### User profile
|
||||
|
||||
Stack automatically creates a user profile on sign-up. Let's create a page that displays this information.
|
||||
|
||||
If you want to use the client component version, create a new file with the following code and import it to `app/page.tsx`. If you want to use the server component version, paste the code directly into `app/page.tsx`.
|
||||
Stack automatically creates a user profile on sign-up. Let's create a page that displays this information. In `app/profile/page.tsx`:
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="client" label="Client Component" default>
|
||||
```tsx
|
||||
'use client';
|
||||
import { useUser, useStackApp } from "@stackframe/stack";
|
||||
```tsx
|
||||
'use client';
|
||||
import { useUser, useStackApp } from "@stackframe/stack";
|
||||
|
||||
export default function PageClient() {
|
||||
const user = useUser();
|
||||
const app = useStackApp();
|
||||
return (
|
||||
<div>
|
||||
<h1>Home</h1>
|
||||
{user ? (
|
||||
export default function PageClient() {
|
||||
const user = useUser();
|
||||
const app = useStackApp();
|
||||
return (
|
||||
<div>
|
||||
<p>Welcome, {user.displayName}</p>
|
||||
<p>Your e-mail: {user.primaryEmail}</p>
|
||||
<p>Your e-mail verification status: {user.primaryEmailVerified}</p>
|
||||
<button onClick={() => user.signOut()}>Sign Out</button>
|
||||
<h1>Home</h1>
|
||||
{user ? (
|
||||
<div>
|
||||
<p>Welcome, {user.displayName}</p>
|
||||
<p>Your e-mail: {user.primaryEmail}</p>
|
||||
<p>Your e-mail verification status: {user.primaryEmailVerified.toString()}</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>
|
||||
) : (
|
||||
<div>
|
||||
<p>You are not logged in</p>
|
||||
<button onClick={() => app.redirectToSignIn()}>Sign in</button>
|
||||
<button onClick={() => app.redirectToSignUp()}>Sign up</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
);
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="server" label="Server Component">
|
||||
```tsx
|
||||
import { stackApp } from "@/lib/stack";
|
||||
```tsx
|
||||
import { stackApp } from "@/lib/stack";
|
||||
|
||||
export default async function Page() {
|
||||
const user = await stackApp.getUser();
|
||||
return (
|
||||
<div>
|
||||
<h1>Home</h1>
|
||||
{user ? (
|
||||
export default async function Page() {
|
||||
const user = await stackApp.getUser();
|
||||
return (
|
||||
<div>
|
||||
<p>Welcome, {user.displayName}</p>
|
||||
<p>Your e-mail: {user.primaryEmail}</p>
|
||||
<p><a href={stackApp.urls.signOut}>Sign Out</a></p>
|
||||
<h1>Home</h1>
|
||||
{user ? (
|
||||
<div>
|
||||
<p>Welcome, {user.displayName}</p>
|
||||
<p>Your e-mail: {user.primaryEmail}</p>
|
||||
<p>Your e-mail verification status: {user.primaryEmailVerified.toString()}</p>
|
||||
<p><a href={stackApp.urls.signOut}>Sign Out</a></p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<p>You are not logged in</p>
|
||||
<p><a href={stackApp.urls.signIn}>Sign in</a></p>
|
||||
<p><a href={stackApp.urls.signUp}>Sign up</a></p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<p>You are not logged in</p>
|
||||
<p><a href={stackApp.urls.signIn}>Sign in</a></p>
|
||||
<p><a href={stackApp.urls.signUp}>Sign up</a></p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
);
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Now, if you visit http://localhost:3000, you should see the main page with user information or sign-in/
|
||||
|
||||
## Next steps
|
||||
|
||||
Next, we will take a look at the actions that can be taken from the server-side.
|
||||
You will now be able to see the new profile page on http://localhost:3000/profile.
|
||||
|
||||
@ -23,7 +23,7 @@ export default function EnvKeys(props: {
|
||||
STACK_SECRET_SERVER_KEY: props.secretServerKey,
|
||||
STACK_SUPER_SECRET_ADMIN_KEY: props.superSecretAdminKey,
|
||||
}).filter(([k, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n")}
|
||||
label="Environment variables"
|
||||
label="Next.js Environment variables"
|
||||
helper={<>Copy these variables into your <InlineCode>.env.local</InlineCode> file.</>}
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
{
|
||||
"name": "@stackframe/stack",
|
||||
"version": "1.2.1",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
@ -16,6 +14,12 @@
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"js-cookie": "^3.0.5",
|
||||
"oauth4webapi": "^2.10.3",
|
||||
@ -26,7 +30,7 @@
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^14",
|
||||
"next": "^14.1",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user