@passflow/react 0.0.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 (182) hide show
  1. package/README.md +844 -0
  2. package/dist/index.cjs.js +34 -0
  3. package/dist/index.cjs.js.map +1 -0
  4. package/dist/index.es.js +5098 -0
  5. package/dist/index.es.js.map +1 -0
  6. package/dist/playwright/fixture/index.d.ts +3 -0
  7. package/dist/playwright/fixture/index.d.ts.map +1 -0
  8. package/dist/playwright/playwright.config.d.ts +10 -0
  9. package/dist/playwright/playwright.config.d.ts.map +1 -0
  10. package/dist/playwright/tests/invitation-flow.spec.d.ts +2 -0
  11. package/dist/playwright/tests/invitation-flow.spec.d.ts.map +1 -0
  12. package/dist/playwright/tests/signin.spec.d.ts +2 -0
  13. package/dist/playwright/tests/signin.spec.d.ts.map +1 -0
  14. package/dist/playwright/tests/signup.spec.d.ts +2 -0
  15. package/dist/playwright/tests/signup.spec.d.ts.map +1 -0
  16. package/dist/playwright/tests/validate.spec.d.ts +2 -0
  17. package/dist/playwright/tests/validate.spec.d.ts.map +1 -0
  18. package/dist/src/app.d.ts +5 -0
  19. package/dist/src/app.d.ts.map +1 -0
  20. package/dist/src/components/error/index.d.ts +7 -0
  21. package/dist/src/components/error/index.d.ts.map +1 -0
  22. package/dist/src/components/flow/index.d.ts +2 -0
  23. package/dist/src/components/flow/index.d.ts.map +1 -0
  24. package/dist/src/components/flow/passflow/index.d.ts +12 -0
  25. package/dist/src/components/flow/passflow/index.d.ts.map +1 -0
  26. package/dist/src/components/form/forgot-password/forgot-password-success.d.ts +2 -0
  27. package/dist/src/components/form/forgot-password/forgot-password-success.d.ts.map +1 -0
  28. package/dist/src/components/form/forgot-password/forgot-password.d.ts +9 -0
  29. package/dist/src/components/form/forgot-password/forgot-password.d.ts.map +1 -0
  30. package/dist/src/components/form/forgot-password/index.d.ts +3 -0
  31. package/dist/src/components/form/forgot-password/index.d.ts.map +1 -0
  32. package/dist/src/components/form/index.d.ts +8 -0
  33. package/dist/src/components/form/index.d.ts.map +1 -0
  34. package/dist/src/components/form/invitation-join/index.d.ts +8 -0
  35. package/dist/src/components/form/invitation-join/index.d.ts.map +1 -0
  36. package/dist/src/components/form/reset-password/index.d.ts +8 -0
  37. package/dist/src/components/form/reset-password/index.d.ts.map +1 -0
  38. package/dist/src/components/form/signin/index.d.ts +14 -0
  39. package/dist/src/components/form/signin/index.d.ts.map +1 -0
  40. package/dist/src/components/form/signup/index.d.ts +13 -0
  41. package/dist/src/components/form/signup/index.d.ts.map +1 -0
  42. package/dist/src/components/form/verify-challenge/index.d.ts +3 -0
  43. package/dist/src/components/form/verify-challenge/index.d.ts.map +1 -0
  44. package/dist/src/components/form/verify-challenge/timer-button.d.ts +9 -0
  45. package/dist/src/components/form/verify-challenge/timer-button.d.ts.map +1 -0
  46. package/dist/src/components/form/verify-challenge/varify-challenge-otp-redirect.d.ts +9 -0
  47. package/dist/src/components/form/verify-challenge/varify-challenge-otp-redirect.d.ts.map +1 -0
  48. package/dist/src/components/form/verify-challenge/varify-challenge-success.d.ts +3 -0
  49. package/dist/src/components/form/verify-challenge/varify-challenge-success.d.ts.map +1 -0
  50. package/dist/src/components/form/verify-challenge/verify-challenge-magic-link.d.ts +2 -0
  51. package/dist/src/components/form/verify-challenge/verify-challenge-magic-link.d.ts.map +1 -0
  52. package/dist/src/components/form/verify-challenge/verify-challenge-otp-manual.d.ts +15 -0
  53. package/dist/src/components/form/verify-challenge/verify-challenge-otp-manual.d.ts.map +1 -0
  54. package/dist/src/components/form/verify-challenge/verify-challenge-otp.d.ts +11 -0
  55. package/dist/src/components/form/verify-challenge/verify-challenge-otp.d.ts.map +1 -0
  56. package/dist/src/components/form/wrapper/index.d.ts +13 -0
  57. package/dist/src/components/form/wrapper/index.d.ts.map +1 -0
  58. package/dist/src/components/passkey/index.d.ts +7 -0
  59. package/dist/src/components/passkey/index.d.ts.map +1 -0
  60. package/dist/src/components/passkey/passkey-actions.d.ts +13 -0
  61. package/dist/src/components/passkey/passkey-actions.d.ts.map +1 -0
  62. package/dist/src/components/passkey/passkey-dialog.d.ts +10 -0
  63. package/dist/src/components/passkey/passkey-dialog.d.ts.map +1 -0
  64. package/dist/src/components/passkey/passkey-list.d.ts +9 -0
  65. package/dist/src/components/passkey/passkey-list.d.ts.map +1 -0
  66. package/dist/src/components/provider/index.d.ts +2 -0
  67. package/dist/src/components/provider/index.d.ts.map +1 -0
  68. package/dist/src/components/provider/passflow-provider.d.ts +11 -0
  69. package/dist/src/components/provider/passflow-provider.d.ts.map +1 -0
  70. package/dist/src/components/ui/button/index.d.ts +19 -0
  71. package/dist/src/components/ui/button/index.d.ts.map +1 -0
  72. package/dist/src/components/ui/dialog/index.d.ts +20 -0
  73. package/dist/src/components/ui/dialog/index.d.ts.map +1 -0
  74. package/dist/src/components/ui/fields/field-password.d.ts +13 -0
  75. package/dist/src/components/ui/fields/field-password.d.ts.map +1 -0
  76. package/dist/src/components/ui/fields/field-phone.d.ts +11 -0
  77. package/dist/src/components/ui/fields/field-phone.d.ts.map +1 -0
  78. package/dist/src/components/ui/fields/field-text.d.ts +8 -0
  79. package/dist/src/components/ui/fields/field-text.d.ts.map +1 -0
  80. package/dist/src/components/ui/fields/index.d.ts +4 -0
  81. package/dist/src/components/ui/fields/index.d.ts.map +1 -0
  82. package/dist/src/components/ui/icon/index.d.ts +9 -0
  83. package/dist/src/components/ui/icon/index.d.ts.map +1 -0
  84. package/dist/src/components/ui/index.d.ts +9 -0
  85. package/dist/src/components/ui/index.d.ts.map +1 -0
  86. package/dist/src/components/ui/link/index.d.ts +11 -0
  87. package/dist/src/components/ui/link/index.d.ts.map +1 -0
  88. package/dist/src/components/ui/popover/index.d.ts +7 -0
  89. package/dist/src/components/ui/popover/index.d.ts.map +1 -0
  90. package/dist/src/components/ui/providers-box/index.d.ts +10 -0
  91. package/dist/src/components/ui/providers-box/index.d.ts.map +1 -0
  92. package/dist/src/components/ui/switch/index.d.ts +9 -0
  93. package/dist/src/components/ui/switch/index.d.ts.map +1 -0
  94. package/dist/src/constants/countries-phone-code.d.ts +253 -0
  95. package/dist/src/constants/countries-phone-code.d.ts.map +1 -0
  96. package/dist/src/constants/formats.d.ts +4 -0
  97. package/dist/src/constants/formats.d.ts.map +1 -0
  98. package/dist/src/constants/index.d.ts +3 -0
  99. package/dist/src/constants/index.d.ts.map +1 -0
  100. package/dist/src/context/auth-context.d.ts +14 -0
  101. package/dist/src/context/auth-context.d.ts.map +1 -0
  102. package/dist/src/context/index.d.ts +5 -0
  103. package/dist/src/context/index.d.ts.map +1 -0
  104. package/dist/src/context/navigation-context.d.ts +15 -0
  105. package/dist/src/context/navigation-context.d.ts.map +1 -0
  106. package/dist/src/context/passflow-context.d.ts +24 -0
  107. package/dist/src/context/passflow-context.d.ts.map +1 -0
  108. package/dist/src/context/router-context.d.ts +30 -0
  109. package/dist/src/context/router-context.d.ts.map +1 -0
  110. package/dist/src/hocs/index.d.ts +2 -0
  111. package/dist/src/hocs/index.d.ts.map +1 -0
  112. package/dist/src/hocs/with-error.d.ts +8 -0
  113. package/dist/src/hocs/with-error.d.ts.map +1 -0
  114. package/dist/src/hooks/index.d.ts +16 -0
  115. package/dist/src/hooks/index.d.ts.map +1 -0
  116. package/dist/src/hooks/use-app-settings.d.ts +16 -0
  117. package/dist/src/hooks/use-app-settings.d.ts.map +1 -0
  118. package/dist/src/hooks/use-auth-cloud-redirect.d.ts +4 -0
  119. package/dist/src/hooks/use-auth-cloud-redirect.d.ts.map +1 -0
  120. package/dist/src/hooks/use-auth.d.ts +3 -0
  121. package/dist/src/hooks/use-auth.d.ts.map +1 -0
  122. package/dist/src/hooks/use-forgot-password.d.ts +10 -0
  123. package/dist/src/hooks/use-forgot-password.d.ts.map +1 -0
  124. package/dist/src/hooks/use-join-invite.d.ts +8 -0
  125. package/dist/src/hooks/use-join-invite.d.ts.map +1 -0
  126. package/dist/src/hooks/use-logout.d.ts +8 -0
  127. package/dist/src/hooks/use-logout.d.ts.map +1 -0
  128. package/dist/src/hooks/use-navigation.d.ts +27 -0
  129. package/dist/src/hooks/use-navigation.d.ts.map +1 -0
  130. package/dist/src/hooks/use-outsideclick.d.ts +3 -0
  131. package/dist/src/hooks/use-outsideclick.d.ts.map +1 -0
  132. package/dist/src/hooks/use-passflow-store.d.ts +3 -0
  133. package/dist/src/hooks/use-passflow-store.d.ts.map +1 -0
  134. package/dist/src/hooks/use-passflow.d.ts +3 -0
  135. package/dist/src/hooks/use-passflow.d.ts.map +1 -0
  136. package/dist/src/hooks/use-passwordless-complete.d.ts +10 -0
  137. package/dist/src/hooks/use-passwordless-complete.d.ts.map +1 -0
  138. package/dist/src/hooks/use-provider.d.ts +7 -0
  139. package/dist/src/hooks/use-provider.d.ts.map +1 -0
  140. package/dist/src/hooks/use-reset-password.d.ts +9 -0
  141. package/dist/src/hooks/use-reset-password.d.ts.map +1 -0
  142. package/dist/src/hooks/use-signin.d.ts +10 -0
  143. package/dist/src/hooks/use-signin.d.ts.map +1 -0
  144. package/dist/src/hooks/use-signup.d.ts +10 -0
  145. package/dist/src/hooks/use-signup.d.ts.map +1 -0
  146. package/dist/src/hooks/use-user-passkeys.d.ts +12 -0
  147. package/dist/src/hooks/use-user-passkeys.d.ts.map +1 -0
  148. package/dist/src/index.d.ts +7 -0
  149. package/dist/src/index.d.ts.map +1 -0
  150. package/dist/src/main.d.ts +1 -0
  151. package/dist/src/main.d.ts.map +1 -0
  152. package/dist/src/types/index.d.ts +5 -0
  153. package/dist/src/types/index.d.ts.map +1 -0
  154. package/dist/src/utils/cn/index.d.ts +3 -0
  155. package/dist/src/utils/cn/index.d.ts.map +1 -0
  156. package/dist/src/utils/dayjs/format.d.ts +8 -0
  157. package/dist/src/utils/dayjs/format.d.ts.map +1 -0
  158. package/dist/src/utils/dayjs/index.d.ts +2 -0
  159. package/dist/src/utils/dayjs/index.d.ts.map +1 -0
  160. package/dist/src/utils/get-app-version/index.d.ts +7 -0
  161. package/dist/src/utils/get-app-version/index.d.ts.map +1 -0
  162. package/dist/src/utils/get-auth-methods/index.d.ts +30 -0
  163. package/dist/src/utils/get-auth-methods/index.d.ts.map +1 -0
  164. package/dist/src/utils/get-form-labels/index.d.ts +10 -0
  165. package/dist/src/utils/get-form-labels/index.d.ts.map +1 -0
  166. package/dist/src/utils/get-url-errors/index.d.ts +5 -0
  167. package/dist/src/utils/get-url-errors/index.d.ts.map +1 -0
  168. package/dist/src/utils/get-url-with-tokens/index.d.ts +3 -0
  169. package/dist/src/utils/get-url-with-tokens/index.d.ts.map +1 -0
  170. package/dist/src/utils/index.d.ts +11 -0
  171. package/dist/src/utils/index.d.ts.map +1 -0
  172. package/dist/src/utils/undefined-on-catch/index.d.ts +2 -0
  173. package/dist/src/utils/undefined-on-catch/index.d.ts.map +1 -0
  174. package/dist/src/utils/url-params/index.d.ts +14 -0
  175. package/dist/src/utils/url-params/index.d.ts.map +1 -0
  176. package/dist/src/utils/validate-url/index.d.ts +2 -0
  177. package/dist/src/utils/validate-url/index.d.ts.map +1 -0
  178. package/dist/src/utils/validation-schemas/index.d.ts +6 -0
  179. package/dist/src/utils/validation-schemas/index.d.ts.map +1 -0
  180. package/dist/style.css +1 -0
  181. package/dist/vite.svg +1 -0
  182. package/package.json +129 -0
package/README.md ADDED
@@ -0,0 +1,844 @@
1
+ # @passflow/passflow-react-sdk
2
+
3
+ This is a SDK for react application.
4
+
5
+ ## Table of Contents
6
+
7
+ - [@passflow/passflow-react-sdk](#passflowpassflow-react-sdk)
8
+ - [Table of Contents](#table-of-contents)
9
+ - [Local Development](#local-development)
10
+ - [Using Local Passflow JS SDK](#using-local-passflow-js-sdk)
11
+ - [Test writing Environment Setup](#test-writing-environment-setup)
12
+ - [UI Testing](#ui-testing)
13
+ - [Writing your own ui tests.](#writing-your-own-ui-tests)
14
+ - [Installation](#installation)
15
+ - [Requirements](#requirements)
16
+ - [Integration](#integration)
17
+ - [Passflow Cloud](#passflow-cloud)
18
+ - [PassflowFlow](#passflowflow)
19
+ - [React Router DOM](#react-router-dom)
20
+ - [Wouter](#wouter)
21
+ - [TanStack Router](#tanstack-router)
22
+ - [Props](#props)
23
+ - [PassflowProvider](#passflowprovider)
24
+ - [Form Components](#form-components)
25
+ - [SignIn](#signin)
26
+ - [SignUp](#signup)
27
+ - [ForgotPassword](#forgotpassword)
28
+ - [ForgotPasswordSuccess](#forgotpasswordsuccess)
29
+ - [ResetPassword](#resetpassword)
30
+ - [VerifyChallengeMagicLink](#verifychallengemagiclink)
31
+ - [VerifyChallengeOTP](#verifychallengeotp)
32
+ - [InvitationJoin](#invitationjoin)
33
+ - [Hooks](#hooks)
34
+ - [useAuth](#useauth)
35
+ - [usePassflow](#usepassflow)
36
+ - [usePassflowStore](#usepassflowstore)
37
+ - [useSignIn](#usesignin)
38
+ - [useSignUp](#usesignup)
39
+ - [useNavigation](#usenavigation)
40
+ - [useProvider](#useprovider)
41
+ - [useResetPassword](#useresetpassword)
42
+ - [useUserPasskeys](#useuserpasskeys)
43
+ - [useAppSettings](#useappsettings)
44
+ - [useAuthCloudRedirect](#useauthcloudredirect)
45
+ - [useForgotPassword](#useforgotpassword)
46
+ - [useJoinInvite](#usejoininvite)
47
+ - [useLogout](#uselogout)
48
+ - [usePasswordlessComplete](#usepasswordlesscomplete)
49
+
50
+ to install just type:
51
+
52
+ ```
53
+ pnpm install
54
+ pnpm build
55
+ ```
56
+
57
+ ## Local Development
58
+
59
+ ### Using Local Passflow JS SDK
60
+
61
+ For local development and testing with a local version of the Passflow JS SDK, you need to:
62
+
63
+ 1. Clone the Passflow JS SDK repository in a sibling directory to this project.
64
+ 2. remove current dependecy `pnpm remove @passflow/core`
65
+ 3. Link folder with:
66
+
67
+ ```sh
68
+ pnpm link ../passflow-js-sdk
69
+ pnpm install
70
+ ```
71
+
72
+ Now you can run watch mode in libraray mode and change it. It will compile every changes incrementally.
73
+
74
+ ```sh
75
+ pnpm watch
76
+ ```
77
+
78
+ After all done, we need to unlink and return all to the original state
79
+
80
+ ```sh
81
+ pnpm remove @passflow/core
82
+ pnpm unlink @passflow/core
83
+ pnpm install @passflow/core
84
+ ```
85
+
86
+ ## Test writing Environment Setup
87
+
88
+ For local development and UI testing, you need to set up the Passflow environment:
89
+
90
+ 1. Set the `PASSFLOW_URL` environment variable to point to your Passflow instance.
91
+ 1. Set the `PASSFLOW_APP_ID` environment variable
92
+ 1. Run `pnpm dev` anmd all should works
93
+
94
+ Refer `.env.example` for more details.
95
+
96
+
97
+ we are using pnpm. Please ansure you have it in the system.
98
+
99
+ ## UI Testing
100
+
101
+ We are using playwright to run UI tests.
102
+
103
+ First, ensure you have all runtime binary enabled:
104
+
105
+ ```
106
+ pnpm exec playwright install
107
+ ```
108
+
109
+ and then feel free to run the tests:
110
+
111
+ ```
112
+ pnpm run test:ui
113
+ ```
114
+
115
+ ### Writing your own ui tests.
116
+
117
+ You can find a tests in the `./tests` frolder.
118
+
119
+ Please create the new files using the current tests as a reference.
120
+
121
+ To run the playwright in the design mode with ui, run the follwoing command:
122
+
123
+ ```
124
+ pnpm playwright test --ui
125
+ ```
126
+
127
+ ## Installation
128
+
129
+ ```bash
130
+ pnpm add @passflow/passflow-react-sdk
131
+ ```
132
+
133
+ ## Requirements
134
+
135
+ - React 18+
136
+ - React Router DOM v6/v7 or Wouter or TanStack Router
137
+
138
+ ## Integration
139
+
140
+ ### Passflow Cloud
141
+
142
+ For a quick start with Passflow Cloud:
143
+
144
+ ```tsx
145
+ const passflowConfig: PassflowConfig = {
146
+ url: process.env.PASSFLOW_URL ?? 'http://localhost:5432',
147
+ appId: process.env.PASSFLOW_APP_ID ?? 'test_app_id',
148
+ createTenantForNewUser: true,
149
+ scopes: ['openid', 'email', 'profile', 'offline'],
150
+ };
151
+
152
+ export const PassflowProviderWrapper: FC<PropsWithChildren> = ({
153
+ children,
154
+ }) => {
155
+ const navigate = useNavigate(); // from react-router-dom
156
+
157
+ return (
158
+ <PassflowProvider
159
+ url={passflowConfig.url}
160
+ appId={passflowConfig.appId}
161
+ createTenantForNewUser={passflowConfig.createTenantForNewUser}
162
+ scopes={passflowConfig.scopes}
163
+ navigate={(options) =>
164
+ navigate(
165
+ {
166
+ pathname: options.to,
167
+ search: options.search,
168
+ },
169
+ { replace: options.replace }
170
+ )
171
+ }
172
+ router="react-router"
173
+ >
174
+ {children}
175
+ </PassflowProvider>
176
+ );
177
+ };
178
+
179
+ export const App = () => (
180
+ <BrowserRouter>
181
+ <PassflowProviderWrapper>
182
+ <PassflowFlow
183
+ federatedDisplayMode='redirect'
184
+ successAuthRedirect='https://jwt.io'
185
+ pathPrefix='/web'
186
+ />
187
+ </PassflowProviderWrapper>
188
+ </BrowserRouter>
189
+ );
190
+ ```
191
+ ### PassflowFlow
192
+
193
+ | Prop | Type | Description |
194
+ |------|------|-------------|
195
+ | successAuthRedirect | string | URL to redirect after successful authentication |
196
+ | federatedDisplayMode | "popup" \| "redirect" | Federated authentication display mode |
197
+ | pathPrefix | string | Prefix for all routes (optional) |
198
+
199
+ ### React Router DOM
200
+
201
+ Example of integration with React Router DOM:
202
+ PS: The example uses the Declarative approach.
203
+
204
+ ```tsx
205
+ import {
206
+ PassflowProvider,
207
+ SignIn,
208
+ SignUp,
209
+ ForgotPassword,
210
+ ForgotPasswordSuccess,
211
+ } from "@passflow/passflow-react-sdk";
212
+ import { BrowserRouter, Routes, Route, useNavigate } from "react-router-dom";
213
+
214
+ const passflowConfig = {
215
+ url: import.meta.env.VITE_PASSFLOW_URL,
216
+ appId: import.meta.env.VITE_PASSFLOW_APP_ID,
217
+ createTenantForNewUser: true,
218
+ scopes: ["id", "offline", "email", "profile", "openid", "management"],
219
+ };
220
+
221
+ const PassflowProviderWrapper = ({ children }) => {
222
+ const navigate = useNavigate();
223
+
224
+ return (
225
+ <PassflowProvider
226
+ url={passflowConfig.url}
227
+ appId={passflowConfig.appId}
228
+ createTenantForNewUser={passflowConfig.createTenantForNewUser}
229
+ scopes={passflowConfig.scopes}
230
+ navigate={(options) =>
231
+ navigate(
232
+ {
233
+ pathname: options.to,
234
+ search: options.search,
235
+ },
236
+ { replace: options.replace }
237
+ )
238
+ }
239
+ router="react-router"
240
+ >
241
+ {children}
242
+ </PassflowProvider>
243
+ );
244
+ };
245
+
246
+ export const App = () => (
247
+ <BrowserRouter>
248
+ <PassflowProviderWrapper>
249
+ <Routes>
250
+ <Route path="/" element={<Home />} />
251
+ <Route path="/signin" element={<SignIn successAuthRedirect="/" signUpPath="/signup" />} />
252
+ <Route path="/signup" element={<SignUp successAuthRedirect="/" signInPath="/signin" />} />
253
+ <Route
254
+ path="/forgot-password"
255
+ element={
256
+ <ForgotPassword
257
+ successResetRedirect="/"
258
+ signInPath="/signin"
259
+ forgotPasswordSuccessPath="/forgot-password/success"
260
+ />
261
+ }
262
+ />
263
+ <Route path="/forgot-password/success" element={<ForgotPasswordSuccess />} />
264
+ {/* Add other routes here */}
265
+ </Routes>
266
+ </PassflowProviderWrapper>
267
+ </BrowserRouter>
268
+ );
269
+ ```
270
+
271
+ ### Wouter
272
+
273
+ Example of integration with Wouter:
274
+
275
+ ```tsx
276
+ import {
277
+ PassflowProvider,
278
+ SignIn,
279
+ SignUp,
280
+ ForgotPassword,
281
+ ForgotPasswordSuccess,
282
+ } from "@passflow/passflow-react-sdk";
283
+ import { Switch, Route, useLocation } from "wouter";
284
+
285
+ const passflowConfig = {
286
+ url: import.meta.env.VITE_PASSFLOW_URL,
287
+ appId: import.meta.env.VITE_PASSFLOW_APP_ID,
288
+ createTenantForNewUser: true,
289
+ scopes: ["id", "offline", "email", "profile", "openid", "management"],
290
+ };
291
+
292
+ const PassflowProviderWrapper = ({ children }) => {
293
+ const [, navigate] = useLocation();
294
+
295
+ return (
296
+ <PassflowProvider
297
+ url={passflowConfig.url}
298
+ appId={passflowConfig.appId}
299
+ createTenantForNewUser={passflowConfig.createTenantForNewUser}
300
+ scopes={passflowConfig.scopes}
301
+ navigate={(options) => {
302
+ const searchParamWouter = options.search
303
+ ? options.search.startsWith("?")
304
+ ? options.search
305
+ : `?${options.search}`
306
+ : "";
307
+ navigate(`${options.to}${searchParamWouter}`, {
308
+ replace: options.replace,
309
+ });
310
+ }}
311
+ router="wouter"
312
+ >
313
+ {children}
314
+ </PassflowProvider>
315
+ );
316
+ };
317
+
318
+ export const App = () => (
319
+ <Switch>
320
+ <PassflowProviderWrapper>
321
+ <Route path="/" component={Home} />
322
+ <Route path="/signin" component={SignInWrapper} />
323
+ <Route path="/signup" component={SignUpWrapper} />
324
+ <Route path="/forgot-password" component={ForgotPasswordWrapper} />
325
+ <Route path="/forgot-password/success" component={ForgotPasswordSuccessWrapper} />
326
+ {/* Add other routes here */}
327
+ </PassflowProviderWrapper>
328
+ </Switch>
329
+ );
330
+ ```
331
+
332
+ ### TanStack Router
333
+
334
+ Example of integration with TanStack Router:
335
+ PS: The example uses Code-Based Routing.
336
+
337
+ ```tsx
338
+ // App.tsx
339
+ import { PassflowProviderWrapper, RouterProvider } from './providers';
340
+
341
+ export const App = () => (
342
+ <PassflowProviderWrapper>
343
+ <RouterProvider />
344
+ </PassflowProviderWrapper>
345
+ );
346
+
347
+ // PassflowProviderWrapper.tsx
348
+ import { PassflowProvider } from '@passflow/passflow-react-sdk';
349
+
350
+ const passflowConfig = {
351
+ url: import.meta.env.VITE_PASSFLOW_URL,
352
+ appId: import.meta.env.VITE_PASSFLOW_APP_ID,
353
+ createTenantForNewUser: true,
354
+ scopes: ['id', 'offline', 'email', 'profile', 'openid', 'management'],
355
+ };
356
+
357
+ export const PassflowProviderWrapper = ({ children }) => (
358
+ <PassflowProvider
359
+ url={passflowConfig.url}
360
+ appId={passflowConfig.appId}
361
+ createTenantForNewUser={passflowConfig.createTenantForNewUser}
362
+ scopes={passflowConfig.scopes}
363
+ router="tanstack-router"
364
+ >
365
+ {children}
366
+ </PassflowProvider>
367
+ );
368
+
369
+ // router/root.tsx
370
+ import { useNavigation } from '@passflow/passflow-react-sdk';
371
+ import { Outlet, useNavigate } from '@tanstack/react-router';
372
+
373
+ export const Root = () => {
374
+ const navigate = useNavigate();
375
+ const { setNavigate } = useNavigation();
376
+
377
+ useEffect(() => {
378
+ setNavigate((options) => navigate(options));
379
+ }, [navigate, setNavigate]);
380
+
381
+ return <Outlet />;
382
+ };
383
+
384
+ // router.tsx
385
+ import { QueryClient } from '@tanstack/react-query';
386
+ import { createRouter } from '@tanstack/react-router';
387
+ import { queryClient } from '../query';
388
+ import { routerTree } from './routes';
389
+ import { Passflow } from '@passflow/passflow-react-sdk';
390
+
391
+ export interface RouterContext {
392
+ queryClient: QueryClient;
393
+ passflow?: Passflow;
394
+ }
395
+
396
+ export const router = createRouter({
397
+ routeTree: routerTree,
398
+ context: {
399
+ queryClient,
400
+ passflow: undefined,
401
+ },
402
+ defaultPreload: 'intent',
403
+ });
404
+
405
+ declare module '@tanstack/react-router' {
406
+ interface Register {
407
+ router: typeof router;
408
+ }
409
+ }
410
+
411
+
412
+ // routes.tsx
413
+ import { Outlet, createRootRouteWithContext, createRoute, redirect } from '@tanstack/react-router';
414
+ import { RouterContext } from './router';
415
+ import { Root } from './root';
416
+ import { About, Home } from '@/pages';
417
+ import { ForgotPassword, ForgotPasswordSuccess, SignIn, SignUp } from '@passflow/passflow-react-sdk';
418
+ import { RootLayout } from '@/layouts';
419
+
420
+ const redirectToSignin = () => {
421
+ throw redirect({
422
+ to: '/signin',
423
+ });
424
+ };
425
+
426
+ const rootRoute = createRootRouteWithContext<RouterContext>()({
427
+ component: Root,
428
+ notFoundComponent: () => <div>404 Not Found</div>,
429
+ });
430
+
431
+ // PUBLIC ROUTES
432
+ const publicRoute = createRoute({
433
+ getParentRoute: () => rootRoute,
434
+ id: 'public',
435
+ component: () => <Outlet />,
436
+ });
437
+
438
+ const signInRoute = createRoute({
439
+ getParentRoute: () => publicRoute,
440
+ path: '/signin',
441
+ component: () => <SignIn successAuthRedirect='/' signUpPath='/signup' />,
442
+ });
443
+
444
+ const signUpRoute = createRoute({
445
+ getParentRoute: () => publicRoute,
446
+ path: '/signup',
447
+ component: () => <SignUp successAuthRedirect='/' signInPath='/signin' />,
448
+ });
449
+
450
+ const forgotPasswordRoute = createRoute({
451
+ getParentRoute: () => publicRoute,
452
+ path: '/forgot-password',
453
+ component: () => (
454
+ <ForgotPassword successResetRedirect='/' signInPath='/signin' forgotPasswordSuccessPath='/forgot-password/success' />
455
+ ),
456
+ });
457
+
458
+ const forgotPasswordSuccessRoute = createRoute({
459
+ getParentRoute: () => publicRoute,
460
+ path: '/forgot-password/success',
461
+ component: () => <ForgotPasswordSuccess />,
462
+ });
463
+
464
+ {/* Add other PASSFLOW COMPONENTS routes here */}
465
+
466
+ // PROTECTED ROUTES
467
+ const protectedRoute = createRoute({
468
+ getParentRoute: () => rootRoute,
469
+ id: 'protected',
470
+ beforeLoad: async ({ context }) => {
471
+ const { passflow } = context;
472
+
473
+ await passflow?.session({
474
+ createSession: async (tokens) => {
475
+ console.log(tokens); // if session is created, this function will be called with the tokens
476
+ },
477
+ expiredSession: async () => {
478
+ console.log('expiredSession');
479
+ redirectToSignin(); // if session is expired and refresh token is not valid, redirect to signin
480
+ },
481
+ doRefresh: true,
482
+ });
483
+ },
484
+ component: () => <RootLayout />,
485
+ });
486
+
487
+ const dashboardRoute = createRoute({
488
+ getParentRoute: () => protectedRoute,
489
+ path: '/',
490
+ component: () => <Home />,
491
+ });
492
+
493
+ const aboutRoute = createRoute({
494
+ getParentRoute: () => protectedRoute,
495
+ path: '/about',
496
+ component: () => <About />,
497
+ });
498
+
499
+ {/* Add other protected routes here */}
500
+
501
+ export const routerTree = rootRoute.addChildren([
502
+ publicRoute.addChildren([signInRoute, signUpRoute, forgotPasswordRoute, forgotPasswordSuccessRoute]),
503
+ protectedRoute.addChildren([dashboardRoute, aboutRoute]),
504
+ ]);
505
+ ```
506
+
507
+ ## Props
508
+
509
+ ### PassflowProvider
510
+
511
+ | Prop | Type | Description |
512
+ |------|------|-------------|
513
+ | url | string | Passflow server URL |
514
+ | appId | string | Application ID |
515
+ | createTenantForNewUser | boolean | Whether to create a tenant for new users |
516
+ | scopes | string[] | Array of required scopes |
517
+ | router | "default" \| "react-router" \| "wouter" \| "tanstack-router" | Router being used (optional) (default is native window navigation) |
518
+ | navigate | (options: NavigateOptions) => void | Navigation function (optional) (default is native window navigation) |
519
+
520
+ ## Form Components
521
+
522
+ ### SignIn
523
+
524
+ Component for user authentication.
525
+
526
+ | Prop | Type | Description | Default |
527
+ |------|------|-------------|---------|
528
+ | successAuthRedirect | string | URL to redirect after successful sign in | Required |
529
+ | signUpPath | string | Path to sign up page (optional) | /signup |
530
+ | forgotPasswordPath | string | Path to forgot password page (optional) | /forgot-password |
531
+ | verifyMagicLinkPath | string | Path to verify magic link page (optional) | /verify-challenge-magic-link |
532
+ | verifyOTPPath | string | Path to verify OTP page (optional) | /verify-challenge-otp |
533
+ | federatedDisplayMode | "popup" \| "redirect" | Display mode for federated authentication (optional) | "popup" |
534
+
535
+ ### SignUp
536
+
537
+ Component for user registration.
538
+
539
+ | Prop | Type | Description | Default |
540
+ |------|------|-------------|---------|
541
+ | successAuthRedirect | string | URL to redirect after successful sign up | Required |
542
+ | signInPath | string | Path to sign in page (optional) | /signin |
543
+ | verifyMagicLinkPath | string | Path to verify magic link page (optional) | /verify-challenge-magic-link |
544
+ | verifyOTPPath | string | Path to verify OTP page (optional) | /verify-challenge-otp |
545
+ | federatedDisplayMode | "popup" \| "redirect" | Display mode for federated authentication (optional) | "popup" |
546
+
547
+ ### ForgotPassword
548
+
549
+ Component for password recovery initiation.
550
+
551
+ | Prop | Type | Description | Default |
552
+ |------|------|-------------|---------|
553
+ | successResetRedirect | string | URL to redirect after successful password reset | Required |
554
+ | signInPath | string | Path to sign in page (optional) | /signin |
555
+ | forgotPasswordSuccessPath | string | Path to success page after initiating password reset (optional) | /forgot-password/success |
556
+
557
+ ### ForgotPasswordSuccess
558
+
559
+ Component for password recovery success.
560
+
561
+ No props required.
562
+
563
+ ### ResetPassword
564
+
565
+ Component for setting a new password.
566
+
567
+ | Prop | Type | Description | Default |
568
+ |------|------|-------------|---------|
569
+ | successAuthRedirect | string | URL to redirect after successful password reset | Required |
570
+
571
+ ### VerifyChallengeMagicLink
572
+
573
+ Component for verifying magic link authentication.
574
+
575
+ No props required.
576
+
577
+ ### VerifyChallengeOTP
578
+
579
+ Component for OTP verification.
580
+
581
+ | Prop | Type | Description | Default |
582
+ |------|------|-------------|---------|
583
+ | successAuthRedirect | string | URL to redirect after successful verification | Required |
584
+ | numInputs | number | Number of OTP input fields (optional) | 6 |
585
+ | shouldAutoFocus | boolean | Whether to autofocus the first input (optional) | true |
586
+ | signUpPath | string | Path to sign up page (optional) | /signup |
587
+
588
+ ### InvitationJoin
589
+
590
+ Component for accepting invitations and joining organizations.
591
+
592
+ | Prop | Type | Description | Default |
593
+ |------|------|-------------|---------|
594
+ | successAuthRedirect | string | URL to redirect after successful join | Required |
595
+ | signInPath | string | Path to sign in page (optional) | /signin |
596
+
597
+ ## Hooks
598
+
599
+ ### useAuth
600
+ Hook for authentication management. Provides methods for checking authentication status, obtaining tokens, and logging out.
601
+
602
+ ```typescript
603
+ const { isAuthenticated, getTokens, logout, isLoading } = useAuth();
604
+ ```
605
+
606
+ | Parameter | Type | Description |
607
+ |-----------|------|-------------|
608
+ | initialRefresh | `boolean` (optional) | Whether to refresh tokens on mount |
609
+
610
+ **Returns:**
611
+
612
+ | Property | Type | Description |
613
+ |----------|------|-------------|
614
+ | isAuthenticated | `() => boolean` | Current authentication status |
615
+ | getTokens | `(doRefresh: boolean) => Promise<{ tokens: Tokens \| undefined; parsedTokens: ParsedTokens \| undefined; }>` | Function to get authentication tokens |
616
+ | logout | `() => void` | Function to log out user |
617
+ | isLoading | `boolean` | Loading state indicator |
618
+
619
+ ### usePassflow
620
+ Hook for accessing the Passflow SDK instance. Must be used within PassflowProvider.
621
+
622
+ ```typescript
623
+ const passflow = usePassflow();
624
+ ```
625
+
626
+ **Returns:**
627
+
628
+ | Type | Description |
629
+ |------|-------------|
630
+ | `Passflow` | Passflow SDK instance |
631
+
632
+ ### usePassflowStore
633
+ Hook for synchronizing state with Passflow SDK. Allows subscribing to token changes.
634
+
635
+ ```typescript
636
+ const tokens = usePassflowStore([PassflowEvent.SignIn, ...]);
637
+ ```
638
+
639
+ | Parameter | Type | Description |
640
+ |-----------|------|-------------|
641
+ | events | `PassflowEvent[]` (optional) | Events to subscribe to |
642
+
643
+ **Returns:**
644
+
645
+ | Type | Description |
646
+ |------|-------------|
647
+ | `Tokens \| undefined` | Current tokens state |
648
+
649
+ ### useSignIn
650
+ Hook for implementing sign-in functionality. Supports password, passkey, and passwordless authentication.
651
+
652
+ ```typescript
653
+ const { fetch, isLoading, isError, error } = useSignIn();
654
+ ```
655
+
656
+ **Returns:**
657
+
658
+ | Property | Type | Description |
659
+ |----------|------|-------------|
660
+ | fetch | `(payload: PassflowPasskeyAuthenticateStartPayload \| PassflowSignInPayload \| PassflowPasswordlessSignInPayload, type: 'passkey' \| 'password' \| 'passwordless') => Promise<boolean \| string \| PassflowPasswordlessResponse>` | Sign in function |
661
+ | isLoading | `boolean` | Loading state |
662
+ | isError | `boolean` | Error state |
663
+ | error | `string` | Error message |
664
+
665
+ ### useSignUp
666
+ Hook for implementing registration functionality. Supports password, passkey, and passwordless registration.
667
+
668
+ ```typescript
669
+ const { fetch, isLoading, isError, error } = useSignUp();
670
+ ```
671
+
672
+ **Returns:**
673
+
674
+ | Property | Type | Description |
675
+ |----------|------|-------------|
676
+ | fetch | `(payload: PassflowPasskeyRegisterStartPayload \| PassflowSignUpPayload \| PassflowPasswordlessSignInPayload, type: 'passkey' \| 'password' \| 'passwordless') => Promise<boolean \| PassflowPasswordlessResponse>` | Sign up function |
677
+ | isLoading | `boolean` | Loading state |
678
+ | isError | `boolean` | Error state |
679
+ | error | `string` | Error message |
680
+
681
+ ### useNavigation
682
+ Hook for navigation between pages. Supports various routers (react-router, wouter, tanstack-router).
683
+
684
+ ```typescript
685
+ const { navigate, setNavigate } = useNavigation();
686
+ ```
687
+
688
+ **Returns:**
689
+
690
+ | Property | Type | Description |
691
+ |----------|------|-------------|
692
+ | navigate | `NavigateFunction` | Navigation function |
693
+ | setNavigate | `(newNavigate: NavigateFunction \| null) => void` | Function to update navigation handler |
694
+
695
+ ### useProvider
696
+ Hook for working with federated authentication providers (OAuth).
697
+
698
+ ```typescript
699
+ const { federatedWithPopup, federatedWithRedirect } = useProvider(redirectUrl);
700
+ ```
701
+
702
+ | Parameter | Type | Description |
703
+ |-----------|------|-------------|
704
+ | redirectUrl | `string` | URL to redirect after authentication |
705
+
706
+ **Returns:**
707
+
708
+ | Property | Type | Description |
709
+ |----------|------|-------------|
710
+ | federatedWithPopup | `(provider: Providers) => void` | Popup authentication function |
711
+ | federatedWithRedirect | `(provider: Providers) => void` | Redirect authentication function |
712
+
713
+ ### useResetPassword
714
+ Hook for resetting user password.
715
+
716
+ ```typescript
717
+ const { fetch, isLoading, isError, error } = useResetPassword();
718
+ ```
719
+
720
+ **Returns:**
721
+
722
+ | Property | Type | Description |
723
+ |----------|------|-------------|
724
+ | fetch | `(newPassword: string) => Promise<boolean>` | Password reset function |
725
+ | isLoading | `boolean` | Loading state |
726
+ | isError | `boolean` | Error state |
727
+ | error | `string` | Error message |
728
+
729
+ ### useUserPasskeys
730
+ Hook for managing user passkeys (create, edit, delete).
731
+
732
+ ```typescript
733
+ const { data, createUserPasskey, editUserPasskey, deleteUserPasskey } = useUserPasskeys();
734
+ ```
735
+
736
+ **Returns:**
737
+
738
+ | Property | Type | Description |
739
+ |----------|------|-------------|
740
+ | data | `PassflowUserPasskey[]` | List of user passkeys |
741
+ | createUserPasskey | `(relyingPartyId: string) => Promise<void>` | Create passkey function |
742
+ | editUserPasskey | `(newName: string, passkeyId: string) => Promise<void>` | Edit passkey function |
743
+ | deleteUserPasskey | `(passkeyId: string) => Promise<void>` | Delete passkey function |
744
+ | isLoading | `boolean` | Loading state |
745
+ | isError | `boolean` | Error state |
746
+ | errorMessage | `string` | Error message |
747
+
748
+ ### useAppSettings
749
+ Hook for retrieving application settings and password policies.
750
+
751
+ ```typescript
752
+ const { appSettings, passwordPolicy } = useAppSettings();
753
+ ```
754
+
755
+ **Returns:**
756
+
757
+ | Property | Type | Description |
758
+ |----------|------|-------------|
759
+ | appSettings | `AppSettings \| null` | Application settings |
760
+ | passwordPolicy | `PassflowPasswordPolicySettings \| null` | Password policy settings |
761
+ | isLoading | `boolean` | Loading state |
762
+ | isError | `boolean` | Error state |
763
+ | error | `string` | Error message |
764
+
765
+ ### useAuthCloudRedirect
766
+ Hook for redirecting to Passflow Cloud.
767
+
768
+ ```typescript
769
+ const redirect = useAuthCloudRedirect(cloudPassflowUrl);
770
+ ```
771
+
772
+ | Parameter | Type | Description |
773
+ |-----------|------|-------------|
774
+ | cloudPassflowUrl | `string` | Passflow Cloud URL |
775
+
776
+ **Returns:**
777
+
778
+ | Type | Description |
779
+ |------|-------------|
780
+ | `() => void` | Redirect function |
781
+
782
+ ### useForgotPassword
783
+ Hook for initiating the password recovery process.
784
+
785
+ ```typescript
786
+ const { fetch, isLoading, isError, error } = useForgotPassword();
787
+ ```
788
+
789
+ **Returns:**
790
+
791
+ | Property | Type | Description |
792
+ |----------|------|-------------|
793
+ | fetch | `(payload: PassflowSendPasswordResetEmailPayload) => Promise<boolean>` | Password recovery function |
794
+ | isLoading | `boolean` | Loading state |
795
+ | isError | `boolean` | Error state |
796
+ | error | `string` | Error message |
797
+
798
+ ### useJoinInvite
799
+ Hook for accepting organization invitations.
800
+
801
+ ```typescript
802
+ const { fetch, isLoading, isError, error } = useJoinInvite();
803
+ ```
804
+
805
+ **Returns:**
806
+
807
+ | Property | Type | Description |
808
+ |----------|------|-------------|
809
+ | fetch | `(token: string) => Promise<boolean>` | Join invitation function |
810
+ | isLoading | `boolean` | Loading state |
811
+ | isError | `boolean` | Error state |
812
+ | error | `string` | Error message |
813
+
814
+ ### useLogout
815
+ Hook for logging out of the system.
816
+
817
+ ```typescript
818
+ const { fetch, isLoading, isError, error } = useLogout();
819
+ ```
820
+
821
+ **Returns:**
822
+
823
+ | Property | Type | Description |
824
+ |----------|------|-------------|
825
+ | fetch | `() => Promise<boolean>` | Logout function |
826
+ | isLoading | `boolean` | Loading state |
827
+ | isError | `boolean` | Error state |
828
+ | error | `string` | Error message |
829
+
830
+ ### usePasswordlessComplete
831
+ Hook for completing passwordless authentication.
832
+
833
+ ```typescript
834
+ const { fetch, isLoading, isError, error } = usePasswordlessComplete();
835
+ ```
836
+
837
+ **Returns:**
838
+
839
+ | Property | Type | Description |
840
+ |----------|------|-------------|
841
+ | fetch | `(payload: PassflowPasswordlessSignInCompletePayload) => Promise<PassflowValidationResponse \| null>` | Complete passwordless auth function |
842
+ | isLoading | `boolean` | Loading state |
843
+ | isError | `boolean` | Error state |
844
+ | error | `string` | Error message |