create-aron-app 0.1.0 → 0.1.1

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.
Files changed (156) hide show
  1. package/package.json +5 -2
  2. package/templates/_base/.cursor/agents/skills/clerk/SKILL.md +89 -0
  3. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/SKILL.md +142 -0
  4. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +30 -0
  5. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +88 -0
  6. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +165 -0
  7. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +208 -0
  8. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +14 -0
  9. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/SKILL.md +157 -0
  10. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +224 -0
  11. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +190 -0
  12. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +314 -0
  13. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +259 -0
  14. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +125 -0
  15. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +94 -0
  16. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +50 -0
  17. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +56 -0
  18. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +68 -0
  19. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +56 -0
  20. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +104 -0
  21. package/templates/_base/.cursor/agents/skills/clerk/clerk-webhooks/SKILL.md +131 -0
  22. package/templates/_base/.cursor/agents/skills/shadcn/SKILL.md +241 -0
  23. package/templates/_base/.cursor/agents/skills/shadcn/agents/openai.yml +5 -0
  24. package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn-small.png +0 -0
  25. package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn.png +0 -0
  26. package/templates/_base/.cursor/agents/skills/shadcn/cli.md +257 -0
  27. package/templates/_base/.cursor/agents/skills/shadcn/customization.md +202 -0
  28. package/templates/_base/.cursor/agents/skills/shadcn/evals/evals.json +47 -0
  29. package/templates/_base/.cursor/agents/skills/shadcn/mcp.md +94 -0
  30. package/templates/_base/.cursor/agents/skills/shadcn/rules/base-vs-radix.md +306 -0
  31. package/templates/_base/.cursor/agents/skills/shadcn/rules/composition.md +195 -0
  32. package/templates/_base/.cursor/agents/skills/shadcn/rules/forms.md +192 -0
  33. package/templates/_base/.cursor/agents/skills/shadcn/rules/icons.md +101 -0
  34. package/templates/_base/.cursor/agents/skills/shadcn/rules/styling.md +162 -0
  35. package/templates/_base/.cursor/commands/builder.md +0 -0
  36. package/templates/_base/.cursor/commands/pr.md +7 -0
  37. package/templates/_base/.cursor/rules/api_architecture.mdc +268 -0
  38. package/templates/_base/.cursor/rules/coding_standards.mdc +64 -0
  39. package/templates/_base/.cursor/rules/convex_rules.mdc +675 -0
  40. package/templates/_base/.cursor/rules/frontend_rules.mdc +268 -0
  41. package/templates/_base/.env.convex.example +3 -0
  42. package/templates/_base/.github/workflows/ci.yml +29 -0
  43. package/templates/_base/.nvmrc +1 -0
  44. package/templates/_base/.vscode/settings.json +9 -0
  45. package/templates/_base/apps/api/auth.config.ts +18 -0
  46. package/templates/_base/apps/api/functions.ts +99 -0
  47. package/templates/_base/apps/api/project.json +22 -0
  48. package/templates/_base/apps/api/schema.ts +11 -0
  49. package/templates/_base/apps/api/todos/crud.ts +81 -0
  50. package/templates/_base/apps/api/todos/schema.ts +11 -0
  51. package/templates/_base/apps/api/todos/types.ts +22 -0
  52. package/templates/_base/apps/api/tsconfig.json +23 -0
  53. package/templates/_base/apps/api/types.ts +16 -0
  54. package/templates/_base/biome.json +114 -0
  55. package/templates/_base/convex.json +4 -0
  56. package/templates/_base/emails/project.json +16 -0
  57. package/templates/_base/emails/tsconfig.json +5 -0
  58. package/templates/_base/emails/welcome_email.tsx +53 -0
  59. package/templates/_base/nx.json +29 -0
  60. package/templates/_base/package.json +73 -0
  61. package/templates/_base/scripts/sync_convex_env.ts +63 -0
  62. package/templates/_base/shared/assets/image.d.ts +4 -0
  63. package/templates/_base/shared/assets/src/styles/global.css +73 -0
  64. package/templates/_base/shared/assets/tsconfig.json +5 -0
  65. package/templates/_base/shared/ui/src/base/alert_dialog.tsx +139 -0
  66. package/templates/_base/shared/ui/src/base/badge.tsx +33 -0
  67. package/templates/_base/shared/ui/src/base/basic_data_table.tsx +61 -0
  68. package/templates/_base/shared/ui/src/base/button.tsx +69 -0
  69. package/templates/_base/shared/ui/src/base/button_group.tsx +82 -0
  70. package/templates/_base/shared/ui/src/base/card.tsx +79 -0
  71. package/templates/_base/shared/ui/src/base/checkbox.tsx +26 -0
  72. package/templates/_base/shared/ui/src/base/command.tsx +165 -0
  73. package/templates/_base/shared/ui/src/base/dialog.tsx +129 -0
  74. package/templates/_base/shared/ui/src/base/dropdown_menu.tsx +232 -0
  75. package/templates/_base/shared/ui/src/base/form.tsx +161 -0
  76. package/templates/_base/shared/ui/src/base/input.tsx +129 -0
  77. package/templates/_base/shared/ui/src/base/label.tsx +19 -0
  78. package/templates/_base/shared/ui/src/base/popover.tsx +46 -0
  79. package/templates/_base/shared/ui/src/base/radio_group.tsx +49 -0
  80. package/templates/_base/shared/ui/src/base/resizable.tsx +55 -0
  81. package/templates/_base/shared/ui/src/base/scroll_area.tsx +44 -0
  82. package/templates/_base/shared/ui/src/base/select.tsx +151 -0
  83. package/templates/_base/shared/ui/src/base/separator.tsx +32 -0
  84. package/templates/_base/shared/ui/src/base/sheet.tsx +130 -0
  85. package/templates/_base/shared/ui/src/base/side_bar.tsx +688 -0
  86. package/templates/_base/shared/ui/src/base/skeleton.tsx +7 -0
  87. package/templates/_base/shared/ui/src/base/spinner.tsx +20 -0
  88. package/templates/_base/shared/ui/src/base/switch.tsx +27 -0
  89. package/templates/_base/shared/ui/src/base/table.tsx +91 -0
  90. package/templates/_base/shared/ui/src/base/text_area.tsx +21 -0
  91. package/templates/_base/shared/ui/src/base/tooltip.tsx +31 -0
  92. package/templates/_base/shared/ui/src/base/utils.ts +17 -0
  93. package/templates/_base/shared/ui/src/hooks/use_keyboard_press.tsx +48 -0
  94. package/templates/_base/shared/ui/src/hooks/use_keyboard_release.tsx +48 -0
  95. package/templates/_base/shared/ui/src/hooks/use_mobile.tsx +25 -0
  96. package/templates/_base/shared/ui/src/hooks/use_mouse_click.tsx +44 -0
  97. package/templates/_base/shared/ui/src/hooks/use_mouse_location.tsx +55 -0
  98. package/templates/_base/shared/ui/src/hooks/use_outside_click.tsx +29 -0
  99. package/templates/_base/shared/ui/src/hooks/use_query_params.tsx +33 -0
  100. package/templates/_base/shared/ui/tsconfig.json +8 -0
  101. package/templates/_base/shared/utils/src/convex.ts +3 -0
  102. package/templates/_base/shared/utils/src/time.ts +12 -0
  103. package/templates/_base/shared/utils/tsconfig.json +5 -0
  104. package/templates/_base/skills-lock.json +35 -0
  105. package/templates/_base/tsconfig.base.json +34 -0
  106. package/templates/nextjs/.env.example +8 -0
  107. package/templates/nextjs/index.d.ts +6 -0
  108. package/templates/nextjs/next-env.d.ts +5 -0
  109. package/templates/nextjs/next.config.js +22 -0
  110. package/templates/nextjs/postcss.config.js +17 -0
  111. package/templates/nextjs/project.json +22 -0
  112. package/templates/nextjs/src/app/(auth)/layout.tsx +21 -0
  113. package/templates/nextjs/src/app/(auth)/not-allowed/page.tsx +22 -0
  114. package/templates/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +15 -0
  115. package/templates/nextjs/src/app/(dashboard)/layout.tsx +27 -0
  116. package/templates/nextjs/src/app/(dashboard)/page.tsx +5 -0
  117. package/templates/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +23 -0
  118. package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +16 -0
  119. package/templates/nextjs/src/app/app.css +3 -0
  120. package/templates/nextjs/src/app/layout.tsx +26 -0
  121. package/templates/nextjs/src/convex.ts +11 -0
  122. package/templates/nextjs/src/middleware.ts +18 -0
  123. package/templates/nextjs/src/providers/convex_provider.tsx +44 -0
  124. package/templates/nextjs/src/surfaces/home_surface.tsx +22 -0
  125. package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +97 -0
  126. package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +107 -0
  127. package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +90 -0
  128. package/templates/nextjs/src/ui/sidebar/nav_link.tsx +36 -0
  129. package/templates/nextjs/src/ui/sidebar/sidebar.tsx +125 -0
  130. package/templates/nextjs/src/utils/font.ts +9 -0
  131. package/templates/nextjs/tsconfig.json +42 -0
  132. package/templates/react-router/.env.example +8 -0
  133. package/templates/react-router/postcss.config.js +15 -0
  134. package/templates/react-router/project.json +23 -0
  135. package/templates/react-router/public/favicon.ico +0 -0
  136. package/templates/react-router/react-router.config.ts +9 -0
  137. package/templates/react-router/src/app.css +3 -0
  138. package/templates/react-router/src/components/error_boundary.tsx +33 -0
  139. package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +76 -0
  140. package/templates/react-router/src/layouts/sidebar/sidebar_aside/user_menu.tsx +36 -0
  141. package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +22 -0
  142. package/templates/react-router/src/providers/api_auth_provider.tsx +38 -0
  143. package/templates/react-router/src/root.tsx +37 -0
  144. package/templates/react-router/src/routes/auth/layout.tsx +13 -0
  145. package/templates/react-router/src/routes/auth/sign-in.tsx +13 -0
  146. package/templates/react-router/src/routes/index.tsx +9 -0
  147. package/templates/react-router/src/routes/layout.tsx +26 -0
  148. package/templates/react-router/src/routes/todos/[id].tsx +22 -0
  149. package/templates/react-router/src/routes/todos/index.tsx +13 -0
  150. package/templates/react-router/src/routes.ts +12 -0
  151. package/templates/react-router/src/surfaces/home_surface.tsx +20 -0
  152. package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +87 -0
  153. package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +102 -0
  154. package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +81 -0
  155. package/templates/react-router/tsconfig.json +20 -0
  156. package/templates/react-router/vite.config.ts +40 -0
@@ -0,0 +1,190 @@
1
+ # Custom Sign-Up Flow (Core 2)
2
+
3
+ > This document covers the **older SDK** (`@clerk/nextjs` v5–v6, `@clerk/clerk-react` v5–v6, `@clerk/clerk-expo` v1–v2). For the current SDK, see `core-3/custom-sign-up.md`.
4
+
5
+ Build a custom sign-up experience using the `useSignUp()` hook.
6
+
7
+ ## Hook API
8
+
9
+ ```typescript
10
+ import { useSignUp } from '@clerk/nextjs' // or @clerk/clerk-react, @clerk/clerk-expo
11
+
12
+ const { signUp, isLoaded, setActive } = useSignUp()
13
+ ```
14
+
15
+ | Property | Type | Description |
16
+ |----------|------|-------------|
17
+ | `signUp` | `SignUp` | Sign-up object with methods |
18
+ | `isLoaded` | `boolean` | Whether the hook has loaded |
19
+ | `setActive` | `(params) => Promise` | Sets the active session |
20
+
21
+ ## Sign-Up Flow
22
+
23
+ ### 1. Create Sign-Up
24
+
25
+ ```typescript
26
+ const result = await signUp.create({
27
+ emailAddress: 'user@example.com',
28
+ password: 'securePassword123',
29
+ firstName: 'Jane', // optional
30
+ lastName: 'Doe', // optional
31
+ })
32
+ ```
33
+
34
+ ### 2. Prepare Verification
35
+
36
+ Send a verification code to the user's email or phone:
37
+
38
+ ```typescript
39
+ await signUp.prepareVerification({
40
+ strategy: 'email_code', // or 'phone_code', 'email_link'
41
+ })
42
+ ```
43
+
44
+ ### 3. Attempt Verification
45
+
46
+ Verify the code the user received:
47
+
48
+ ```typescript
49
+ const result = await signUp.attemptVerification({
50
+ strategy: 'email_code',
51
+ code: '123456',
52
+ })
53
+ ```
54
+
55
+ ### 4. Finalize
56
+
57
+ Set the active session after successful sign-up:
58
+
59
+ ```typescript
60
+ await setActive({ session: signUp.createdSessionId })
61
+ ```
62
+
63
+ ### SSO (OAuth)
64
+
65
+ ```typescript
66
+ await signUp.authenticateWithRedirect({
67
+ strategy: 'oauth_google',
68
+ redirectUrl: '/sso-callback',
69
+ redirectUrlComplete: '/',
70
+ })
71
+ ```
72
+
73
+ ## Error Handling
74
+
75
+ Use try/catch with `isClerkAPIResponseError()`:
76
+
77
+ ```typescript
78
+ import { isClerkAPIResponseError } from '@clerk/nextjs/errors'
79
+
80
+ try {
81
+ await signUp.create({ emailAddress, password })
82
+ } catch (err) {
83
+ if (isClerkAPIResponseError(err)) {
84
+ err.errors.forEach((e) => {
85
+ console.log(e.code) // e.g. 'form_password_pwned'
86
+ console.log(e.message) // Human-readable message
87
+ console.log(e.longMessage) // Detailed message
88
+ })
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## Complete Example: Email/Password with Email Verification
94
+
95
+ ```tsx
96
+ 'use client'
97
+ import { useState } from 'react'
98
+ import { useSignUp } from '@clerk/nextjs'
99
+ import { isClerkAPIResponseError } from '@clerk/nextjs/errors'
100
+ import { useRouter } from 'next/navigation'
101
+
102
+ export default function SignUpPage() {
103
+ const { signUp, isLoaded, setActive } = useSignUp()
104
+ const router = useRouter()
105
+
106
+ const [email, setEmail] = useState('')
107
+ const [password, setPassword] = useState('')
108
+ const [code, setCode] = useState('')
109
+ const [step, setStep] = useState<'register' | 'verify'>('register')
110
+ const [error, setError] = useState('')
111
+
112
+ if (!isLoaded) return <div>Loading...</div>
113
+
114
+ async function handleRegister(e: React.FormEvent) {
115
+ e.preventDefault()
116
+ setError('')
117
+
118
+ try {
119
+ await signUp.create({ emailAddress: email, password })
120
+ await signUp.prepareVerification({ strategy: 'email_code' })
121
+ setStep('verify')
122
+ } catch (err) {
123
+ if (isClerkAPIResponseError(err)) {
124
+ setError(err.errors[0]?.message || 'Sign up failed')
125
+ }
126
+ }
127
+ }
128
+
129
+ async function handleVerify(e: React.FormEvent) {
130
+ e.preventDefault()
131
+ setError('')
132
+
133
+ try {
134
+ const result = await signUp.attemptVerification({
135
+ strategy: 'email_code',
136
+ code,
137
+ })
138
+
139
+ if (result.status === 'complete') {
140
+ await setActive({ session: result.createdSessionId })
141
+ router.push('/')
142
+ }
143
+ } catch (err) {
144
+ if (isClerkAPIResponseError(err)) {
145
+ setError(err.errors[0]?.message || 'Verification failed')
146
+ }
147
+ }
148
+ }
149
+
150
+ if (step === 'verify') {
151
+ return (
152
+ <form onSubmit={handleVerify}>
153
+ <p>Check your email for a verification code.</p>
154
+ <input
155
+ type="text"
156
+ value={code}
157
+ onChange={(e) => setCode(e.target.value)}
158
+ placeholder="Verification code"
159
+ />
160
+ {error && <p>{error}</p>}
161
+ <button type="submit">Verify Email</button>
162
+ </form>
163
+ )
164
+ }
165
+
166
+ return (
167
+ <form onSubmit={handleRegister}>
168
+ <input
169
+ type="email"
170
+ value={email}
171
+ onChange={(e) => setEmail(e.target.value)}
172
+ placeholder="Email"
173
+ />
174
+ <input
175
+ type="password"
176
+ value={password}
177
+ onChange={(e) => setPassword(e.target.value)}
178
+ placeholder="Password"
179
+ />
180
+ {error && <p>{error}</p>}
181
+ <button type="submit">Sign Up</button>
182
+ </form>
183
+ )
184
+ }
185
+ ```
186
+
187
+ ## Docs
188
+
189
+ - [Custom sign-up flow](https://clerk.com/docs/custom-flows/overview)
190
+ - [useSignUp() reference](https://clerk.com/docs/references/react/use-sign-up)
@@ -0,0 +1,314 @@
1
+ # Custom Sign-In Flow
2
+
3
+ Build a custom sign-in experience using the `useSignIn()` hook.
4
+
5
+ ## Hook API
6
+
7
+ ```typescript
8
+ import { useSignIn } from '@clerk/nextjs' // or @clerk/react, @clerk/expo
9
+
10
+ const { signIn, errors, fetchStatus } = useSignIn()
11
+ ```
12
+
13
+ | Property | Type | Description |
14
+ |----------|------|-------------|
15
+ | `signIn` | `SignInFuture` | Sign-in object with namespaced methods |
16
+ | `errors` | `Errors<SignInFields>` | Structured error object |
17
+ | `fetchStatus` | `'idle' \| 'fetching'` | Network request status |
18
+
19
+ ## Sign-In Methods
20
+
21
+ ### Password
22
+
23
+ ```typescript
24
+ const { error } = await signIn.password({
25
+ identifier: 'user@example.com',
26
+ password: 'securePassword123',
27
+ })
28
+ ```
29
+
30
+ ### SSO (OAuth / Enterprise)
31
+
32
+ ```typescript
33
+ const { error } = await signIn.sso({
34
+ strategy: 'oauth_google', // or 'oauth_github', 'enterprise_sso', etc.
35
+ redirectUrl: '/dashboard', // where to go after SSO completes
36
+ redirectCallbackUrl: '/sso-callback', // intermediate callback route
37
+ })
38
+ ```
39
+
40
+ ### Passkey
41
+
42
+ ```typescript
43
+ const { error } = await signIn.passkey({ flow: 'discoverable' })
44
+ ```
45
+
46
+ ### Web3
47
+
48
+ ```typescript
49
+ const { error } = await signIn.web3({ strategy: 'web3_solana_signature' })
50
+ // or
51
+ const { error } = await signIn.web3({ strategy: 'web3_base_signature' })
52
+ ```
53
+
54
+ ### Ticket (Invitation link)
55
+
56
+ ```typescript
57
+ const { error } = await signIn.ticket({ ticket: 'ticket_abc123' })
58
+ ```
59
+
60
+ ### Email Code
61
+
62
+ ```typescript
63
+ // Send code (emailAddress is optional if a signIn already exists from a prior method call)
64
+ const { error } = await signIn.emailCode.sendCode({ emailAddress: 'user@example.com' })
65
+
66
+ // Verify code
67
+ const { error } = await signIn.emailCode.verifyCode({ code: '123456' })
68
+ ```
69
+
70
+ ### Phone Code
71
+
72
+ ```typescript
73
+ // Send code (phoneNumber is optional if a signIn already exists from a prior method call)
74
+ const { error } = await signIn.phoneCode.sendCode({ phoneNumber: '+12015551234' })
75
+
76
+ // Verify code
77
+ const { error } = await signIn.phoneCode.verifyCode({ code: '123456' })
78
+ ```
79
+
80
+ ## MFA (Second Factor)
81
+
82
+ A second factor is required when `signIn.status` is one of:
83
+ - `'needs_second_factor'` — user has MFA enabled (TOTP, backup codes, etc.)
84
+ - `'needs_client_trust'` — new device sign-in without MFA; requires email or phone code verification
85
+
86
+ ```typescript
87
+ // TOTP (Authenticator app)
88
+ const { error } = await signIn.mfa.verifyTOTP({ code: '123456' })
89
+
90
+ // Backup code
91
+ const { error } = await signIn.mfa.verifyBackupCode({ code: 'backup-code-here' })
92
+
93
+ // Email code
94
+ const { error: sendErr } = await signIn.mfa.sendEmailCode()
95
+ const { error: verifyErr } = await signIn.mfa.verifyEmailCode({ code: '123456' })
96
+
97
+ // Phone code
98
+ const { error: sendErr } = await signIn.mfa.sendPhoneCode()
99
+ const { error: verifyErr } = await signIn.mfa.verifyPhoneCode({ code: '123456' })
100
+ ```
101
+
102
+ ## Password Reset
103
+
104
+ ```typescript
105
+ // 1. Send reset code
106
+ const { error } = await signIn.resetPasswordEmailCode.sendCode()
107
+
108
+ // 2. Verify the code
109
+ const { error } = await signIn.resetPasswordEmailCode.verifyCode({ code: '123456' })
110
+
111
+ // 3. Submit new password
112
+ const { error } = await signIn.resetPasswordEmailCode.submitPassword({
113
+ password: 'newSecurePassword123',
114
+ })
115
+ ```
116
+
117
+ ## Client Trust
118
+
119
+ When a user signs in with a valid password from a new device without MFA enabled, the sign-in status becomes `needs_client_trust`. This requires an additional verification step:
120
+
121
+ ```typescript
122
+ if (signIn.status === 'needs_client_trust') {
123
+ // Check supportedSecondFactors for available methods (email_code or phone_code)
124
+ const factors = signIn.supportedSecondFactors
125
+ // Use the appropriate mfa method to verify
126
+ }
127
+ ```
128
+
129
+ ## Finalizing Sign-In
130
+
131
+ After successful authentication, call `finalize()` to activate the session:
132
+
133
+ ```typescript
134
+ await signIn.finalize({
135
+ navigate: async ({ session, decorateUrl }) => {
136
+ const destination = session.currentTask
137
+ ? `/sign-in/tasks/${session.currentTask.key}`
138
+ : '/'
139
+ const url = decorateUrl(destination)
140
+ // decorateUrl may return an absolute URL for Safari ITP
141
+ if (url.startsWith('http')) {
142
+ window.location.href = url
143
+ } else {
144
+ router.push(url)
145
+ }
146
+ },
147
+ })
148
+ ```
149
+
150
+ - `decorateUrl(path)` — decorates the URL with session info (required to support Safari's Intelligent Tracking Prevention). May return an absolute URL.
151
+ - `session.currentTask` — check for pending session tasks before redirecting
152
+
153
+ ### Reset State
154
+
155
+ Clear local sign-in state and start over:
156
+
157
+ ```typescript
158
+ signIn.reset()
159
+ ```
160
+
161
+ ## Error Handling
162
+
163
+ All methods return `Promise<{ error: ClerkError | null }>`. Errors are also available reactively on the hook:
164
+
165
+ ```typescript
166
+ const { signIn, errors } = useSignIn()
167
+
168
+ // Field-level errors
169
+ errors?.fields?.identifier // { code, message, longMessage? }
170
+ errors?.fields?.password // { code, message, longMessage? }
171
+ errors?.fields?.code // { code, message, longMessage? }
172
+
173
+ // Global errors (not tied to a field)
174
+ errors?.global // ClerkGlobalHookError[] | null
175
+
176
+ // Raw error array
177
+ errors?.raw // ClerkError[] | null
178
+ ```
179
+
180
+ ## Complete Example: Email/Password with MFA
181
+
182
+ From [the docs](https://clerk.com/docs/guides/development/custom-flows/authentication/multi-factor-authentication). Supports SMS verification codes, authenticator app (TOTP), and backup codes.
183
+
184
+ ```tsx
185
+ 'use client'
186
+
187
+ import { useSignIn } from '@clerk/nextjs'
188
+ import { useRouter } from 'next/navigation'
189
+
190
+ export default function Page() {
191
+ const { signIn, errors, fetchStatus } = useSignIn()
192
+ const router = useRouter()
193
+
194
+ const handleSubmit = async (formData: FormData) => {
195
+ const emailAddress = formData.get('email') as string
196
+ const password = formData.get('password') as string
197
+
198
+ await signIn.password({
199
+ emailAddress,
200
+ password,
201
+ })
202
+
203
+ // If you're using the authenticator app strategy, remove this check.
204
+ if (signIn.status === 'needs_second_factor') {
205
+ await signIn.mfa.sendPhoneCode()
206
+ }
207
+
208
+ if (signIn.status === 'complete') {
209
+ await signIn.finalize({
210
+ navigate: ({ session, decorateUrl }) => {
211
+ if (session?.currentTask) {
212
+ // Handle pending session tasks
213
+ // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
214
+ console.log(session?.currentTask)
215
+ return
216
+ }
217
+
218
+ const url = decorateUrl('/')
219
+ if (url.startsWith('http')) {
220
+ window.location.href = url
221
+ } else {
222
+ router.push(url)
223
+ }
224
+ },
225
+ })
226
+ }
227
+ }
228
+
229
+ const handleMFAVerification = async (formData: FormData) => {
230
+ const code = formData.get('code') as string
231
+ const useBackupCode = formData.get('useBackupCode') === 'on'
232
+
233
+ if (useBackupCode) {
234
+ await signIn.mfa.verifyBackupCode({ code })
235
+ } else {
236
+ await signIn.mfa.verifyPhoneCode({ code })
237
+ // If you're using the authenticator app strategy, use the following method instead:
238
+ // await signIn.mfa.verifyTOTP({ code })
239
+ }
240
+
241
+ if (signIn.status === 'complete') {
242
+ await signIn.finalize({
243
+ navigate: ({ session, decorateUrl }) => {
244
+ if (session?.currentTask) {
245
+ // Handle pending session tasks
246
+ // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
247
+ console.log(session?.currentTask)
248
+ return
249
+ }
250
+
251
+ const url = decorateUrl('/')
252
+ if (url.startsWith('http')) {
253
+ window.location.href = url
254
+ } else {
255
+ router.push(url)
256
+ }
257
+ },
258
+ })
259
+ }
260
+ }
261
+
262
+ if (signIn.status === 'needs_second_factor') {
263
+ return (
264
+ <div>
265
+ <h1>Verify your account</h1>
266
+ <form action={handleMFAVerification}>
267
+ <div>
268
+ <label htmlFor="code">Code</label>
269
+ <input id="code" name="code" type="text" />
270
+ {errors.fields.code && <p>{errors.fields.code.message}</p>}
271
+ </div>
272
+ <div>
273
+ <label>
274
+ Use backup code
275
+ <input type="checkbox" name="useBackupCode" />
276
+ </label>
277
+ </div>
278
+ <button type="submit" disabled={fetchStatus === 'fetching'}>
279
+ Verify
280
+ </button>
281
+ </form>
282
+ </div>
283
+ )
284
+ }
285
+
286
+ return (
287
+ <>
288
+ <h1>Sign in</h1>
289
+ <form action={handleSubmit}>
290
+ <div>
291
+ <label htmlFor="email">Enter email address</label>
292
+ <input id="email" name="email" type="email" />
293
+ {errors.fields.identifier && <p>{errors.fields.identifier.message}</p>}
294
+ </div>
295
+ <div>
296
+ <label htmlFor="password">Enter password</label>
297
+ <input id="password" name="password" type="password" />
298
+ {errors.fields.password && <p>{errors.fields.password.message}</p>}
299
+ </div>
300
+ <button type="submit" disabled={fetchStatus === 'fetching'}>
301
+ Continue
302
+ </button>
303
+ </form>
304
+ {errors && <p>{JSON.stringify(errors, null, 2)}</p>}
305
+ </>
306
+ )
307
+ }
308
+ ```
309
+
310
+ ## Docs
311
+
312
+ - [Custom sign-in flow](https://clerk.com/docs/custom-flows/overview)
313
+ - [MFA custom flow](https://clerk.com/docs/guides/development/custom-flows/authentication/multi-factor-authentication)
314
+ - [useSignIn() reference](https://clerk.com/docs/references/react/use-sign-in)