@strayl/agent 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.js +16 -7
- package/package.json +27 -27
- package/skills/api-creation/SKILL.md +631 -631
- package/skills/authentication/SKILL.md +294 -294
- package/skills/frontend-design/SKILL.md +108 -108
- package/skills/landing-creation/SKILL.md +125 -125
- package/skills/reference/SKILL.md +149 -149
- package/skills/web-application-creation/SKILL.md +231 -231
|
@@ -1,294 +1,294 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: authentication
|
|
3
|
-
description: Add authentication to a TanStack Start app using Neon Auth (managed Better Auth). Handles sign-in, sign-up, OAuth, email verification, password reset, session management, route protection, and pre-built auth UI. Use when the user needs user accounts, login, or protected routes.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Authentication (Neon Auth)
|
|
7
|
-
|
|
8
|
-
## When to Use
|
|
9
|
-
|
|
10
|
-
- User asks to add authentication, login, sign-up, or user accounts
|
|
11
|
-
- User wants to protect routes (dashboard, settings, profile, etc.)
|
|
12
|
-
- User mentions "auth", "login", "register", "sign up", "sign in", "logout", "session", "password", "OAuth", "Google sign-in"
|
|
13
|
-
- User needs user management or access control in their app
|
|
14
|
-
- User wants OAuth (Google, GitHub) login
|
|
15
|
-
|
|
16
|
-
## When NOT to Use
|
|
17
|
-
|
|
18
|
-
- User only needs a public site with no user accounts
|
|
19
|
-
- User wants API key authentication (not session-based)
|
|
20
|
-
- User explicitly wants to build auth from scratch without Neon Auth
|
|
21
|
-
|
|
22
|
-
## Prerequisites
|
|
23
|
-
|
|
24
|
-
- A TanStack Start project (scaffolded with `web-application-creation` skill or existing)
|
|
25
|
-
- A database created with `database-management` skill (or will be created in this workflow)
|
|
26
|
-
- `AUTH_BASE_URL` and `VITE_AUTH_BASE_URL` env vars are automatically available after database creation (both set by `create_database`)
|
|
27
|
-
|
|
28
|
-
## Architecture
|
|
29
|
-
|
|
30
|
-
Neon Auth is a **managed authentication service** built on Better Auth. It runs as a REST API deployed in the same region as the Neon database.
|
|
31
|
-
|
|
32
|
-
| Concern | Solution |
|
|
33
|
-
|---------|----------|
|
|
34
|
-
| Auth service | Neon Auth (managed Better Auth) |
|
|
35
|
-
| User storage | `neon_auth` schema in Neon DB (automatic) |
|
|
36
|
-
| UI components | `@neondatabase/neon-js/auth/react/ui` (pre-built) |
|
|
37
|
-
| Session | HTTP-only cookie (`__Secure-neonauth.session_token`), managed by SDK |
|
|
38
|
-
| OAuth | Google works out of the box; GitHub/Vercel need custom credentials |
|
|
39
|
-
|
|
40
|
-
**No custom user table needed.** Users, sessions, and accounts are stored automatically in the `neon_auth` schema.
|
|
41
|
-
|
|
42
|
-
## Workflow
|
|
43
|
-
|
|
44
|
-
### Step 1: Ensure Database Exists
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
universal({ tool: "list_databases", params: {} })
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
If no databases exist, create one first:
|
|
51
|
-
```
|
|
52
|
-
universal({ tool: "create_database", params: { name: "main" } })
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Auth is automatically provisioned when the database is created. The `AUTH_BASE_URL`, `VITE_AUTH_BASE_URL`, and `AUTH_COOKIE_SECRET` env vars are already set in the sandbox and `.env`.
|
|
56
|
-
|
|
57
|
-
### Step 2: Install Neon Auth SDK
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
exec({ command: "cd {app-name} && npm install @neondatabase/neon-js", background: true })
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Step 3: Add Auth Styles
|
|
64
|
-
|
|
65
|
-
**Edit** `src/styles.css` — add the Neon UI import right after the Tailwind import:
|
|
66
|
-
|
|
67
|
-
```css
|
|
68
|
-
@import 'tailwindcss';
|
|
69
|
-
@import '@neondatabase/neon-js/ui/tailwind';
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
If the project does NOT use Tailwind, import the pre-built CSS bundle instead. Add to the root layout or entry point:
|
|
73
|
-
```typescript
|
|
74
|
-
import '@neondatabase/neon-js/ui/css';
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Step 4: Create Auth Client
|
|
78
|
-
|
|
79
|
-
Create `src/auth.ts`. Uses `VITE_AUTH_BASE_URL` which is auto-set by `create_database` — no manual env var setup needed.
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { createAuthClient } from '@neondatabase/neon-js/auth';
|
|
83
|
-
import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react';
|
|
84
|
-
|
|
85
|
-
export const authClient = createAuthClient(
|
|
86
|
-
import.meta.env.VITE_AUTH_BASE_URL,
|
|
87
|
-
{ adapter: BetterAuthReactAdapter() }
|
|
88
|
-
);
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Step 5: Add Auth Provider to Root Route
|
|
92
|
-
|
|
93
|
-
**Edit** `src/routes/__root.tsx` — wrap the app with `NeonAuthUIProvider`:
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react';
|
|
97
|
-
import { authClient } from '../auth';
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Wrap the existing `<Outlet />` (or app content) with the provider:
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
<NeonAuthUIProvider authClient={authClient}>
|
|
104
|
-
<Outlet />
|
|
105
|
-
</NeonAuthUIProvider>
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
**Optional props** for `NeonAuthUIProvider`:
|
|
109
|
-
- `social={{ providers: ['google'] }}` — show OAuth buttons (Google works out of the box)
|
|
110
|
-
- `emailOTP` — enable Email OTP sign-in
|
|
111
|
-
- `credentials={{ forgotPassword: true }}` — enable forgot password flow
|
|
112
|
-
- `navigate={navigate}` — for React Router integration
|
|
113
|
-
|
|
114
|
-
**Do NOT replace** the existing root route — just add the import and wrap the content with the provider.
|
|
115
|
-
|
|
116
|
-
### Step 6: Create Auth Page Route
|
|
117
|
-
|
|
118
|
-
Create `src/routes/auth.$pathname.tsx`:
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
import { createFileRoute } from '@tanstack/react-router';
|
|
122
|
-
import { AuthView } from '@neondatabase/neon-js/auth/react/ui';
|
|
123
|
-
|
|
124
|
-
export const Route = createFileRoute('/auth/$pathname')({
|
|
125
|
-
component: Auth,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
function Auth() {
|
|
129
|
-
const { pathname } = Route.useParams();
|
|
130
|
-
return (
|
|
131
|
-
<div className="flex min-h-screen items-center justify-center">
|
|
132
|
-
<AuthView pathname={pathname} />
|
|
133
|
-
</div>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
This single route handles `/auth/sign-in`, `/auth/sign-up`, `/auth/forgot-password`, etc.
|
|
139
|
-
|
|
140
|
-
### Step 7: Create Account Page Route
|
|
141
|
-
|
|
142
|
-
Create `src/routes/account.$pathname.tsx`:
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
import { createFileRoute } from '@tanstack/react-router';
|
|
146
|
-
import { AccountView } from '@neondatabase/neon-js/auth/react/ui';
|
|
147
|
-
|
|
148
|
-
export const Route = createFileRoute('/account/$pathname')({
|
|
149
|
-
component: Account,
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
function Account() {
|
|
153
|
-
const { pathname } = Route.useParams();
|
|
154
|
-
return (
|
|
155
|
-
<div className="flex min-h-screen items-center justify-center">
|
|
156
|
-
<AccountView pathname={pathname} />
|
|
157
|
-
</div>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
This handles `/account/settings`, `/account/profile`, etc.
|
|
163
|
-
|
|
164
|
-
### Step 8: Protect Routes
|
|
165
|
-
|
|
166
|
-
**Edit** the main page (e.g., `src/routes/index.tsx`) to require authentication:
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
import { createFileRoute } from '@tanstack/react-router';
|
|
170
|
-
import { SignedIn, UserButton, RedirectToSignIn } from '@neondatabase/neon-js/auth/react/ui';
|
|
171
|
-
import { authClient } from '../auth';
|
|
172
|
-
|
|
173
|
-
export const Route = createFileRoute('/')({
|
|
174
|
-
component: Home,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
function Home() {
|
|
178
|
-
const { data } = authClient.useSession();
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<>
|
|
182
|
-
<SignedIn>
|
|
183
|
-
<div className="container mx-auto p-6">
|
|
184
|
-
<div className="flex items-center justify-between">
|
|
185
|
-
<h1 className="text-2xl font-bold">Welcome, {data?.user?.name}!</h1>
|
|
186
|
-
<UserButton />
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
</SignedIn>
|
|
190
|
-
<RedirectToSignIn />
|
|
191
|
-
</>
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Key components:**
|
|
197
|
-
- `<SignedIn>` — renders children only when authenticated
|
|
198
|
-
- `<SignedOut>` — renders children only when NOT authenticated
|
|
199
|
-
- `<RedirectToSignIn>` — redirects to `/auth/sign-in` if not authenticated
|
|
200
|
-
- `<UserButton />` — user avatar/menu dropdown with sign-out
|
|
201
|
-
|
|
202
|
-
### Step 9: Restart and Preview
|
|
203
|
-
|
|
204
|
-
Restart the dev server to pick up new routes and env vars, then `showPreview`. Tell the user to test `/auth/sign-in` and `/auth/sign-up`.
|
|
205
|
-
|
|
206
|
-
## File Structure (after completion)
|
|
207
|
-
|
|
208
|
-
```
|
|
209
|
-
src/
|
|
210
|
-
├── auth.ts # Auth client configuration (NEW)
|
|
211
|
-
├── styles.css # EDITED: added neon-js/ui/tailwind import
|
|
212
|
-
└── routes/
|
|
213
|
-
├── __root.tsx # EDITED: wrapped with NeonAuthUIProvider
|
|
214
|
-
├── auth.$pathname.tsx # NEW: handles sign-in, sign-up, forgot-password
|
|
215
|
-
├── account.$pathname.tsx # NEW: handles account settings, profile
|
|
216
|
-
└── index.tsx # EDITED: added route protection
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## Available UI Components
|
|
220
|
-
|
|
221
|
-
| Component | Import | Purpose |
|
|
222
|
-
|-----------|--------|---------|
|
|
223
|
-
| `<AuthView>` | `@neondatabase/neon-js/auth/react/ui` | Full auth page (sign-in/sign-up/reset) |
|
|
224
|
-
| `<AccountView>` | `@neondatabase/neon-js/auth/react/ui` | Account management page |
|
|
225
|
-
| `<SignedIn>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when authenticated |
|
|
226
|
-
| `<SignedOut>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when NOT authenticated |
|
|
227
|
-
| `<RedirectToSignIn>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-in if not authenticated |
|
|
228
|
-
| `<RedirectToSignUp>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-up if not authenticated |
|
|
229
|
-
| `<UserButton>` | `@neondatabase/neon-js/auth/react/ui` | User avatar dropdown with sign-out |
|
|
230
|
-
| `<UserAvatar>` | `@neondatabase/neon-js/auth/react/ui` | User profile picture |
|
|
231
|
-
| `<SignInForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-in form |
|
|
232
|
-
| `<SignUpForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-up form |
|
|
233
|
-
| `<ForgotPasswordForm>` | `@neondatabase/neon-js/auth/react/ui` | Password recovery form |
|
|
234
|
-
|
|
235
|
-
## Hooks
|
|
236
|
-
|
|
237
|
-
| Hook | Import | Returns |
|
|
238
|
-
|------|--------|---------|
|
|
239
|
-
| `authClient.useSession()` | from auth client | `{ data: { session, user }, isPending }` |
|
|
240
|
-
|
|
241
|
-
## Important Notes
|
|
242
|
-
|
|
243
|
-
- **No custom user table.** Users are stored automatically in the `neon_auth` schema. Query with `SELECT * FROM neon_auth.user;`
|
|
244
|
-
- **No password hashing.** Neon Auth handles all credential management.
|
|
245
|
-
- **No session management.** Sessions are managed by the SDK via HTTP-only cookies.
|
|
246
|
-
- **Google OAuth works immediately** with shared credentials for development. GitHub/Vercel require custom OAuth app setup.
|
|
247
|
-
- **AUTH_BASE_URL is branch-specific.** Each Neon branch has its own auth environment — dev and prod are isolated.
|
|
248
|
-
- Do NOT import both `@neondatabase/neon-js/ui/css` AND `@neondatabase/neon-js/ui/tailwind` — pick one based on whether the project uses Tailwind.
|
|
249
|
-
- Do NOT install `bcryptjs`, `better-auth`, or other auth libraries — Neon Auth replaces them.
|
|
250
|
-
|
|
251
|
-
## SDK Methods Reference
|
|
252
|
-
|
|
253
|
-
For programmatic auth (building custom UI instead of pre-built components):
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import { authClient } from './auth';
|
|
257
|
-
|
|
258
|
-
// Sign up
|
|
259
|
-
await authClient.signUp.email({ email, password, name });
|
|
260
|
-
|
|
261
|
-
// Sign in with email/password
|
|
262
|
-
await authClient.signIn.email({ email, password });
|
|
263
|
-
|
|
264
|
-
// Sign in with OAuth
|
|
265
|
-
await authClient.signIn.social({ provider: 'google', callbackURL: '/' });
|
|
266
|
-
|
|
267
|
-
// Sign out
|
|
268
|
-
await authClient.signOut();
|
|
269
|
-
|
|
270
|
-
// Get current session
|
|
271
|
-
const { data } = await authClient.getSession();
|
|
272
|
-
// data.session, data.user
|
|
273
|
-
|
|
274
|
-
// React hook for session
|
|
275
|
-
const { data } = authClient.useSession();
|
|
276
|
-
|
|
277
|
-
// Update user profile
|
|
278
|
-
await authClient.updateUser({ name: 'New Name' });
|
|
279
|
-
|
|
280
|
-
// Change password
|
|
281
|
-
await authClient.changePassword({ currentPassword, newPassword });
|
|
282
|
-
|
|
283
|
-
// Email OTP verification
|
|
284
|
-
await authClient.emailOtp.verifyEmail({ email, otp: code });
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Extending
|
|
288
|
-
|
|
289
|
-
- **OAuth providers** — add `social={{ providers: ['google', 'github', 'vercel'] }}` to `NeonAuthUIProvider`
|
|
290
|
-
- **Forgot password** — add `credentials={{ forgotPassword: true }}` to `NeonAuthUIProvider`, or use `<ForgotPasswordForm>` and `<ResetPasswordForm>` components
|
|
291
|
-
- **Email verification** — enable in Neon Console (Settings > Auth). Use verification codes (works out of the box) or verification links (requires custom SMTP)
|
|
292
|
-
- **Custom sign-up fields** — use `additionalFields` and `signUp` props on `NeonAuthUIProvider`
|
|
293
|
-
- **Custom localization** — use `localization` prop to change labels (e.g., `{ SIGN_IN: 'Welcome Back' }`)
|
|
294
|
-
- **Protected route layout** — create `src/routes/_authed.tsx` with `<SignedIn>` check for route groups
|
|
1
|
+
---
|
|
2
|
+
name: authentication
|
|
3
|
+
description: Add authentication to a TanStack Start app using Neon Auth (managed Better Auth). Handles sign-in, sign-up, OAuth, email verification, password reset, session management, route protection, and pre-built auth UI. Use when the user needs user accounts, login, or protected routes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authentication (Neon Auth)
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- User asks to add authentication, login, sign-up, or user accounts
|
|
11
|
+
- User wants to protect routes (dashboard, settings, profile, etc.)
|
|
12
|
+
- User mentions "auth", "login", "register", "sign up", "sign in", "logout", "session", "password", "OAuth", "Google sign-in"
|
|
13
|
+
- User needs user management or access control in their app
|
|
14
|
+
- User wants OAuth (Google, GitHub) login
|
|
15
|
+
|
|
16
|
+
## When NOT to Use
|
|
17
|
+
|
|
18
|
+
- User only needs a public site with no user accounts
|
|
19
|
+
- User wants API key authentication (not session-based)
|
|
20
|
+
- User explicitly wants to build auth from scratch without Neon Auth
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- A TanStack Start project (scaffolded with `web-application-creation` skill or existing)
|
|
25
|
+
- A database created with `database-management` skill (or will be created in this workflow)
|
|
26
|
+
- `AUTH_BASE_URL` and `VITE_AUTH_BASE_URL` env vars are automatically available after database creation (both set by `create_database`)
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
Neon Auth is a **managed authentication service** built on Better Auth. It runs as a REST API deployed in the same region as the Neon database.
|
|
31
|
+
|
|
32
|
+
| Concern | Solution |
|
|
33
|
+
|---------|----------|
|
|
34
|
+
| Auth service | Neon Auth (managed Better Auth) |
|
|
35
|
+
| User storage | `neon_auth` schema in Neon DB (automatic) |
|
|
36
|
+
| UI components | `@neondatabase/neon-js/auth/react/ui` (pre-built) |
|
|
37
|
+
| Session | HTTP-only cookie (`__Secure-neonauth.session_token`), managed by SDK |
|
|
38
|
+
| OAuth | Google works out of the box; GitHub/Vercel need custom credentials |
|
|
39
|
+
|
|
40
|
+
**No custom user table needed.** Users, sessions, and accounts are stored automatically in the `neon_auth` schema.
|
|
41
|
+
|
|
42
|
+
## Workflow
|
|
43
|
+
|
|
44
|
+
### Step 1: Ensure Database Exists
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
universal({ tool: "list_databases", params: {} })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If no databases exist, create one first:
|
|
51
|
+
```
|
|
52
|
+
universal({ tool: "create_database", params: { name: "main" } })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Auth is automatically provisioned when the database is created. The `AUTH_BASE_URL`, `VITE_AUTH_BASE_URL`, and `AUTH_COOKIE_SECRET` env vars are already set in the sandbox and `.env`.
|
|
56
|
+
|
|
57
|
+
### Step 2: Install Neon Auth SDK
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
exec({ command: "cd {app-name} && npm install @neondatabase/neon-js", background: true })
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Step 3: Add Auth Styles
|
|
64
|
+
|
|
65
|
+
**Edit** `src/styles.css` — add the Neon UI import right after the Tailwind import:
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
@import 'tailwindcss';
|
|
69
|
+
@import '@neondatabase/neon-js/ui/tailwind';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If the project does NOT use Tailwind, import the pre-built CSS bundle instead. Add to the root layout or entry point:
|
|
73
|
+
```typescript
|
|
74
|
+
import '@neondatabase/neon-js/ui/css';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Step 4: Create Auth Client
|
|
78
|
+
|
|
79
|
+
Create `src/auth.ts`. Uses `VITE_AUTH_BASE_URL` which is auto-set by `create_database` — no manual env var setup needed.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { createAuthClient } from '@neondatabase/neon-js/auth';
|
|
83
|
+
import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react';
|
|
84
|
+
|
|
85
|
+
export const authClient = createAuthClient(
|
|
86
|
+
import.meta.env.VITE_AUTH_BASE_URL,
|
|
87
|
+
{ adapter: BetterAuthReactAdapter() }
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Step 5: Add Auth Provider to Root Route
|
|
92
|
+
|
|
93
|
+
**Edit** `src/routes/__root.tsx` — wrap the app with `NeonAuthUIProvider`:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react';
|
|
97
|
+
import { authClient } from '../auth';
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Wrap the existing `<Outlet />` (or app content) with the provider:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<NeonAuthUIProvider authClient={authClient}>
|
|
104
|
+
<Outlet />
|
|
105
|
+
</NeonAuthUIProvider>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Optional props** for `NeonAuthUIProvider`:
|
|
109
|
+
- `social={{ providers: ['google'] }}` — show OAuth buttons (Google works out of the box)
|
|
110
|
+
- `emailOTP` — enable Email OTP sign-in
|
|
111
|
+
- `credentials={{ forgotPassword: true }}` — enable forgot password flow
|
|
112
|
+
- `navigate={navigate}` — for React Router integration
|
|
113
|
+
|
|
114
|
+
**Do NOT replace** the existing root route — just add the import and wrap the content with the provider.
|
|
115
|
+
|
|
116
|
+
### Step 6: Create Auth Page Route
|
|
117
|
+
|
|
118
|
+
Create `src/routes/auth.$pathname.tsx`:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
122
|
+
import { AuthView } from '@neondatabase/neon-js/auth/react/ui';
|
|
123
|
+
|
|
124
|
+
export const Route = createFileRoute('/auth/$pathname')({
|
|
125
|
+
component: Auth,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
function Auth() {
|
|
129
|
+
const { pathname } = Route.useParams();
|
|
130
|
+
return (
|
|
131
|
+
<div className="flex min-h-screen items-center justify-center">
|
|
132
|
+
<AuthView pathname={pathname} />
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This single route handles `/auth/sign-in`, `/auth/sign-up`, `/auth/forgot-password`, etc.
|
|
139
|
+
|
|
140
|
+
### Step 7: Create Account Page Route
|
|
141
|
+
|
|
142
|
+
Create `src/routes/account.$pathname.tsx`:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
146
|
+
import { AccountView } from '@neondatabase/neon-js/auth/react/ui';
|
|
147
|
+
|
|
148
|
+
export const Route = createFileRoute('/account/$pathname')({
|
|
149
|
+
component: Account,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
function Account() {
|
|
153
|
+
const { pathname } = Route.useParams();
|
|
154
|
+
return (
|
|
155
|
+
<div className="flex min-h-screen items-center justify-center">
|
|
156
|
+
<AccountView pathname={pathname} />
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This handles `/account/settings`, `/account/profile`, etc.
|
|
163
|
+
|
|
164
|
+
### Step 8: Protect Routes
|
|
165
|
+
|
|
166
|
+
**Edit** the main page (e.g., `src/routes/index.tsx`) to require authentication:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
170
|
+
import { SignedIn, UserButton, RedirectToSignIn } from '@neondatabase/neon-js/auth/react/ui';
|
|
171
|
+
import { authClient } from '../auth';
|
|
172
|
+
|
|
173
|
+
export const Route = createFileRoute('/')({
|
|
174
|
+
component: Home,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
function Home() {
|
|
178
|
+
const { data } = authClient.useSession();
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<>
|
|
182
|
+
<SignedIn>
|
|
183
|
+
<div className="container mx-auto p-6">
|
|
184
|
+
<div className="flex items-center justify-between">
|
|
185
|
+
<h1 className="text-2xl font-bold">Welcome, {data?.user?.name}!</h1>
|
|
186
|
+
<UserButton />
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</SignedIn>
|
|
190
|
+
<RedirectToSignIn />
|
|
191
|
+
</>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Key components:**
|
|
197
|
+
- `<SignedIn>` — renders children only when authenticated
|
|
198
|
+
- `<SignedOut>` — renders children only when NOT authenticated
|
|
199
|
+
- `<RedirectToSignIn>` — redirects to `/auth/sign-in` if not authenticated
|
|
200
|
+
- `<UserButton />` — user avatar/menu dropdown with sign-out
|
|
201
|
+
|
|
202
|
+
### Step 9: Restart and Preview
|
|
203
|
+
|
|
204
|
+
Restart the dev server to pick up new routes and env vars, then `showPreview`. Tell the user to test `/auth/sign-in` and `/auth/sign-up`.
|
|
205
|
+
|
|
206
|
+
## File Structure (after completion)
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
src/
|
|
210
|
+
├── auth.ts # Auth client configuration (NEW)
|
|
211
|
+
├── styles.css # EDITED: added neon-js/ui/tailwind import
|
|
212
|
+
└── routes/
|
|
213
|
+
├── __root.tsx # EDITED: wrapped with NeonAuthUIProvider
|
|
214
|
+
├── auth.$pathname.tsx # NEW: handles sign-in, sign-up, forgot-password
|
|
215
|
+
├── account.$pathname.tsx # NEW: handles account settings, profile
|
|
216
|
+
└── index.tsx # EDITED: added route protection
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Available UI Components
|
|
220
|
+
|
|
221
|
+
| Component | Import | Purpose |
|
|
222
|
+
|-----------|--------|---------|
|
|
223
|
+
| `<AuthView>` | `@neondatabase/neon-js/auth/react/ui` | Full auth page (sign-in/sign-up/reset) |
|
|
224
|
+
| `<AccountView>` | `@neondatabase/neon-js/auth/react/ui` | Account management page |
|
|
225
|
+
| `<SignedIn>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when authenticated |
|
|
226
|
+
| `<SignedOut>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when NOT authenticated |
|
|
227
|
+
| `<RedirectToSignIn>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-in if not authenticated |
|
|
228
|
+
| `<RedirectToSignUp>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-up if not authenticated |
|
|
229
|
+
| `<UserButton>` | `@neondatabase/neon-js/auth/react/ui` | User avatar dropdown with sign-out |
|
|
230
|
+
| `<UserAvatar>` | `@neondatabase/neon-js/auth/react/ui` | User profile picture |
|
|
231
|
+
| `<SignInForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-in form |
|
|
232
|
+
| `<SignUpForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-up form |
|
|
233
|
+
| `<ForgotPasswordForm>` | `@neondatabase/neon-js/auth/react/ui` | Password recovery form |
|
|
234
|
+
|
|
235
|
+
## Hooks
|
|
236
|
+
|
|
237
|
+
| Hook | Import | Returns |
|
|
238
|
+
|------|--------|---------|
|
|
239
|
+
| `authClient.useSession()` | from auth client | `{ data: { session, user }, isPending }` |
|
|
240
|
+
|
|
241
|
+
## Important Notes
|
|
242
|
+
|
|
243
|
+
- **No custom user table.** Users are stored automatically in the `neon_auth` schema. Query with `SELECT * FROM neon_auth.user;`
|
|
244
|
+
- **No password hashing.** Neon Auth handles all credential management.
|
|
245
|
+
- **No session management.** Sessions are managed by the SDK via HTTP-only cookies.
|
|
246
|
+
- **Google OAuth works immediately** with shared credentials for development. GitHub/Vercel require custom OAuth app setup.
|
|
247
|
+
- **AUTH_BASE_URL is branch-specific.** Each Neon branch has its own auth environment — dev and prod are isolated.
|
|
248
|
+
- Do NOT import both `@neondatabase/neon-js/ui/css` AND `@neondatabase/neon-js/ui/tailwind` — pick one based on whether the project uses Tailwind.
|
|
249
|
+
- Do NOT install `bcryptjs`, `better-auth`, or other auth libraries — Neon Auth replaces them.
|
|
250
|
+
|
|
251
|
+
## SDK Methods Reference
|
|
252
|
+
|
|
253
|
+
For programmatic auth (building custom UI instead of pre-built components):
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { authClient } from './auth';
|
|
257
|
+
|
|
258
|
+
// Sign up
|
|
259
|
+
await authClient.signUp.email({ email, password, name });
|
|
260
|
+
|
|
261
|
+
// Sign in with email/password
|
|
262
|
+
await authClient.signIn.email({ email, password });
|
|
263
|
+
|
|
264
|
+
// Sign in with OAuth
|
|
265
|
+
await authClient.signIn.social({ provider: 'google', callbackURL: '/' });
|
|
266
|
+
|
|
267
|
+
// Sign out
|
|
268
|
+
await authClient.signOut();
|
|
269
|
+
|
|
270
|
+
// Get current session
|
|
271
|
+
const { data } = await authClient.getSession();
|
|
272
|
+
// data.session, data.user
|
|
273
|
+
|
|
274
|
+
// React hook for session
|
|
275
|
+
const { data } = authClient.useSession();
|
|
276
|
+
|
|
277
|
+
// Update user profile
|
|
278
|
+
await authClient.updateUser({ name: 'New Name' });
|
|
279
|
+
|
|
280
|
+
// Change password
|
|
281
|
+
await authClient.changePassword({ currentPassword, newPassword });
|
|
282
|
+
|
|
283
|
+
// Email OTP verification
|
|
284
|
+
await authClient.emailOtp.verifyEmail({ email, otp: code });
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Extending
|
|
288
|
+
|
|
289
|
+
- **OAuth providers** — add `social={{ providers: ['google', 'github', 'vercel'] }}` to `NeonAuthUIProvider`
|
|
290
|
+
- **Forgot password** — add `credentials={{ forgotPassword: true }}` to `NeonAuthUIProvider`, or use `<ForgotPasswordForm>` and `<ResetPasswordForm>` components
|
|
291
|
+
- **Email verification** — enable in Neon Console (Settings > Auth). Use verification codes (works out of the box) or verification links (requires custom SMTP)
|
|
292
|
+
- **Custom sign-up fields** — use `additionalFields` and `signUp` props on `NeonAuthUIProvider`
|
|
293
|
+
- **Custom localization** — use `localization` prop to change labels (e.g., `{ SIGN_IN: 'Welcome Back' }`)
|
|
294
|
+
- **Protected route layout** — create `src/routes/_authed.tsx` with `<SignedIn>` check for route groups
|