@luminaryworks/auth-react 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,6 +43,16 @@ Override layout via `className` / `style` on the root.
43
43
  // socialProviders: "auto" | ["google","github"] | []
44
44
  />
45
45
 
46
+ // Desktop / mobile native shell — Google/GitHub in the system browser (RFC 8252)
47
+ <HeadlessLoginPanel
48
+ config={idpConfig}
49
+ productName="VistaRemote"
50
+ mode="external"
51
+ openExternalUrl={(url) => window.nativeShell.openExternal(url)}
52
+ // Password Headless stays in-app; social/SSO open the OS browser.
53
+ // Register redirect_uri as http://127.0.0.1:<port>/auth/callback or app://…
54
+ />
55
+
46
56
  // Admin / internal console — hide Experience social connectors
47
57
  <HeadlessLoginPanel
48
58
  config={idpConfig}
@@ -54,11 +64,15 @@ Override layout via `className` / `style` on the root.
54
64
 
55
65
  | Prop | Default | Notes |
56
66
  |------|---------|--------|
67
+ | `mode` | `"popup"` | `"redirect"` SPA full-page; `"external"` system browser for social/SSO (needs `openExternalUrl`) |
68
+ | `openExternalUrl` | — | Required for `mode="external"`. Electron: `shell.openExternal`; RN: Custom Tabs / ASWebAuthenticationSession |
57
69
  | `showSocialConnectors` | `true` | `false` skips fetch and hides divider + social buttons |
58
70
  | `socialProviders` | `"auto"` | allowlist, or `[]` (same effect as `showSocialConnectors={false}`) |
59
71
  | `experienceAdapter` | catalog default | optional custom `LoginExperienceAdapter`; otherwise `config.iamProvider` |
60
72
  | `config.iamProvider` | `logto` | `logto` Headless; `oidc` / `zitadel` Hosted Redirect |
61
73
 
74
+ **Desktop callback:** Logto redirects the *system browser* to your loopback `redirect_uri`. The native shell must detect that request, focus the app window onto the same URL (so PKCE `localStorage` matches), and show Chrome a “you can close this tab” page. See VistaRemote Electron `serve-renderer-static` + Viewer preload.
75
+
62
76
  IdP hosted `/sign-in` social row layout: `node scripts/apply-branding.mjs` (customCss wrap). Enable connectors: `ensure-sign-in-experience.mjs` + `verify-social-direct-signin.mjs`.
63
77
 
64
78
  ### Login experience adapters
package/dist/index.css CHANGED
@@ -48,6 +48,55 @@
48
48
  display: grid;
49
49
  gap: 10px;
50
50
  }
51
+ .HeadlessLoginPanel_module_channelTabs {
52
+ display: grid;
53
+ grid-template-columns: 1fr 1fr;
54
+ gap: 6px;
55
+ margin-bottom: 2px;
56
+ }
57
+ .HeadlessLoginPanel_module_channelTab {
58
+ border: 1px solid #c9d5de;
59
+ border-radius: 10px;
60
+ padding: 8px 10px;
61
+ font-size: 13px;
62
+ font-weight: 650;
63
+ cursor: pointer;
64
+ color: #4b5c68;
65
+ background: #f7fafc;
66
+ }
67
+ .HeadlessLoginPanel_module_channelTab:disabled {
68
+ opacity: 0.65;
69
+ cursor: not-allowed;
70
+ }
71
+ .HeadlessLoginPanel_module_channelTabActive {
72
+ color: var(--lw-auth-theme-deep);
73
+ border-color: var(--lw-auth-theme);
74
+ background: color-mix(in srgb, var(--lw-auth-theme) 10%, #fff);
75
+ }
76
+ .HeadlessLoginPanel_module_codeRow {
77
+ display: grid;
78
+ grid-template-columns: 1fr auto;
79
+ gap: 8px;
80
+ align-items: stretch;
81
+ }
82
+ .HeadlessLoginPanel_module_codeInput {
83
+ min-width: 0;
84
+ }
85
+ .HeadlessLoginPanel_module_secondaryBtn {
86
+ border: 1px solid #b7c9d4;
87
+ border-radius: 10px;
88
+ padding: 0 12px;
89
+ font-size: 13px;
90
+ font-weight: 650;
91
+ cursor: pointer;
92
+ color: #14212b;
93
+ background: #fff;
94
+ white-space: nowrap;
95
+ }
96
+ .HeadlessLoginPanel_module_secondaryBtn:disabled {
97
+ opacity: 0.65;
98
+ cursor: not-allowed;
99
+ }
51
100
  .HeadlessLoginPanel_module_socialStack {
52
101
  display: flex;
53
102
  flex-wrap: wrap;
@@ -201,6 +250,13 @@
201
250
  color: #6b7c87;
202
251
  line-height: 1.45;
203
252
  }
253
+ .HeadlessLoginPanel_module_domainsHint {
254
+ margin: -2px 0 0;
255
+ font-size: 12px;
256
+ line-height: 1.45;
257
+ color: #4b5c68;
258
+ word-break: break-word;
259
+ }
204
260
  .HeadlessLoginPanel_module_switchMode {
205
261
  margin: 12px 0 0;
206
262
  text-align: center;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/HeadlessLoginPanel.module.scss"],"sourcesContent":["$ink: #14212b;\n$muted: #4b5c68;\n$hint: #6b7c87;\n$brand: #3d6f8f;\n$brand-deep: #15485c;\n$brand-mid: #1f6f8b;\n$border: #c9d5de;\n$border-soft: #b7c9d4;\n$line: #d5e0e7;\n$divider: #90a0ab;\n$surface: #f7fafc;\n$fallback-bg: #e8eef2;\n$danger: #b42318;\n$footer-line: #e4ebf0;\n$radius-lg: 16px;\n$radius-md: 10px;\n$radius-sm: 4px;\n\n.panel {\n --lw-auth-theme: #1677ff;\n --lw-auth-theme-deep: color-mix(in srgb, var(--lw-auth-theme) 72%, #000);\n width: min(100%, 400px);\n padding: 28px 28px 22px;\n border-radius: $radius-lg;\n background: rgba(255, 255, 255, 0.96);\n color: $ink;\n box-shadow: 0 24px 64px rgba(15, 23, 42, 0.28);\n font-family: \"Segoe UI\", \"PingFang SC\", \"Noto Sans SC\", sans-serif;\n}\n\n.brand {\n display: flex;\n gap: 14px;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.logo {\n border-radius: 12px;\n display: block;\n}\n\n.product {\n margin: 0;\n font-size: 13px;\n font-weight: 650;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--lw-auth-theme);\n}\n\n.title {\n margin: 2px 0 0;\n font-size: 22px;\n font-weight: 700;\n line-height: 1.25;\n}\n\n.subtitle {\n margin: 0 0 18px;\n font-size: 14px;\n line-height: 1.5;\n color: $muted;\n}\n\n.form {\n display: grid;\n gap: 10px;\n}\n\n.socialStack {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.input {\n width: 100%;\n box-sizing: border-box;\n border: 1px solid $border;\n border-radius: $radius-md;\n padding: 10px 12px;\n font-size: 14px;\n outline: none;\n background: $surface;\n\n &:focus {\n border-color: var(--lw-auth-theme);\n }\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.passwordField {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.passwordInput {\n padding-right: 42px;\n}\n\n.passwordToggle {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: $radius-sm;\n padding: 0;\n color: #5a6b76;\n background: transparent;\n cursor: pointer;\n\n &:hover:not(:disabled) {\n color: var(--lw-auth-theme);\n background: color-mix(in srgb, var(--lw-auth-theme) 12%, transparent);\n }\n\n &:focus-visible {\n outline: 2px solid var(--lw-auth-theme);\n outline-offset: 1px;\n }\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.primaryBtn {\n border: none;\n border-radius: $radius-md;\n padding: 11px 14px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #fff;\n background: linear-gradient(135deg, var(--lw-auth-theme) 0%, var(--lw-auth-theme-deep) 100%);\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.socialBtn {\n flex: 1 1 calc(50% - 5px);\n min-width: min(140px, 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: 1px solid $border-soft;\n border-radius: $radius-md;\n padding: 11px 10px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: $ink;\n background: #fff;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.socialLogo {\n flex-shrink: 0;\n display: block;\n}\n\n.logoFallback {\n width: 18px;\n height: 18px;\n border-radius: $radius-sm;\n background: color-mix(in srgb, var(--lw-auth-theme) 14%, #fff);\n color: var(--lw-auth-theme-deep);\n font-size: 11px;\n font-weight: 700;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.cancelBtn {\n margin-top: 10px;\n width: 100%;\n border: none;\n background: transparent;\n color: #5a6b76;\n font-size: 13px;\n cursor: pointer;\n padding: 8px;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.divider {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 14px 0;\n color: $divider;\n}\n\n.dividerLine {\n flex: 1;\n height: 1px;\n background: $line;\n}\n\n.dividerText {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.hint {\n margin: 10px 0 0;\n font-size: 12px;\n color: $hint;\n line-height: 1.45;\n}\n\n.switchMode {\n margin: 12px 0 0;\n text-align: center;\n}\n\n.switchModeBtn {\n border: none;\n background: transparent;\n color: var(--lw-auth-theme);\n font-size: 13px;\n font-weight: 650;\n cursor: pointer;\n padding: 4px 8px;\n text-decoration: underline;\n text-underline-offset: 3px;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.error {\n margin: 12px 0 0;\n font-size: 13px;\n color: $danger;\n line-height: 1.4;\n}\n\n.footer {\n margin-top: 18px;\n padding-top: 12px;\n border-top: 1px solid $footer-line;\n font-size: 12px;\n color: $hint;\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n"],"mappings":"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","names":["panel","brand","logo","product","title","subtitle","form","socialStack","input","passwordField","passwordInput","passwordToggle","primaryBtn","socialBtn","socialLogo","logoFallback","cancelBtn","divider","dividerLine","dividerText","hint","switchMode","switchModeBtn","error","footer"]}
1
+ {"version":3,"sources":["../src/HeadlessLoginPanel.module.scss"],"sourcesContent":["$ink: #14212b;\n$muted: #4b5c68;\n$hint: #6b7c87;\n$brand: #3d6f8f;\n$brand-deep: #15485c;\n$brand-mid: #1f6f8b;\n$border: #c9d5de;\n$border-soft: #b7c9d4;\n$line: #d5e0e7;\n$divider: #90a0ab;\n$surface: #f7fafc;\n$fallback-bg: #e8eef2;\n$danger: #b42318;\n$footer-line: #e4ebf0;\n$radius-lg: 16px;\n$radius-md: 10px;\n$radius-sm: 4px;\n\n.panel {\n --lw-auth-theme: #1677ff;\n --lw-auth-theme-deep: color-mix(in srgb, var(--lw-auth-theme) 72%, #000);\n width: min(100%, 400px);\n padding: 28px 28px 22px;\n border-radius: $radius-lg;\n background: rgba(255, 255, 255, 0.96);\n color: $ink;\n box-shadow: 0 24px 64px rgba(15, 23, 42, 0.28);\n font-family: \"Segoe UI\", \"PingFang SC\", \"Noto Sans SC\", sans-serif;\n}\n\n.brand {\n display: flex;\n gap: 14px;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.logo {\n border-radius: 12px;\n display: block;\n}\n\n.product {\n margin: 0;\n font-size: 13px;\n font-weight: 650;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--lw-auth-theme);\n}\n\n.title {\n margin: 2px 0 0;\n font-size: 22px;\n font-weight: 700;\n line-height: 1.25;\n}\n\n.subtitle {\n margin: 0 0 18px;\n font-size: 14px;\n line-height: 1.5;\n color: $muted;\n}\n\n.form {\n display: grid;\n gap: 10px;\n}\n\n.channelTabs {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.channelTab {\n border: 1px solid $border;\n border-radius: $radius-md;\n padding: 8px 10px;\n font-size: 13px;\n font-weight: 650;\n cursor: pointer;\n color: $muted;\n background: $surface;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.channelTabActive {\n color: var(--lw-auth-theme-deep);\n border-color: var(--lw-auth-theme);\n background: color-mix(in srgb, var(--lw-auth-theme) 10%, #fff);\n}\n\n.codeRow {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 8px;\n align-items: stretch;\n}\n\n.codeInput {\n min-width: 0;\n}\n\n.secondaryBtn {\n border: 1px solid $border-soft;\n border-radius: $radius-md;\n padding: 0 12px;\n font-size: 13px;\n font-weight: 650;\n cursor: pointer;\n color: $ink;\n background: #fff;\n white-space: nowrap;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.socialStack {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.input {\n width: 100%;\n box-sizing: border-box;\n border: 1px solid $border;\n border-radius: $radius-md;\n padding: 10px 12px;\n font-size: 14px;\n outline: none;\n background: $surface;\n\n &:focus {\n border-color: var(--lw-auth-theme);\n }\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.passwordField {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.passwordInput {\n padding-right: 42px;\n}\n\n.passwordToggle {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: $radius-sm;\n padding: 0;\n color: #5a6b76;\n background: transparent;\n cursor: pointer;\n\n &:hover:not(:disabled) {\n color: var(--lw-auth-theme);\n background: color-mix(in srgb, var(--lw-auth-theme) 12%, transparent);\n }\n\n &:focus-visible {\n outline: 2px solid var(--lw-auth-theme);\n outline-offset: 1px;\n }\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.primaryBtn {\n border: none;\n border-radius: $radius-md;\n padding: 11px 14px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #fff;\n background: linear-gradient(135deg, var(--lw-auth-theme) 0%, var(--lw-auth-theme-deep) 100%);\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.socialBtn {\n flex: 1 1 calc(50% - 5px);\n min-width: min(140px, 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: 1px solid $border-soft;\n border-radius: $radius-md;\n padding: 11px 10px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: $ink;\n background: #fff;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.socialLogo {\n flex-shrink: 0;\n display: block;\n}\n\n.logoFallback {\n width: 18px;\n height: 18px;\n border-radius: $radius-sm;\n background: color-mix(in srgb, var(--lw-auth-theme) 14%, #fff);\n color: var(--lw-auth-theme-deep);\n font-size: 11px;\n font-weight: 700;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.cancelBtn {\n margin-top: 10px;\n width: 100%;\n border: none;\n background: transparent;\n color: #5a6b76;\n font-size: 13px;\n cursor: pointer;\n padding: 8px;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.divider {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 14px 0;\n color: $divider;\n}\n\n.dividerLine {\n flex: 1;\n height: 1px;\n background: $line;\n}\n\n.dividerText {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.hint {\n margin: 10px 0 0;\n font-size: 12px;\n color: $hint;\n line-height: 1.45;\n}\n\n.domainsHint {\n margin: -2px 0 0;\n font-size: 12px;\n line-height: 1.45;\n color: $muted;\n word-break: break-word;\n}\n\n.switchMode {\n margin: 12px 0 0;\n text-align: center;\n}\n\n.switchModeBtn {\n border: none;\n background: transparent;\n color: var(--lw-auth-theme);\n font-size: 13px;\n font-weight: 650;\n cursor: pointer;\n padding: 4px 8px;\n text-decoration: underline;\n text-underline-offset: 3px;\n\n &:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n }\n}\n\n.error {\n margin: 12px 0 0;\n font-size: 13px;\n color: $danger;\n line-height: 1.4;\n}\n\n.footer {\n margin-top: 18px;\n padding-top: 12px;\n border-top: 1px solid $footer-line;\n font-size: 12px;\n color: $hint;\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n"],"mappings":"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","names":["panel","brand","logo","product","title","subtitle","form","channelTabs","channelTab","channelTabActive","codeRow","codeInput","secondaryBtn","socialStack","input","passwordField","passwordInput","passwordToggle","primaryBtn","socialBtn","socialLogo","logoFallback","cancelBtn","divider","dividerLine","dividerText","hint","domainsHint","switchMode","switchModeBtn","error","footer"]}
package/dist/index.d.ts CHANGED
@@ -100,6 +100,8 @@ declare const LOGIN_EXPERIENCE_CAPABILITIES: {
100
100
  readonly passwordSignIn: "password-sign-in";
101
101
  /** Username + password self-register via Experience (Logto NewPasswordIdentity). */
102
102
  readonly passwordSignUp: "password-sign-up";
103
+ /** Email + verification code + password self-register. */
104
+ readonly emailCodeSignUp: "email-code-sign-up";
103
105
  readonly socialConnectors: "social-connectors";
104
106
  readonly socialDirectSignIn: "social-direct-sign-in";
105
107
  };
@@ -126,8 +128,42 @@ interface ExperiencePasswordSignInResult {
126
128
  raw?: unknown;
127
129
  }
128
130
  /** Same OIDC bootstrap fields as sign-in; username must match Logto username rules. */
129
- type ExperiencePasswordSignUpInput = ExperiencePasswordSignInInput;
131
+ type ExperiencePasswordSignUpInput = ExperiencePasswordSignInInput & {
132
+ /** Optional CAPTCHA token for Logto bot protection (Turnstile / reCAPTCHA). */
133
+ captchaToken?: string;
134
+ };
130
135
  type ExperiencePasswordSignUpResult = ExperiencePasswordSignInResult;
136
+ interface ExperienceEmailSignUpSendCodeInput {
137
+ apiBase: string;
138
+ email: string;
139
+ /** @deprecated alias of email */
140
+ identifier?: string;
141
+ captchaToken?: string;
142
+ issuer?: string;
143
+ clientId?: string;
144
+ redirectUri?: string;
145
+ audience?: string;
146
+ scopes?: string;
147
+ returnUrl?: string;
148
+ }
149
+ interface ExperienceEmailSignUpSendCodeResult {
150
+ verificationId: string;
151
+ }
152
+ interface ExperienceEmailSignUpCompleteInput {
153
+ apiBase: string;
154
+ email: string;
155
+ password: string;
156
+ code: string;
157
+ verificationId: string;
158
+ identifier?: string;
159
+ captchaToken?: string;
160
+ issuer?: string;
161
+ clientId?: string;
162
+ redirectUri?: string;
163
+ audience?: string;
164
+ scopes?: string;
165
+ returnUrl?: string;
166
+ }
131
167
  interface ExperienceSocialConnector {
132
168
  id: string;
133
169
  target: string;
@@ -158,6 +194,8 @@ interface LoginExperienceAdapter {
158
194
  * Email/phone sign-up needs verification codes — not covered by this method.
159
195
  */
160
196
  experiencePasswordSignUp?(input: ExperiencePasswordSignUpInput): Promise<ExperiencePasswordSignUpResult>;
197
+ sendRegisterEmailCode?(input: ExperienceEmailSignUpSendCodeInput): Promise<ExperienceEmailSignUpSendCodeResult>;
198
+ experienceEmailPasswordSignUp?(input: ExperienceEmailSignUpCompleteInput): Promise<ExperiencePasswordSignUpResult>;
161
199
  fetchSocialConnectors?(input: FetchSocialConnectorsInput): Promise<ExperienceSocialConnector[]>;
162
200
  createSocialSignInRequest?(target: string): SocialSignInRequest;
163
201
  }
@@ -180,6 +218,76 @@ declare function resolveLoginExperienceAdapter(adapter?: LoginExperienceAdapter
180
218
  /** `VITE_IAM_PROVIDER` / `IAM_PROVIDER` / older `IDP_MODE`. */
181
219
  declare function resolveLoginExperienceProviderFromEnv(env?: Record<string, string | undefined>): LoginExperienceProvider;
182
220
 
221
+ /**
222
+ * Self-register email policy for early ToC / hosted SaaS.
223
+ *
224
+ * Why allowlist: disposable / game / temporary mailboxes drive bot farms and
225
+ * verification-email cost. Early stage: only well-known consumer providers.
226
+ * Enterprise / private: set mode `off` or extend allowlist with corporate domains.
227
+ */
228
+ /** Popular consumer inboxes (CN + global). Lowercase host only. */
229
+ declare const DEFAULT_REGISTER_EMAIL_ALLOWLIST: readonly string[];
230
+ /** Common disposable / throwaway hosts (used when mode is blocklist or as extra deny). */
231
+ declare const DEFAULT_DISPOSABLE_EMAIL_BLOCKLIST: readonly string[];
232
+ type RegisterEmailMode = "allowlist" | "blocklist" | "off";
233
+ interface RegisterEmailPolicy {
234
+ mode: RegisterEmailMode;
235
+ allowlist: readonly string[];
236
+ blocklist: readonly string[];
237
+ }
238
+ interface RegisterEmailPolicyInput {
239
+ mode?: string | null;
240
+ allowlist?: string | readonly string[] | null;
241
+ blocklist?: string | readonly string[] | null;
242
+ }
243
+ declare function normalizeRegisterEmailMode(raw: string | null | undefined): RegisterEmailMode;
244
+ declare function resolveRegisterEmailPolicy(input?: RegisterEmailPolicyInput): RegisterEmailPolicy;
245
+ /** Read VITE_/PUBLIC_/AUTH_REGISTER_* from a static env map (bundler-safe). */
246
+ declare function readRegisterEmailPolicyFromEnv(env?: Record<string, string | undefined>): RegisterEmailPolicy;
247
+ declare function emailDomain(email: string): string | null;
248
+ declare function isValidEmailShape(email: string): boolean;
249
+ type RegisterEmailDecision = {
250
+ ok: true;
251
+ domain: string;
252
+ } | {
253
+ ok: false;
254
+ reason: "invalid" | "not_allowed" | "disposable";
255
+ domain?: string;
256
+ };
257
+ /**
258
+ * Enforce register email policy. `off` still rejects disposable hosts when
259
+ * `blocklist` is non-empty (defense in depth); pass `blocklist: []` to disable.
260
+ */
261
+ declare function evaluateRegisterEmail(email: string, policy?: RegisterEmailPolicy): RegisterEmailDecision;
262
+ declare function registerEmailRejectionMessage(decision: RegisterEmailDecision): string;
263
+ /**
264
+ * Human-readable domain list for the register form (allowlist mode only).
265
+ * Returns null when domains are not restricted to an allowlist.
266
+ */
267
+ declare function formatAllowedEmailDomains(policy: RegisterEmailPolicy, options?: {
268
+ max?: number;
269
+ }): string | null;
270
+ /** Short policy note under the email field on the register form. */
271
+ declare function registerEmailDomainsHint(policy: RegisterEmailPolicy, labels?: {
272
+ allowedDomainsPrefix?: string;
273
+ allowedDomainsOpen?: string;
274
+ allowedDomainsBlocklist?: string;
275
+ }): string | null;
276
+ /** Public policy document from Auth Gateway `GET /api/register-policy`. */
277
+ interface PublicRegisterPolicyResponse {
278
+ mode?: string;
279
+ allowlist?: string[];
280
+ blocklist?: string[];
281
+ ipDailyLimit?: number;
282
+ codeHourlyLimit?: number;
283
+ enabled?: boolean;
284
+ }
285
+ /**
286
+ * Fetch live register policy from Auth Gateway (or any host that serves `/api/register-policy`).
287
+ * Falls back to built-in defaults when the endpoint is missing.
288
+ */
289
+ declare function fetchRegisterEmailPolicy(apiBase: string, init?: RequestInit): Promise<RegisterEmailPolicy>;
290
+
183
291
  /**
184
292
  * Logto Experience API (Headless) adapter.
185
293
  * Prefer same-origin Experience base (SPA proxies /api/experience) so cookies
@@ -198,12 +306,15 @@ declare function createLogtoDirectSignInRequest(directSignIn: string): SocialSig
198
306
  declare class LogtoExperienceAdapter implements LoginExperienceAdapter {
199
307
  readonly provider = "logto";
200
308
  readonly capabilities: readonly LoginExperienceCapability[];
309
+ emailPolicy: RegisterEmailPolicy;
201
310
  experiencePasswordSignIn(input: ExperiencePasswordSignInInput): Promise<ExperiencePasswordSignInResult>;
202
311
  /**
203
312
  * Register with username + password via NewPasswordIdentity.
204
313
  * Email/phone self-register requires verification codes — use social or invite instead.
205
314
  */
206
315
  experiencePasswordSignUp(input: ExperiencePasswordSignUpInput): Promise<ExperiencePasswordSignUpResult>;
316
+ sendRegisterEmailCode(input: ExperienceEmailSignUpSendCodeInput): Promise<ExperienceEmailSignUpSendCodeResult>;
317
+ experienceEmailPasswordSignUp(input: ExperienceEmailSignUpCompleteInput): Promise<ExperiencePasswordSignUpResult>;
207
318
  fetchSocialConnectors(input: FetchSocialConnectorsInput): Promise<ExperienceSocialConnector[]>;
208
319
  createSocialSignInRequest(target: string): SocialSignInRequest;
209
320
  }
@@ -340,6 +451,23 @@ interface HeadlessLoginLabels {
340
451
  passwordMismatch?: string;
341
452
  registerTitle?: string;
342
453
  registerSubtitle?: string;
454
+ registerWithEmail?: string;
455
+ registerWithUsername?: string;
456
+ emailPlaceholder?: string;
457
+ verificationCodePlaceholder?: string;
458
+ sendCode?: string;
459
+ resendCode?: string;
460
+ /** Prefix before the allowlisted domain list, e.g. "Allowed email domains". */
461
+ allowedDomainsPrefix?: string;
462
+ /** Shown when mode is off / unrestricted (aside from disposable blocklist). */
463
+ allowedDomainsOpen?: string;
464
+ /** Shown when only disposable domains are blocked. */
465
+ allowedDomainsBlocklist?: string;
466
+ /**
467
+ * Desktop/mobile system-browser social login: tell the user to finish in the browser
468
+ * and return to the app (loopback / deep link callback).
469
+ */
470
+ waitingExternalBrowser?: string;
343
471
  }
344
472
  interface HeadlessLoginPanelProps {
345
473
  config: Partial<LuminaryIdpConfig>;
@@ -350,8 +478,13 @@ interface HeadlessLoginPanelProps {
350
478
  logoSrc?: string;
351
479
  labels?: HeadlessLoginLabels;
352
480
  returnUrl?: string;
353
- /** Prefer popup (default) for reauth; use redirect for full-page login. */
354
- mode?: "popup" | "redirect";
481
+ /** Prefer popup (default) for reauth; redirect for full-page SPA; external for desktop/mobile system browser (RFC 8252). */
482
+ mode?: "popup" | "redirect" | "external";
483
+ /**
484
+ * Open an authorize URL in the OS browser / Custom Tabs / ASWebAuthenticationSession.
485
+ * Required when `mode="external"` (Google / GitHub / hosted SSO). Password Headless stays in-app.
486
+ */
487
+ openExternalUrl?: (url: string) => void | Promise<void>;
355
488
  /**
356
489
  * Show Experience social connectors (Google / GitHub / …).
357
490
  * Default `true`. Set `false` for admin / internal consoles that only allow
@@ -361,11 +494,26 @@ interface HeadlessLoginPanelProps {
361
494
  */
362
495
  showSocialConnectors?: boolean;
363
496
  /**
364
- * Show self-register switch + register form (username + password via Experience).
497
+ * Show self-register switch + register form.
365
498
  * Default `true` for end-user product logins. Set `false` for admin / ops consoles.
366
- * Hosted OIDC adapters without passwordSignUp hide register automatically.
367
499
  */
368
500
  showRegister?: boolean;
501
+ /**
502
+ * Email domain policy for self-register.
503
+ * If omitted, the panel loads `GET {experienceApiBase}/api/register-policy` when available,
504
+ * otherwise uses built-in consumer allowlist defaults.
505
+ */
506
+ registerEmailPolicy?: RegisterEmailPolicy;
507
+ /**
508
+ * When true (default), fetch live policy from Auth Gateway `/api/register-policy`.
509
+ * Set false to use only `registerEmailPolicy` / built-in defaults (e.g. local auth-dev-proxy).
510
+ */
511
+ fetchRegisterPolicy?: boolean;
512
+ /**
513
+ * Optional CAPTCHA token provider (Cloudflare Turnstile / reCAPTCHA).
514
+ * Token is sent as `captchaToken` on Experience Register init when Logto bot protection is on.
515
+ */
516
+ getCaptchaToken?: () => Promise<string | undefined>;
369
517
  /**
370
518
  * Social providers (when `showSocialConnectors` is not `false`):
371
519
  * - omit / `"auto"` — load enabled connectors from IdP (google, github, x, …)
@@ -393,7 +541,7 @@ interface HeadlessLoginPanelProps {
393
541
  }
394
542
  /** Shared default accent for product login panels (shared/brand --lw-primary). */
395
543
  declare const DEFAULT_LOGIN_THEME_COLOR = "#1677ff";
396
- declare function HeadlessLoginPanel({ config, experienceAdapter: experienceAdapterProp, productName, logoSrc, labels: labelsProp, returnUrl, mode, showSocialConnectors, showRegister, socialProviders, showCancel, onCancel, onOidcSession, onExperienceRedirect, footer, className, style, themeColor, }: HeadlessLoginPanelProps): react.JSX.Element;
544
+ declare function HeadlessLoginPanel({ config, experienceAdapter: experienceAdapterProp, productName, logoSrc, labels: labelsProp, returnUrl, mode, openExternalUrl, showSocialConnectors, showRegister, registerEmailPolicy: registerEmailPolicyProp, fetchRegisterPolicy, getCaptchaToken, socialProviders, showCancel, onCancel, onOidcSession, onExperienceRedirect, footer, className, style, themeColor, }: HeadlessLoginPanelProps): react.JSX.Element;
397
545
 
398
546
  interface ReauthOverlayProps {
399
547
  config: Partial<LuminaryIdpConfig>;
@@ -456,4 +604,4 @@ declare function createPostLoginPathHelpers(options: PostLoginPathOptions): {
456
604
  isUnsafeReturnPath: (path: string) => boolean;
457
605
  };
458
606
 
459
- export { type AuthGateConfig, type AuthGatePhase, AuthGateProvider, type AuthGateProviderProps, type AuthGateSnapshot, DEFAULT_LOGIN_THEME_COLOR, type ExperienceIdentifierType, type ExperiencePasswordSignInInput, type ExperiencePasswordSignInResult, type ExperiencePasswordSignUpInput, type ExperiencePasswordSignUpResult, type ExperienceSocialConnector, type FetchSocialConnectorsInput, type HeadlessLoginLabels, HeadlessLoginPanel, type HeadlessLoginPanelProps, HostedOidcExperienceAdapter, LOGIN_EXPERIENCE_CAPABILITIES, type LoginExperienceAdapter, type LoginExperienceCapability, type LoginExperienceProvider, LogtoExperienceAdapter, LuminaryAuthProvider, type LuminaryAuthProviderProps, type LuminaryAuthSession, type LuminaryIdpConfig, type PostLoginPathOptions, ReauthOverlay, type ReauthOverlayProps, type SignInOptions, type SocialProviderTarget, type SocialSignInRequest, type UnauthorizedDisposition, authGate, clearStoredSession, createLoginExperienceAdapter, createLogtoDirectSignInRequest, createPostLoginPathHelpers, createUserManager, experiencePasswordSignIn, fetchSocialConnectors, getCurrentUser, getStoredAccessToken, handleSignInCallback, handleSignInPopupCallback, isIdpConfigured, isLogtoRegisterUsername, isOidcPopupWindow, prepareSignInRequestUrl, readIdpConfigFromEnv, resetUserManager, resolveExperienceApiBase, resolveIssuer, resolveLoginExperienceAdapter, resolveLoginExperienceProviderFromEnv, sameOriginAuthorizeUrl, signInPopup, signInRedirect, signOutRedirect, useAuthGate, useAuthGateOptional, useLuminaryAuth, withAuthGateRetry };
607
+ export { type AuthGateConfig, type AuthGatePhase, AuthGateProvider, type AuthGateProviderProps, type AuthGateSnapshot, DEFAULT_DISPOSABLE_EMAIL_BLOCKLIST, DEFAULT_LOGIN_THEME_COLOR, DEFAULT_REGISTER_EMAIL_ALLOWLIST, type ExperienceEmailSignUpCompleteInput, type ExperienceEmailSignUpSendCodeInput, type ExperienceEmailSignUpSendCodeResult, type ExperienceIdentifierType, type ExperiencePasswordSignInInput, type ExperiencePasswordSignInResult, type ExperiencePasswordSignUpInput, type ExperiencePasswordSignUpResult, type ExperienceSocialConnector, type FetchSocialConnectorsInput, type HeadlessLoginLabels, HeadlessLoginPanel, type HeadlessLoginPanelProps, HostedOidcExperienceAdapter, LOGIN_EXPERIENCE_CAPABILITIES, type LoginExperienceAdapter, type LoginExperienceCapability, type LoginExperienceProvider, LogtoExperienceAdapter, LuminaryAuthProvider, type LuminaryAuthProviderProps, type LuminaryAuthSession, type LuminaryIdpConfig, type PostLoginPathOptions, type PublicRegisterPolicyResponse, ReauthOverlay, type ReauthOverlayProps, type RegisterEmailDecision, type RegisterEmailMode, type RegisterEmailPolicy, type RegisterEmailPolicyInput, type SignInOptions, type SocialProviderTarget, type SocialSignInRequest, type UnauthorizedDisposition, authGate, clearStoredSession, createLoginExperienceAdapter, createLogtoDirectSignInRequest, createPostLoginPathHelpers, createUserManager, emailDomain, evaluateRegisterEmail, experiencePasswordSignIn, fetchRegisterEmailPolicy, fetchSocialConnectors, formatAllowedEmailDomains, getCurrentUser, getStoredAccessToken, handleSignInCallback, handleSignInPopupCallback, isIdpConfigured, isLogtoRegisterUsername, isOidcPopupWindow, isValidEmailShape, normalizeRegisterEmailMode, prepareSignInRequestUrl, readIdpConfigFromEnv, readRegisterEmailPolicyFromEnv, registerEmailDomainsHint, registerEmailRejectionMessage, resetUserManager, resolveExperienceApiBase, resolveIssuer, resolveLoginExperienceAdapter, resolveLoginExperienceProviderFromEnv, resolveRegisterEmailPolicy, sameOriginAuthorizeUrl, signInPopup, signInRedirect, signOutRedirect, useAuthGate, useAuthGateOptional, useLuminaryAuth, withAuthGateRetry };