hazo_auth 6.0.0 → 7.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 (256) hide show
  1. package/README.md +233 -8
  2. package/SETUP_CHECKLIST.md +240 -0
  3. package/cli-src/cli/validate.ts +4 -0
  4. package/cli-src/lib/auth/nextauth_config.ts +101 -1
  5. package/cli-src/lib/cookies_config.server.ts +1 -0
  6. package/cli-src/lib/email_verification_config.server.ts +0 -34
  7. package/cli-src/lib/forgot_password_config.server.ts +0 -34
  8. package/cli-src/lib/login_config.server.ts +14 -31
  9. package/cli-src/lib/my_settings_config.server.ts +0 -3
  10. package/cli-src/lib/oauth_config.server.ts +58 -0
  11. package/cli-src/lib/otp_config.server.ts +91 -0
  12. package/cli-src/lib/register_config.server.ts +11 -31
  13. package/cli-src/lib/reset_password_config.server.ts +0 -31
  14. package/cli-src/lib/services/email_service.ts +3 -1
  15. package/cli-src/lib/services/email_template_manifest.ts +17 -0
  16. package/cli-src/lib/services/email_templates/otp_signin_code.html +13 -0
  17. package/cli-src/lib/services/email_templates/otp_signin_code.txt +5 -0
  18. package/cli-src/lib/services/index.ts +8 -2
  19. package/cli-src/lib/services/oauth_service.ts +197 -0
  20. package/cli-src/lib/services/otp_service.ts +295 -0
  21. package/cli-src/lib/services/session_token_service.ts +4 -1
  22. package/config/hazo_auth_config.example.ini +76 -41
  23. package/dist/cli/validate.d.ts.map +1 -1
  24. package/dist/cli/validate.js +4 -0
  25. package/dist/client.d.ts +2 -0
  26. package/dist/client.d.ts.map +1 -1
  27. package/dist/client.js +1 -0
  28. package/dist/components/layouts/create_firm/index.d.ts +4 -8
  29. package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
  30. package/dist/components/layouts/create_firm/index.js +3 -3
  31. package/dist/components/layouts/email_verification/index.d.ts +4 -5
  32. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  33. package/dist/components/layouts/email_verification/index.js +4 -4
  34. package/dist/components/layouts/forgot_password/index.d.ts +4 -5
  35. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  36. package/dist/components/layouts/forgot_password/index.js +2 -2
  37. package/dist/components/layouts/login/index.d.ts +19 -9
  38. package/dist/components/layouts/login/index.d.ts.map +1 -1
  39. package/dist/components/layouts/login/index.js +12 -6
  40. package/dist/components/layouts/otp/index.d.ts +17 -0
  41. package/dist/components/layouts/otp/index.d.ts.map +1 -0
  42. package/dist/components/layouts/otp/index.js +16 -0
  43. package/dist/components/layouts/register/index.d.ts +11 -7
  44. package/dist/components/layouts/register/index.d.ts.map +1 -1
  45. package/dist/components/layouts/register/index.js +8 -4
  46. package/dist/components/layouts/reset_password/index.d.ts +4 -5
  47. package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
  48. package/dist/components/layouts/reset_password/index.js +5 -5
  49. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +3 -5
  50. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
  51. package/dist/components/layouts/shared/components/already_logged_in_guard.js +2 -2
  52. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +25 -0
  53. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -0
  54. package/dist/components/layouts/shared/components/facebook_sign_in_button.js +49 -0
  55. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  56. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +8 -3
  57. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +3 -6
  58. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
  59. package/dist/components/layouts/shared/components/two_column_auth_layout.js +8 -5
  60. package/dist/components/otp/OTPRequestForm.d.ts +11 -0
  61. package/dist/components/otp/OTPRequestForm.d.ts.map +1 -0
  62. package/dist/components/otp/OTPRequestForm.js +42 -0
  63. package/dist/components/otp/OTPVerifyForm.d.ts +16 -0
  64. package/dist/components/otp/OTPVerifyForm.d.ts.map +1 -0
  65. package/dist/components/otp/OTPVerifyForm.js +75 -0
  66. package/dist/components/otp/index.d.ts +5 -0
  67. package/dist/components/otp/index.d.ts.map +1 -0
  68. package/dist/components/otp/index.js +2 -0
  69. package/dist/components/ui/input-otp.d.ts +35 -0
  70. package/dist/components/ui/input-otp.d.ts.map +1 -0
  71. package/dist/components/ui/input-otp.js +44 -0
  72. package/dist/consent/consent_state.d.ts +18 -0
  73. package/dist/consent/consent_state.d.ts.map +1 -0
  74. package/dist/consent/consent_state.js +29 -0
  75. package/dist/consent/cookie_consent_banner.d.ts +11 -0
  76. package/dist/consent/cookie_consent_banner.d.ts.map +1 -0
  77. package/dist/consent/cookie_consent_banner.js +40 -0
  78. package/dist/consent/gtm_mapping.d.ts +13 -0
  79. package/dist/consent/gtm_mapping.d.ts.map +1 -0
  80. package/dist/consent/gtm_mapping.js +30 -0
  81. package/dist/consent/index.d.ts +7 -0
  82. package/dist/consent/index.d.ts.map +1 -0
  83. package/dist/consent/index.js +7 -0
  84. package/dist/consent/manage_modal.d.ts +2 -0
  85. package/dist/consent/manage_modal.d.ts.map +1 -0
  86. package/dist/consent/manage_modal.js +33 -0
  87. package/dist/consent/read_consent.d.ts +15 -0
  88. package/dist/consent/read_consent.d.ts.map +1 -0
  89. package/dist/consent/read_consent.js +23 -0
  90. package/dist/consent/use_consent.d.ts +7 -0
  91. package/dist/consent/use_consent.d.ts.map +1 -0
  92. package/dist/consent/use_consent.js +55 -0
  93. package/dist/lib/auth/nextauth_config.d.ts +10 -0
  94. package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
  95. package/dist/lib/auth/nextauth_config.js +80 -2
  96. package/dist/lib/cookies_config.server.d.ts +1 -0
  97. package/dist/lib/cookies_config.server.d.ts.map +1 -1
  98. package/dist/lib/cookies_config.server.js +1 -0
  99. package/dist/lib/email_verification_config.server.d.ts +0 -3
  100. package/dist/lib/email_verification_config.server.d.ts.map +1 -1
  101. package/dist/lib/email_verification_config.server.js +0 -15
  102. package/dist/lib/forgot_password_config.server.d.ts +0 -3
  103. package/dist/lib/forgot_password_config.server.d.ts.map +1 -1
  104. package/dist/lib/forgot_password_config.server.js +0 -15
  105. package/dist/lib/login_config.server.d.ts +6 -3
  106. package/dist/lib/login_config.server.d.ts.map +1 -1
  107. package/dist/lib/login_config.server.js +7 -13
  108. package/dist/lib/my_settings_config.server.d.ts +0 -1
  109. package/dist/lib/my_settings_config.server.d.ts.map +1 -1
  110. package/dist/lib/my_settings_config.server.js +0 -2
  111. package/dist/lib/oauth_config.server.d.ts +17 -0
  112. package/dist/lib/oauth_config.server.d.ts.map +1 -1
  113. package/dist/lib/oauth_config.server.js +25 -0
  114. package/dist/lib/otp_config.server.d.ts +49 -0
  115. package/dist/lib/otp_config.server.d.ts.map +1 -0
  116. package/dist/lib/otp_config.server.js +48 -0
  117. package/dist/lib/register_config.server.d.ts +2 -3
  118. package/dist/lib/register_config.server.d.ts.map +1 -1
  119. package/dist/lib/register_config.server.js +4 -13
  120. package/dist/lib/reset_password_config.server.d.ts +0 -3
  121. package/dist/lib/reset_password_config.server.d.ts.map +1 -1
  122. package/dist/lib/reset_password_config.server.js +0 -13
  123. package/dist/lib/services/email_service.d.ts +1 -1
  124. package/dist/lib/services/email_service.d.ts.map +1 -1
  125. package/dist/lib/services/email_service.js +2 -0
  126. package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
  127. package/dist/lib/services/email_template_manifest.js +17 -0
  128. package/dist/lib/services/email_templates/otp_signin_code.html +13 -0
  129. package/dist/lib/services/email_templates/otp_signin_code.txt +5 -0
  130. package/dist/lib/services/index.d.ts +2 -0
  131. package/dist/lib/services/index.d.ts.map +1 -1
  132. package/dist/lib/services/index.js +1 -0
  133. package/dist/lib/services/oauth_service.d.ts +24 -0
  134. package/dist/lib/services/oauth_service.d.ts.map +1 -1
  135. package/dist/lib/services/oauth_service.js +155 -0
  136. package/dist/lib/services/otp_service.d.ts +46 -0
  137. package/dist/lib/services/otp_service.d.ts.map +1 -0
  138. package/dist/lib/services/otp_service.js +238 -0
  139. package/dist/lib/services/session_token_service.d.ts +3 -1
  140. package/dist/lib/services/session_token_service.d.ts.map +1 -1
  141. package/dist/lib/services/session_token_service.js +4 -2
  142. package/dist/page_components/create_firm.d.ts +13 -1
  143. package/dist/page_components/create_firm.d.ts.map +1 -1
  144. package/dist/page_components/create_firm.js +10 -6
  145. package/dist/page_components/forgot_password.d.ts +1 -4
  146. package/dist/page_components/forgot_password.d.ts.map +1 -1
  147. package/dist/page_components/forgot_password.js +2 -6
  148. package/dist/page_components/login.d.ts +1 -4
  149. package/dist/page_components/login.d.ts.map +1 -1
  150. package/dist/page_components/login.js +2 -6
  151. package/dist/page_components/otp.d.ts +4 -0
  152. package/dist/page_components/otp.d.ts.map +1 -0
  153. package/dist/page_components/otp.js +5 -0
  154. package/dist/page_components/register.d.ts +1 -4
  155. package/dist/page_components/register.d.ts.map +1 -1
  156. package/dist/page_components/register.js +2 -6
  157. package/dist/page_components/reset_password.d.ts +1 -4
  158. package/dist/page_components/reset_password.d.ts.map +1 -1
  159. package/dist/page_components/reset_password.js +2 -6
  160. package/dist/page_components/verify_email.d.ts +1 -4
  161. package/dist/page_components/verify_email.d.ts.map +1 -1
  162. package/dist/page_components/verify_email.js +2 -6
  163. package/dist/server/routes/index.d.ts +3 -0
  164. package/dist/server/routes/index.d.ts.map +1 -1
  165. package/dist/server/routes/index.js +4 -0
  166. package/dist/server/routes/me.d.ts.map +1 -1
  167. package/dist/server/routes/me.js +43 -1
  168. package/dist/server/routes/oauth_facebook_callback.d.ts +8 -0
  169. package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -0
  170. package/dist/server/routes/oauth_facebook_callback.js +157 -0
  171. package/dist/server/routes/oauth_google_callback.js +1 -1
  172. package/dist/server/routes/otp/request.d.ts +3 -0
  173. package/dist/server/routes/otp/request.d.ts.map +1 -0
  174. package/dist/server/routes/otp/request.js +33 -0
  175. package/dist/server/routes/otp/verify.d.ts +3 -0
  176. package/dist/server/routes/otp/verify.d.ts.map +1 -0
  177. package/dist/server/routes/otp/verify.js +58 -0
  178. package/dist/server-lib.d.ts +3 -0
  179. package/dist/server-lib.d.ts.map +1 -1
  180. package/dist/server-lib.js +2 -0
  181. package/dist/server_pages/forgot_password.d.ts +13 -17
  182. package/dist/server_pages/forgot_password.d.ts.map +1 -1
  183. package/dist/server_pages/forgot_password.js +12 -8
  184. package/dist/server_pages/forgot_password_client_wrapper.d.ts +7 -6
  185. package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
  186. package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
  187. package/dist/server_pages/login.d.ts +22 -21
  188. package/dist/server_pages/login.d.ts.map +1 -1
  189. package/dist/server_pages/login.js +15 -19
  190. package/dist/server_pages/login_client_wrapper.d.ts +10 -6
  191. package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
  192. package/dist/server_pages/login_client_wrapper.js +2 -2
  193. package/dist/server_pages/my_settings.d.ts +2 -0
  194. package/dist/server_pages/my_settings.d.ts.map +1 -1
  195. package/dist/server_pages/my_settings.js +8 -2
  196. package/dist/server_pages/otp.d.ts +56 -0
  197. package/dist/server_pages/otp.d.ts.map +1 -0
  198. package/dist/server_pages/otp.js +45 -0
  199. package/dist/server_pages/register.d.ts +19 -16
  200. package/dist/server_pages/register.d.ts.map +1 -1
  201. package/dist/server_pages/register.js +15 -12
  202. package/dist/server_pages/register_client_wrapper.d.ts +10 -6
  203. package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
  204. package/dist/server_pages/register_client_wrapper.js +2 -2
  205. package/dist/server_pages/reset_password.d.ts +11 -16
  206. package/dist/server_pages/reset_password.d.ts.map +1 -1
  207. package/dist/server_pages/reset_password.js +11 -9
  208. package/dist/server_pages/reset_password_client_wrapper.d.ts +7 -6
  209. package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
  210. package/dist/server_pages/reset_password_client_wrapper.js +2 -2
  211. package/dist/server_pages/verify_email.d.ts +11 -17
  212. package/dist/server_pages/verify_email.d.ts.map +1 -1
  213. package/dist/server_pages/verify_email.js +11 -8
  214. package/dist/server_pages/verify_email_client_wrapper.d.ts +7 -6
  215. package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
  216. package/dist/server_pages/verify_email_client_wrapper.js +2 -2
  217. package/dist/strings/default_strings.d.ts +47 -0
  218. package/dist/strings/default_strings.d.ts.map +1 -0
  219. package/dist/strings/default_strings.js +18 -0
  220. package/dist/strings/index.d.ts +4 -0
  221. package/dist/strings/index.d.ts.map +1 -0
  222. package/dist/strings/index.js +3 -0
  223. package/dist/strings/strings_context.d.ts +12 -0
  224. package/dist/strings/strings_context.d.ts.map +1 -0
  225. package/dist/strings/strings_context.js +23 -0
  226. package/dist/strings/strings_provider.d.ts +26 -0
  227. package/dist/strings/strings_provider.d.ts.map +1 -0
  228. package/dist/strings/strings_provider.js +45 -0
  229. package/dist/theme/create_theme.d.ts +7 -0
  230. package/dist/theme/create_theme.d.ts.map +1 -0
  231. package/dist/theme/create_theme.js +97 -0
  232. package/dist/theme/hex_to_hsl.d.ts +16 -0
  233. package/dist/theme/hex_to_hsl.d.ts.map +1 -0
  234. package/dist/theme/hex_to_hsl.js +110 -0
  235. package/dist/theme/index.d.ts +4 -0
  236. package/dist/theme/index.d.ts.map +1 -0
  237. package/dist/theme/index.js +3 -0
  238. package/dist/theme/luminance.d.ts +11 -0
  239. package/dist/theme/luminance.d.ts.map +1 -0
  240. package/dist/theme/luminance.js +45 -0
  241. package/dist/theme/theme_provider.d.ts +14 -0
  242. package/dist/theme/theme_provider.d.ts.map +1 -0
  243. package/dist/theme/theme_provider.js +23 -0
  244. package/dist/theme/theme_types.d.ts +36 -0
  245. package/dist/theme/theme_types.d.ts.map +1 -0
  246. package/dist/theme/theme_types.js +1 -0
  247. package/dist/themes/index.d.ts +3 -0
  248. package/dist/themes/index.d.ts.map +1 -0
  249. package/dist/themes/index.js +2 -0
  250. package/dist/themes/preset_indigo_sunset.d.ts +3 -0
  251. package/dist/themes/preset_indigo_sunset.d.ts.map +1 -0
  252. package/dist/themes/preset_indigo_sunset.js +20 -0
  253. package/dist/themes/preset_neutral.d.ts +3 -0
  254. package/dist/themes/preset_neutral.d.ts.map +1 -0
  255. package/dist/themes/preset_neutral.js +14 -0
  256. package/package.json +36 -2
@@ -4,12 +4,6 @@ import "server-only";
4
4
 
5
5
  // section: imports
6
6
  import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
7
- import { get_config_value } from "./config/config_loader.server.js";
8
-
9
- // Default image path - consuming apps should either:
10
- // 1. Configure their own image_src in hazo_auth_config.ini
11
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
12
- const DEFAULT_VERIFY_EMAIL_IMAGE_PATH = "/hazo_auth/images/verify_email_default.jpg";
13
7
 
14
8
  // section: types
15
9
  export type EmailVerificationConfig = {
@@ -18,9 +12,6 @@ export type EmailVerificationConfig = {
18
12
  showReturnHomeButton: boolean;
19
13
  returnHomeButtonLabel: string;
20
14
  returnHomePath: string;
21
- imageSrc: string;
22
- imageAlt: string;
23
- imageBackgroundColor: string;
24
15
  };
25
16
 
26
17
  // section: helpers
@@ -30,40 +21,15 @@ export type EmailVerificationConfig = {
30
21
  * @returns Email verification configuration options
31
22
  */
32
23
  export function get_email_verification_config(): EmailVerificationConfig {
33
- const section = "hazo_auth__email_verification_layout";
34
-
35
24
  // Get shared already logged in config
36
25
  const alreadyLoggedInConfig = get_already_logged_in_config();
37
26
 
38
- // Read image configuration
39
- // If not set in config, falls back to default path-based image
40
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
41
- const imageSrc = get_config_value(
42
- section,
43
- "image_src",
44
- DEFAULT_VERIFY_EMAIL_IMAGE_PATH
45
- );
46
-
47
- const imageAlt = get_config_value(
48
- section,
49
- "image_alt",
50
- "Email verification illustration"
51
- );
52
- const imageBackgroundColor = get_config_value(
53
- section,
54
- "image_background_color",
55
- "#f1f5f9"
56
- );
57
-
58
27
  return {
59
28
  alreadyLoggedInMessage: alreadyLoggedInConfig.message,
60
29
  showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
61
30
  showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
62
31
  returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
63
32
  returnHomePath: alreadyLoggedInConfig.returnHomePath,
64
- imageSrc,
65
- imageAlt,
66
- imageBackgroundColor,
67
33
  };
68
34
  }
69
35
 
@@ -4,12 +4,6 @@ import "server-only";
4
4
 
5
5
  // section: imports
6
6
  import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
7
- import { get_config_value } from "./config/config_loader.server.js";
8
-
9
- // Default image path - consuming apps should either:
10
- // 1. Configure their own image_src in hazo_auth_config.ini
11
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
12
- const DEFAULT_FORGOT_PASSWORD_IMAGE_PATH = "/hazo_auth/images/forgot_password_default.jpg";
13
7
 
14
8
  // section: types
15
9
  export type ForgotPasswordConfig = {
@@ -18,9 +12,6 @@ export type ForgotPasswordConfig = {
18
12
  showReturnHomeButton: boolean;
19
13
  returnHomeButtonLabel: string;
20
14
  returnHomePath: string;
21
- imageSrc: string;
22
- imageAlt: string;
23
- imageBackgroundColor: string;
24
15
  };
25
16
 
26
17
  // section: helpers
@@ -30,40 +21,15 @@ export type ForgotPasswordConfig = {
30
21
  * @returns Forgot password configuration options
31
22
  */
32
23
  export function get_forgot_password_config(): ForgotPasswordConfig {
33
- const section = "hazo_auth__forgot_password_layout";
34
-
35
24
  // Get shared already logged in config
36
25
  const alreadyLoggedInConfig = get_already_logged_in_config();
37
26
 
38
- // Read image configuration
39
- // If not set in config, falls back to default path-based image
40
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
41
- const imageSrc = get_config_value(
42
- section,
43
- "image_src",
44
- DEFAULT_FORGOT_PASSWORD_IMAGE_PATH
45
- );
46
-
47
- const imageAlt = get_config_value(
48
- section,
49
- "image_alt",
50
- "Password recovery illustration"
51
- );
52
- const imageBackgroundColor = get_config_value(
53
- section,
54
- "image_background_color",
55
- "#f1f5f9"
56
- );
57
-
58
27
  return {
59
28
  alreadyLoggedInMessage: alreadyLoggedInConfig.message,
60
29
  showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
61
30
  showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
62
31
  returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
63
32
  returnHomePath: alreadyLoggedInConfig.returnHomePath,
64
- imageSrc,
65
- imageAlt,
66
- imageBackgroundColor,
67
33
  };
68
34
  }
69
35
 
@@ -7,11 +7,6 @@ import { get_config_value, get_config_value_allow_empty } from "./config/config_
7
7
  import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
8
8
  import { get_oauth_config, type OAuthConfig } from "./oauth_config.server.js";
9
9
 
10
- // Default image path - consuming apps should either:
11
- // 1. Configure their own image_src in hazo_auth_config.ini
12
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
13
- const DEFAULT_LOGIN_IMAGE_PATH = "/hazo_auth/images/login_default.jpg";
14
-
15
10
  // section: types
16
11
  export type LoginConfig = {
17
12
  redirectRoute?: string;
@@ -26,11 +21,14 @@ export type LoginConfig = {
26
21
  createAccountPath: string;
27
22
  createAccountLabel: string;
28
23
  showCreateAccountLink: boolean;
29
- imageSrc: string;
30
- imageAlt: string;
31
- imageBackgroundColor: string;
32
24
  /** OAuth configuration */
33
25
  oauth: OAuthConfig;
26
+ /** Whether the OTP sign-in link is shown below the login form */
27
+ otpSigninEnabled: boolean;
28
+ /** Label for the OTP sign-in link */
29
+ otpSigninLabel: string;
30
+ /** href for the OTP sign-in link */
31
+ otpSigninHref: string;
34
32
  };
35
33
 
36
34
  // section: helpers
@@ -71,29 +69,14 @@ export function get_login_config(): LoginConfig {
71
69
  // Get shared already logged in config
72
70
  const alreadyLoggedInConfig = get_already_logged_in_config();
73
71
 
74
- // Read image configuration
75
- // If not set in config, falls back to default path-based image
76
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
77
- const imageSrc = get_config_value(
78
- section,
79
- "image_src",
80
- DEFAULT_LOGIN_IMAGE_PATH
81
- );
82
-
83
- const imageAlt = get_config_value(
84
- section,
85
- "image_alt",
86
- "Secure login illustration"
87
- );
88
- const imageBackgroundColor = get_config_value(
89
- section,
90
- "image_background_color",
91
- "#f1f5f9"
92
- );
93
-
94
72
  // Get OAuth configuration
95
73
  const oauth = get_oauth_config();
96
74
 
75
+ // OTP sign-in link
76
+ const otpSigninEnabled = get_config_value(section, "otp_signin_enabled", "false") === "true";
77
+ const otpSigninLabel = get_config_value(section, "otp_signin_label", "Sign in with email code");
78
+ const otpSigninHref = get_config_value(section, "otp_signin_href", "/hazo_auth/otp");
79
+
97
80
  return {
98
81
  redirectRoute,
99
82
  successMessage,
@@ -107,10 +90,10 @@ export function get_login_config(): LoginConfig {
107
90
  createAccountPath,
108
91
  createAccountLabel,
109
92
  showCreateAccountLink,
110
- imageSrc,
111
- imageAlt,
112
- imageBackgroundColor,
113
93
  oauth,
94
+ otpSigninEnabled,
95
+ otpSigninLabel,
96
+ otpSigninHref,
114
97
  };
115
98
  }
116
99
 
@@ -34,7 +34,6 @@ export type MySettingsConfig = {
34
34
  user_photo_default_priority2?: "library" | "gravatar";
35
35
  library_photo_path: string;
36
36
  };
37
- heading?: string;
38
37
  subHeading?: string;
39
38
  profilePhotoLabel?: string;
40
39
  profilePhotoRecommendation?: string;
@@ -95,7 +94,6 @@ export function get_my_settings_config(): MySettingsConfig {
95
94
  const fileTypes = get_file_types_config();
96
95
 
97
96
  // Read optional labels with defaults
98
- const heading = get_config_value(section, "heading", "Account Settings");
99
97
  const subHeading = get_config_value(section, "sub_heading", "Manage your profile, password, and email preferences.");
100
98
  const profilePhotoLabel = get_config_value(section, "profile_photo_label", "Profile Photo");
101
99
  const profilePhotoRecommendation = get_config_value(section, "profile_photo_recommendation", "Recommended size: 200x200px. JPG, PNG.");
@@ -115,7 +113,6 @@ export function get_my_settings_config(): MySettingsConfig {
115
113
  userFields,
116
114
  passwordRequirements,
117
115
  profilePicture,
118
- heading,
119
116
  subHeading,
120
117
  profilePhotoLabel,
121
118
  profilePhotoRecommendation,
@@ -10,12 +10,20 @@ import { DEFAULT_OAUTH } from "./config/default_config.js";
10
10
  export type OAuthConfig = {
11
11
  /** Enable Google OAuth login */
12
12
  enable_google: boolean;
13
+ /** Enable Facebook OAuth login */
14
+ enable_facebook: boolean;
13
15
  /** Enable traditional email/password login */
14
16
  enable_email_password: boolean;
15
17
  /** Auto-link Google login to existing unverified email/password accounts */
16
18
  auto_link_unverified_accounts: boolean;
19
+ /** Auto-link Google login to existing unverified email/password accounts (per-provider override) */
20
+ auto_link_unverified_accounts_google: boolean;
21
+ /** Auto-link Facebook login to existing unverified email/password accounts */
22
+ auto_link_unverified_accounts_facebook: boolean;
17
23
  /** Text displayed on the Google sign-in button */
18
24
  google_button_text: string;
25
+ /** Text displayed on the Facebook sign-in button */
26
+ facebook_button_text: string;
19
27
  /** Text displayed on the divider between OAuth and email/password form */
20
28
  oauth_divider_text: string;
21
29
  /** NextAuth signIn page path */
@@ -30,6 +38,10 @@ export type OAuthConfig = {
30
38
  skip_invitation_check: boolean;
31
39
  /** Redirect when skip_invitation_check=true and user has no scope */
32
40
  no_scope_redirect: string;
41
+ /** Facebook App ID from env HAZO_AUTH_FACEBOOK_APP_ID */
42
+ facebook_client_id: string | undefined;
43
+ /** Facebook App Secret from env HAZO_AUTH_FACEBOOK_APP_SECRET */
44
+ facebook_client_secret: string | undefined;
33
45
  };
34
46
 
35
47
  // section: constants
@@ -48,24 +60,51 @@ export function get_oauth_config(): OAuthConfig {
48
60
  DEFAULT_OAUTH.enable_google
49
61
  );
50
62
 
63
+ const enable_facebook = get_config_boolean(
64
+ SECTION_NAME,
65
+ "enable_facebook",
66
+ false
67
+ );
68
+
51
69
  const enable_email_password = get_config_boolean(
52
70
  SECTION_NAME,
53
71
  "enable_email_password",
54
72
  DEFAULT_OAUTH.enable_email_password
55
73
  );
56
74
 
75
+ // Generic key (backward compat)
57
76
  const auto_link_unverified_accounts = get_config_boolean(
58
77
  SECTION_NAME,
59
78
  "auto_link_unverified_accounts",
60
79
  DEFAULT_OAUTH.auto_link_unverified_accounts
61
80
  );
62
81
 
82
+ // Per-provider Google key (falls back to generic)
83
+ const auto_link_unverified_accounts_google = get_config_boolean(
84
+ SECTION_NAME,
85
+ "auto_link_unverified_accounts_google",
86
+ auto_link_unverified_accounts
87
+ );
88
+
89
+ // Per-provider Facebook key (defaults to false — don't auto-link Facebook unverified)
90
+ const auto_link_unverified_accounts_facebook = get_config_boolean(
91
+ SECTION_NAME,
92
+ "auto_link_unverified_accounts_facebook",
93
+ false
94
+ );
95
+
63
96
  const google_button_text = get_config_value(
64
97
  SECTION_NAME,
65
98
  "google_button_text",
66
99
  DEFAULT_OAUTH.google_button_text
67
100
  );
68
101
 
102
+ const facebook_button_text = get_config_value(
103
+ SECTION_NAME,
104
+ "facebook_button_text",
105
+ "Continue with Facebook"
106
+ );
107
+
69
108
  const oauth_divider_text = get_config_value(
70
109
  SECTION_NAME,
71
110
  "oauth_divider_text",
@@ -108,11 +147,18 @@ export function get_oauth_config(): OAuthConfig {
108
147
  DEFAULT_OAUTH.no_scope_redirect
109
148
  );
110
149
 
150
+ const facebook_client_id = process.env.HAZO_AUTH_FACEBOOK_APP_ID;
151
+ const facebook_client_secret = process.env.HAZO_AUTH_FACEBOOK_APP_SECRET;
152
+
111
153
  return {
112
154
  enable_google,
155
+ enable_facebook,
113
156
  enable_email_password,
114
157
  auto_link_unverified_accounts,
158
+ auto_link_unverified_accounts_google,
159
+ auto_link_unverified_accounts_facebook,
115
160
  google_button_text,
161
+ facebook_button_text,
116
162
  oauth_divider_text,
117
163
  sign_in_page,
118
164
  error_page,
@@ -120,6 +166,8 @@ export function get_oauth_config(): OAuthConfig {
120
166
  default_redirect,
121
167
  skip_invitation_check,
122
168
  no_scope_redirect,
169
+ facebook_client_id,
170
+ facebook_client_secret,
123
171
  };
124
172
  }
125
173
 
@@ -142,3 +190,13 @@ export function is_email_password_enabled(): boolean {
142
190
  DEFAULT_OAUTH.enable_email_password
143
191
  );
144
192
  }
193
+
194
+ /**
195
+ * Helper to check if Facebook OAuth is enabled and credentials are present
196
+ * @returns true if Facebook OAuth is enabled and env vars are set
197
+ */
198
+ export function is_facebook_oauth_enabled(): boolean {
199
+ const enabled = get_config_boolean(SECTION_NAME, "enable_facebook", false);
200
+ if (!enabled) return false;
201
+ return !!(process.env.HAZO_AUTH_FACEBOOK_APP_ID && process.env.HAZO_AUTH_FACEBOOK_APP_SECRET);
202
+ }
@@ -0,0 +1,91 @@
1
+ // file_description: server-only helper to read OTP sign-in configuration from hazo_auth_config.ini
2
+ // section: server-only-guard
3
+ import "server-only";
4
+
5
+ // section: imports
6
+ import { get_config_value, get_config_boolean, get_config_number } from "./config/config_loader.server.js";
7
+
8
+ // section: defaults
9
+ export const OTP_CONFIG_DEFAULTS = {
10
+ auto_register: false,
11
+ code_ttl_seconds: 600,
12
+ session_ttl_seconds: 604800,
13
+ slide_when_within_seconds: 86400,
14
+ email_rate_limit_max: 3,
15
+ email_rate_limit_window_seconds: 900,
16
+ ip_rate_limit_max: 20,
17
+ ip_rate_limit_window_seconds: 3600,
18
+ max_verify_attempts: 5,
19
+ auto_assign_scope_id: "00000000-0000-0000-0000-000000000001",
20
+ auto_assign_role_name: "member",
21
+ } as const;
22
+
23
+ // section: types
24
+ export type OtpConfig = {
25
+ /** Whether to automatically register a new user when an unrecognised email requests an OTP */
26
+ auto_register: boolean;
27
+ /** How long (seconds) a generated OTP code is valid */
28
+ code_ttl_seconds: number;
29
+ /** How long (seconds) the session created after successful OTP verification lasts */
30
+ session_ttl_seconds: number;
31
+ /** Slide the session expiry when the remaining TTL falls below this many seconds */
32
+ slide_when_within_seconds: number;
33
+ /** Maximum OTP requests allowed per email address within the rate-limit window */
34
+ email_rate_limit_max: number;
35
+ /** Rate-limit window (seconds) for per-email OTP requests */
36
+ email_rate_limit_window_seconds: number;
37
+ /** Maximum OTP requests allowed per IP address within the rate-limit window */
38
+ ip_rate_limit_max: number;
39
+ /** Rate-limit window (seconds) for per-IP OTP requests */
40
+ ip_rate_limit_window_seconds: number;
41
+ /** Maximum failed verify attempts before the OTP code is invalidated */
42
+ max_verify_attempts: number;
43
+ /** Scope ID to auto-assign a newly registered OTP user to */
44
+ auto_assign_scope_id: string;
45
+ /** Role name to assign within the auto-assign scope */
46
+ auto_assign_role_name: string;
47
+ };
48
+
49
+ // section: helpers
50
+ /**
51
+ * Reads OTP configuration from hazo_auth_config.ini [hazo_auth__otp] section.
52
+ * Falls back to defaults if the config file or section is missing.
53
+ */
54
+ export function get_otp_config(): OtpConfig {
55
+ const section = "hazo_auth__otp";
56
+ const d = OTP_CONFIG_DEFAULTS;
57
+
58
+ return {
59
+ auto_register: get_config_boolean(section, "otp_auto_register", d.auto_register),
60
+ code_ttl_seconds: get_config_number(section, "otp_code_ttl_seconds", d.code_ttl_seconds),
61
+ session_ttl_seconds: get_config_number(section, "otp_session_ttl_seconds", d.session_ttl_seconds),
62
+ slide_when_within_seconds: get_config_number(
63
+ section,
64
+ "otp_slide_when_within_seconds",
65
+ d.slide_when_within_seconds
66
+ ),
67
+ email_rate_limit_max: get_config_number(section, "otp_email_rate_limit_max", d.email_rate_limit_max),
68
+ email_rate_limit_window_seconds: get_config_number(
69
+ section,
70
+ "otp_email_rate_limit_window_seconds",
71
+ d.email_rate_limit_window_seconds
72
+ ),
73
+ ip_rate_limit_max: get_config_number(section, "otp_ip_rate_limit_max", d.ip_rate_limit_max),
74
+ ip_rate_limit_window_seconds: get_config_number(
75
+ section,
76
+ "otp_ip_rate_limit_window_seconds",
77
+ d.ip_rate_limit_window_seconds
78
+ ),
79
+ max_verify_attempts: get_config_number(section, "otp_max_verify_attempts", d.max_verify_attempts),
80
+ auto_assign_scope_id: get_config_value(section, "otp_auto_assign_scope_id", d.auto_assign_scope_id),
81
+ auto_assign_role_name: get_config_value(section, "otp_auto_assign_role_name", d.auto_assign_role_name),
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Convenience accessor — returns just the session TTL seconds from OTP config.
87
+ * Suitable for passing to token-creation utilities.
88
+ */
89
+ export function hazo_auth_otp_session_ttl_seconds(): number {
90
+ return get_otp_config().session_ttl_seconds;
91
+ }
@@ -9,11 +9,6 @@ import { get_already_logged_in_config } from "./already_logged_in_config.server.
9
9
  import { get_user_fields_config } from "./user_fields_config.server.js";
10
10
  import { get_oauth_config } from "./oauth_config.server.js";
11
11
 
12
- // Default image path - consuming apps should either:
13
- // 1. Configure their own image_src in hazo_auth_config.ini
14
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
15
- const DEFAULT_REGISTER_IMAGE_PATH = "/hazo_auth/images/register_default.jpg";
16
-
17
12
  // section: types
18
13
  export type RegisterConfig = {
19
14
  showNameField: boolean;
@@ -31,14 +26,13 @@ export type RegisterConfig = {
31
26
  returnHomePath: string;
32
27
  signInPath: string;
33
28
  signInLabel: string;
34
- imageSrc: string;
35
- imageAlt: string;
36
- imageBackgroundColor: string;
37
29
  /** OAuth configuration */
38
30
  oauth: {
39
31
  enable_google: boolean;
32
+ enable_facebook: boolean;
40
33
  enable_email_password: boolean;
41
34
  google_button_text: string;
35
+ facebook_button_text: string;
42
36
  oauth_divider_text: string;
43
37
  };
44
38
  };
@@ -77,26 +71,6 @@ export function get_register_config(): RegisterConfig {
77
71
  "Sign in"
78
72
  );
79
73
 
80
- // Read image configuration
81
- // If not set in config, falls back to default path-based image
82
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
83
- const imageSrc = get_config_value(
84
- "hazo_auth__register_layout",
85
- "image_src",
86
- DEFAULT_REGISTER_IMAGE_PATH
87
- );
88
-
89
- const imageAlt = get_config_value(
90
- "hazo_auth__register_layout",
91
- "image_alt",
92
- "Modern building representing user registration"
93
- );
94
- const imageBackgroundColor = get_config_value(
95
- "hazo_auth__register_layout",
96
- "image_background_color",
97
- "#e2e8f0"
98
- );
99
-
100
74
  // Get OAuth configuration (shared with login)
101
75
  const oauthConfig = get_oauth_config();
102
76
 
@@ -107,6 +81,13 @@ export function get_register_config(): RegisterConfig {
107
81
  "Sign up with Google"
108
82
  );
109
83
 
84
+ // For the register page, default Facebook button text to "Sign up with Facebook" unless overridden
85
+ const registerFacebookButtonText = get_config_value(
86
+ "hazo_auth__oauth",
87
+ "facebook_button_text_register",
88
+ "Sign up with Facebook"
89
+ );
90
+
110
91
  return {
111
92
  showNameField,
112
93
  passwordRequirements,
@@ -117,13 +98,12 @@ export function get_register_config(): RegisterConfig {
117
98
  returnHomePath: alreadyLoggedInConfig.returnHomePath,
118
99
  signInPath,
119
100
  signInLabel,
120
- imageSrc,
121
- imageAlt,
122
- imageBackgroundColor,
123
101
  oauth: {
124
102
  enable_google: oauthConfig.enable_google,
103
+ enable_facebook: oauthConfig.enable_facebook,
125
104
  enable_email_password: oauthConfig.enable_email_password,
126
105
  google_button_text: registerGoogleButtonText,
106
+ facebook_button_text: registerFacebookButtonText,
127
107
  oauth_divider_text: oauthConfig.oauth_divider_text,
128
108
  },
129
109
  };
@@ -7,11 +7,6 @@ import { get_config_value } from "./config/config_loader.server.js";
7
7
  import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
8
8
  import { get_password_requirements_config } from "./password_requirements_config.server.js";
9
9
 
10
- // Default image path - consuming apps should either:
11
- // 1. Configure their own image_src in hazo_auth_config.ini
12
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
13
- const DEFAULT_RESET_PASSWORD_IMAGE_PATH = "/hazo_auth/images/reset_password_default.jpg";
14
-
15
10
  // section: types
16
11
  export type ResetPasswordConfig = {
17
12
  errorMessage: string;
@@ -30,9 +25,6 @@ export type ResetPasswordConfig = {
30
25
  require_number: boolean;
31
26
  require_special: boolean;
32
27
  };
33
- imageSrc: string;
34
- imageAlt: string;
35
- imageBackgroundColor: string;
36
28
  };
37
29
 
38
30
  // section: helpers
@@ -70,26 +62,6 @@ export function get_reset_password_config(): ResetPasswordConfig {
70
62
  // Get shared password requirements
71
63
  const passwordRequirements = get_password_requirements_config();
72
64
 
73
- // Read image configuration
74
- // If not set in config, falls back to default path-based image
75
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
76
- const imageSrc = get_config_value(
77
- section,
78
- "image_src",
79
- DEFAULT_RESET_PASSWORD_IMAGE_PATH
80
- );
81
-
82
- const imageAlt = get_config_value(
83
- section,
84
- "image_alt",
85
- "Reset password illustration"
86
- );
87
- const imageBackgroundColor = get_config_value(
88
- section,
89
- "image_background_color",
90
- "#f1f5f9"
91
- );
92
-
93
65
  return {
94
66
  errorMessage,
95
67
  successMessage,
@@ -101,9 +73,6 @@ export function get_reset_password_config(): ResetPasswordConfig {
101
73
  returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
102
74
  returnHomePath: alreadyLoggedInConfig.returnHomePath,
103
75
  passwordRequirements,
104
- imageSrc,
105
- imageAlt,
106
- imageBackgroundColor,
107
76
  };
108
77
  }
109
78
 
@@ -14,7 +14,7 @@ export type EmailOptions = {
14
14
  text_body?: string;
15
15
  };
16
16
 
17
- export type EmailTemplateType = "forgot_password" | "email_verification" | "password_changed";
17
+ export type EmailTemplateType = "forgot_password" | "email_verification" | "password_changed" | "otp_signin_code";
18
18
 
19
19
  export type EmailTemplateData = {
20
20
  token?: string;
@@ -243,6 +243,8 @@ function get_email_subject(template_type: EmailTemplateType): string {
243
243
  return "Reset Your Password";
244
244
  case "password_changed":
245
245
  return "Password Changed Successfully";
246
+ case "otp_signin_code":
247
+ return "Your sign-in code";
246
248
  default:
247
249
  return "Email from hazo_auth";
248
250
  }
@@ -101,4 +101,21 @@ export const hazo_auth_template_manifest: SystemTemplateManifest[] = [
101
101
  },
102
102
  ],
103
103
  },
104
+ {
105
+ template_name: "otp_signin_code",
106
+ template_label: "OTP sign-in code",
107
+ category: SYSTEM_CATEGORY,
108
+ html: read_template("otp_signin_code", "html"),
109
+ text: read_template("otp_signin_code", "txt"),
110
+ variables: [
111
+ {
112
+ variable_name: "otp_code",
113
+ variable_description: "6-digit OTP code for email sign-in (v6.1.0+)",
114
+ },
115
+ {
116
+ variable_name: "expires_in_minutes",
117
+ variable_description: "Number of minutes until the OTP code expires",
118
+ },
119
+ ],
120
+ },
104
121
  ];
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Your sign-in code</title>
6
+ </head>
7
+ <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
8
+ <p>Your sign-in code is:</p>
9
+ <p style="font-size: 28px; font-weight: bold; letter-spacing: 0.2em; font-family: monospace; margin: 16px 0;">{{otp_code}}</p>
10
+ <p>This code expires in {{expires_in_minutes}} minutes.</p>
11
+ <p style="color: #666; font-size: 12px;">If you didn't request this code, you can safely ignore this email.</p>
12
+ </body>
13
+ </html>
@@ -0,0 +1,5 @@
1
+ Your sign-in code is: {{otp_code}}
2
+
3
+ This code expires in {{expires_in_minutes}} minutes.
4
+
5
+ If you didn't request this code, you can safely ignore this email.
@@ -20,5 +20,11 @@ export * from "./scope_service.js";
20
20
  export * from "./user_scope_service.js";
21
21
  export * from "./oauth_service.js";
22
22
  export * from "./branding_service.js";
23
-
24
-
23
+ export {
24
+ request_email_otp,
25
+ verify_email_otp,
26
+ generate_otp_code,
27
+ hash_otp_code,
28
+ verify_otp_code,
29
+ } from "./otp_service.js";
30
+ export type { RequestEmailOTPResult, VerifyEmailOTPResult } from "./otp_service";