hazo_auth 6.1.1 → 7.0.2
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 +65 -167
- package/SETUP_CHECKLIST.md +28 -100
- package/cli-src/cli/generate.ts +1 -10
- package/cli-src/cli/validate.ts +0 -4
- package/cli-src/lib/auth/auth_types.ts +12 -21
- package/cli-src/lib/auth/hazo_get_tenant_auth.server.ts +24 -25
- package/cli-src/lib/auth/index.ts +2 -2
- package/cli-src/lib/auth/nextauth_config.ts +61 -1
- package/cli-src/lib/auth/with_auth.server.ts +15 -15
- package/cli-src/lib/config/default_config.ts +8 -0
- package/cli-src/lib/cookies_config.server.ts +1 -1
- package/cli-src/lib/login_config.server.ts +2 -18
- package/cli-src/lib/oauth_config.server.ts +32 -0
- package/cli-src/lib/register_config.server.ts +4 -0
- package/cli-src/lib/services/email_template_manifest.ts +0 -17
- package/cli-src/lib/services/index.ts +2 -8
- package/cli-src/lib/services/oauth_service.ts +143 -0
- package/cli-src/lib/services/otp_service.ts +7 -2
- package/cli-src/lib/services/session_token_service.ts +0 -2
- package/config/hazo_auth_config.example.ini +0 -38
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +1 -10
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +0 -4
- package/dist/client.d.ts +0 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +0 -1
- package/dist/components/layouts/login/index.d.ts +5 -7
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +5 -2
- package/dist/components/layouts/otp/index.d.ts +12 -1
- package/dist/components/layouts/otp/index.d.ts.map +1 -1
- package/dist/components/layouts/otp/index.js +4 -2
- package/dist/components/layouts/register/index.d.ts +4 -0
- package/dist/components/layouts/register/index.d.ts.map +1 -1
- package/dist/components/layouts/register/index.js +4 -1
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +21 -0
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/facebook_sign_in_button.js +47 -0
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +3 -8
- package/dist/components/layouts/shared/index.d.ts +2 -0
- package/dist/components/layouts/shared/index.d.ts.map +1 -1
- package/dist/components/layouts/shared/index.js +1 -0
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +39 -2
- package/dist/consent/consent_state.d.ts +18 -0
- package/dist/consent/consent_state.d.ts.map +1 -0
- package/dist/consent/consent_state.js +29 -0
- package/dist/consent/cookie_consent_banner.d.ts +11 -0
- package/dist/consent/cookie_consent_banner.d.ts.map +1 -0
- package/dist/consent/cookie_consent_banner.js +40 -0
- package/dist/consent/gtm_mapping.d.ts +13 -0
- package/dist/consent/gtm_mapping.d.ts.map +1 -0
- package/dist/consent/gtm_mapping.js +30 -0
- package/dist/consent/index.d.ts +7 -0
- package/dist/consent/index.d.ts.map +1 -0
- package/dist/consent/index.js +7 -0
- package/dist/consent/manage_modal.d.ts +2 -0
- package/dist/consent/manage_modal.d.ts.map +1 -0
- package/dist/consent/manage_modal.js +33 -0
- package/dist/consent/read_consent.d.ts +15 -0
- package/dist/consent/read_consent.d.ts.map +1 -0
- package/dist/consent/read_consent.js +23 -0
- package/dist/consent/use_consent.d.ts +7 -0
- package/dist/consent/use_consent.d.ts.map +1 -0
- package/dist/consent/use_consent.js +55 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.d.ts +12 -13
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.js +0 -8
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts +7 -8
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_tenant_auth.server.js +22 -23
- package/dist/lib/auth/index.d.ts +2 -2
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.js +50 -1
- package/dist/lib/auth/with_auth.server.d.ts +13 -13
- package/dist/lib/auth/with_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/with_auth.server.js +2 -2
- package/dist/lib/config/default_config.d.ts +16 -0
- package/dist/lib/config/default_config.d.ts.map +1 -1
- package/dist/lib/config/default_config.js +8 -0
- package/dist/lib/cookies_config.server.d.ts +1 -1
- package/dist/lib/cookies_config.server.js +1 -1
- package/dist/lib/login_config.server.d.ts +0 -6
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +2 -11
- package/dist/lib/oauth_config.server.d.ts +8 -0
- package/dist/lib/oauth_config.server.d.ts.map +1 -1
- package/dist/lib/oauth_config.server.js +10 -0
- package/dist/lib/register_config.server.d.ts +2 -0
- package/dist/lib/register_config.server.d.ts.map +1 -1
- package/dist/lib/register_config.server.js +2 -0
- package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
- package/dist/lib/services/email_template_manifest.js +0 -17
- package/dist/lib/services/index.d.ts +0 -2
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +0 -1
- package/dist/lib/services/oauth_service.d.ts +13 -0
- package/dist/lib/services/oauth_service.d.ts.map +1 -1
- package/dist/lib/services/oauth_service.js +122 -0
- package/dist/lib/services/otp_service.d.ts +1 -1
- package/dist/lib/services/otp_service.d.ts.map +1 -1
- package/dist/lib/services/otp_service.js +6 -1
- package/dist/lib/services/session_token_service.d.ts +0 -2
- package/dist/lib/services/session_token_service.d.ts.map +1 -1
- package/dist/lib/services/session_token_service.js +0 -2
- package/dist/server/routes/assets.d.ts +8 -0
- package/dist/server/routes/assets.d.ts.map +1 -0
- package/dist/server/routes/assets.js +38 -0
- package/dist/server/routes/consent_me.d.ts +4 -0
- package/dist/server/routes/consent_me.d.ts.map +1 -0
- package/dist/server/routes/consent_me.js +15 -0
- package/dist/server/routes/index.d.ts +6 -3
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +9 -4
- package/dist/server/routes/me.d.ts.map +1 -1
- package/dist/server/routes/me.js +1 -43
- package/dist/server/routes/oauth_facebook_callback.d.ts +8 -0
- package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -0
- package/dist/server/routes/oauth_facebook_callback.js +164 -0
- package/dist/server/routes/otp/verify.js +2 -2
- package/dist/server/routes/strings_defaults.d.ts +4 -0
- package/dist/server/routes/strings_defaults.d.ts.map +1 -0
- package/dist/server/routes/strings_defaults.js +7 -0
- package/dist/server/routes/user_management_users.d.ts +11 -0
- package/dist/server/routes/user_management_users.d.ts.map +1 -1
- package/dist/server/routes/user_management_users.js +50 -0
- package/dist/server-lib.d.ts +0 -3
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +0 -2
- package/dist/server_pages/forgot_password.d.ts +1 -1
- package/dist/server_pages/forgot_password.d.ts.map +1 -1
- package/dist/server_pages/forgot_password.js +9 -3
- package/dist/server_pages/forgot_password_client_wrapper.d.ts +3 -1
- package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
- package/dist/server_pages/index.d.ts +2 -0
- package/dist/server_pages/index.d.ts.map +1 -1
- package/dist/server_pages/index.js +1 -0
- package/dist/server_pages/login.d.ts +1 -1
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +12 -3
- package/dist/server_pages/login_client_wrapper.d.ts +4 -1
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/dist/server_pages/my_settings.d.ts +1 -1
- package/dist/server_pages/my_settings.d.ts.map +1 -1
- package/dist/server_pages/my_settings.js +1 -2
- package/dist/server_pages/otp.d.ts +16 -2
- package/dist/server_pages/otp.d.ts.map +1 -1
- package/dist/server_pages/otp.js +10 -3
- package/dist/server_pages/register.d.ts +1 -1
- package/dist/server_pages/register.d.ts.map +1 -1
- package/dist/server_pages/register.js +11 -3
- package/dist/server_pages/register_client_wrapper.d.ts +3 -1
- package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/register_client_wrapper.js +2 -2
- package/dist/server_pages/reset_password.d.ts +1 -1
- package/dist/server_pages/reset_password.d.ts.map +1 -1
- package/dist/server_pages/reset_password.js +9 -3
- package/dist/server_pages/reset_password_client_wrapper.d.ts +3 -1
- package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/reset_password_client_wrapper.js +2 -2
- package/dist/server_pages/verify_email.d.ts +1 -1
- package/dist/server_pages/verify_email.d.ts.map +1 -1
- package/dist/server_pages/verify_email.js +8 -3
- package/dist/server_pages/verify_email_client_wrapper.d.ts +3 -1
- package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/verify_email_client_wrapper.js +2 -2
- package/dist/strings/default_strings.d.ts +47 -0
- package/dist/strings/default_strings.d.ts.map +1 -0
- package/dist/strings/default_strings.js +18 -0
- package/dist/strings/index.d.ts +4 -0
- package/dist/strings/index.d.ts.map +1 -0
- package/dist/strings/index.js +3 -0
- package/dist/strings/strings_context.d.ts +12 -0
- package/dist/strings/strings_context.d.ts.map +1 -0
- package/dist/strings/strings_context.js +23 -0
- package/dist/strings/strings_provider.d.ts +26 -0
- package/dist/strings/strings_provider.d.ts.map +1 -0
- package/dist/strings/strings_provider.js +45 -0
- package/dist/theme/create_theme.d.ts +7 -0
- package/dist/theme/create_theme.d.ts.map +1 -0
- package/dist/theme/create_theme.js +97 -0
- package/dist/theme/hex_to_hsl.d.ts +16 -0
- package/dist/theme/hex_to_hsl.d.ts.map +1 -0
- package/dist/theme/hex_to_hsl.js +110 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +3 -0
- package/dist/theme/luminance.d.ts +11 -0
- package/dist/theme/luminance.d.ts.map +1 -0
- package/dist/theme/luminance.js +45 -0
- package/dist/theme/theme_provider.d.ts +14 -0
- package/dist/theme/theme_provider.d.ts.map +1 -0
- package/dist/theme/theme_provider.js +23 -0
- package/dist/theme/theme_types.d.ts +36 -0
- package/dist/theme/theme_types.d.ts.map +1 -0
- package/dist/theme/theme_types.js +1 -0
- package/dist/themes/index.d.ts +2 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +2 -0
- package/dist/themes/preset_neutral.d.ts +3 -0
- package/dist/themes/preset_neutral.d.ts.map +1 -0
- package/dist/themes/preset_neutral.js +14 -0
- package/package.json +25 -22
package/README.md
CHANGED
|
@@ -2,154 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
A reusable authentication UI component package powered by Next.js, TailwindCSS, and shadcn. It integrates `hazo_config` for configuration management and `hazo_connect` for data access, enabling future components to stay aligned with platform conventions.
|
|
4
4
|
|
|
5
|
-
## What's New in v6.1.0
|
|
6
|
-
|
|
7
|
-
**Email-OTP sign-in** — a passwordless, OAuth-free way to sign in via a 6-digit code emailed to the user. Targeted at single-operator deployments that don't want to wire Google OAuth or manage passwords.
|
|
8
|
-
|
|
9
|
-
### Highlights
|
|
10
|
-
|
|
11
|
-
- **New routes** — `POST /api/hazo_auth/otp/request` and `POST /api/hazo_auth/otp/verify`
|
|
12
|
-
- **New components** — `<OTPRequestForm/>` and `<OTPVerifyForm/>` exported from `hazo_auth/client`
|
|
13
|
-
- **New page** — `/hazo_auth/otp` (zero-config) via `hazo_auth/pages/otp`
|
|
14
|
-
- **Sliding 7-day session** — OTP sessions auto-extend on `/me` when within 24h of expiry. OAuth/password sessions keep their existing 30-day fixed behaviour.
|
|
15
|
-
- **Auto-register (opt-in)** — set `otp_auto_register = true` to let unknown emails sign in on first successful /verify
|
|
16
|
-
- **Rate limited** — 3 requests/email/15min, 20 requests/IP/hour; per-code attempts capped at 5
|
|
17
|
-
|
|
18
|
-
### Consumer example
|
|
19
|
-
|
|
20
|
-
Mount the routes:
|
|
21
|
-
|
|
22
|
-
```ts
|
|
23
|
-
// app/api/hazo_auth/otp/request/route.ts
|
|
24
|
-
export { otpRequestPOST as POST } from "hazo_auth/server/routes";
|
|
25
|
-
|
|
26
|
-
// app/api/hazo_auth/otp/verify/route.ts
|
|
27
|
-
export { otpVerifyPOST as POST } from "hazo_auth/server/routes";
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Render the zero-config page:
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
// app/hazo_auth/otp/page.tsx
|
|
34
|
-
export { default } from "hazo_auth/pages/otp";
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Or compose components yourself:
|
|
38
|
-
|
|
39
|
-
```tsx
|
|
40
|
-
"use client";
|
|
41
|
-
import { OTPRequestForm, OTPVerifyForm } from "hazo_auth/client";
|
|
42
|
-
import { useState } from "react";
|
|
43
|
-
|
|
44
|
-
export default function CustomOtp() {
|
|
45
|
-
const [sent_to, set_sent_to] = useState<string | null>(null);
|
|
46
|
-
return sent_to
|
|
47
|
-
? <OTPVerifyForm email={sent_to} redirect_url="/" />
|
|
48
|
-
: <OTPRequestForm on_sent={set_sent_to} />;
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Required setup
|
|
53
|
-
|
|
54
|
-
1. Apply migration: `npm run migrate migrations/015_email_otp.sql`
|
|
55
|
-
2. Add `[hazo_auth__otp]` section to `config/hazo_auth_config.ini` (template in `hazo_auth_config.example.ini`)
|
|
56
|
-
3. `hazo_notify ^3.0.0` (existing peer dep) must be configured to deliver email
|
|
57
|
-
4. New peer dep: `input-otp` (optional; required only if you render `<OTPVerifyForm/>`)
|
|
58
|
-
5. **Add OTP routes to your middleware/proxy `public_routes`** — unauthenticated users land on the OTP page, so the page route and its API routes must bypass auth guards:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
// middleware.ts / proxy.ts (in your consuming app)
|
|
62
|
-
const public_routes = [
|
|
63
|
-
// ... existing entries ...
|
|
64
|
-
"/hazo_auth/otp", // OTP sign-in page (public — users arrive unauthenticated)
|
|
65
|
-
"/api/hazo_auth/otp", // OTP request + verify API routes
|
|
66
|
-
];
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Without this your middleware redirects unauthenticated users away from the sign-in page before they can authenticate.
|
|
70
|
-
|
|
71
|
-
See `MIGRATION.md` "v6.0.x → v6.1" for the full upgrade walkthrough.
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
### What's New in v6.0.0 🚨 BREAKING CHANGE
|
|
76
|
-
|
|
77
|
-
**`TenantAuthResult.organization` / `.organization_id` renamed to `.selected_scope` / `.selected_scope_id`.**
|
|
78
|
-
|
|
79
|
-
The multi-tenancy model has been scope-based for several releases — `auth.user_scopes`, `auth.scope_access_via`, `auth.scope_ok`, the `hazo_auth_scope_id` cookie, the `X-Hazo-Scope-Id` header. The only holdouts using the legacy "organization" name were two fields on `TenantAuthResult` that were always just *"the currently selected scope"* under the hood. This release eliminates the inconsistency.
|
|
80
|
-
|
|
81
|
-
> 📖 **Full migration guide:** [MIGRATION.md → v5.x → v6.0](./MIGRATION.md#v5x--v60-organization--selected_scope)
|
|
82
|
-
|
|
83
|
-
**No behavioral change.** `selected_scope_id` is derived from the same scope-selection cookie/header that `organization_id` was. Wire-format auth responses change field names, but the underlying scope lookup is identical.
|
|
84
|
-
|
|
85
|
-
**No deprecation shim.** A clean find-replace is the upgrade path. If you absolutely need a transitional period, pin to `hazo_auth@^5.3` until you can do the rename in one shot.
|
|
86
|
-
|
|
87
|
-
**What to replace (find ↔ replace, all in your app code):**
|
|
88
|
-
|
|
89
|
-
| Find | Replace with |
|
|
90
|
-
| ------------------------------------------------- | -------------------------------------------------- |
|
|
91
|
-
| `auth.organization` | `auth.selected_scope` |
|
|
92
|
-
| `auth.organization_id` | `auth.selected_scope_id` |
|
|
93
|
-
| `import type { TenantOrganization }` | `import type { SelectedScope }` |
|
|
94
|
-
| `: TenantOrganization` | `: SelectedScope` |
|
|
95
|
-
| `AuthenticatedTenantAuthWithOrg` | `AuthenticatedTenantAuthWithSelectedScope` |
|
|
96
|
-
|
|
97
|
-
**Before / after example:**
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
// BEFORE (v5.x)
|
|
101
|
-
import { hazo_get_tenant_auth } from "hazo_auth/server-lib";
|
|
102
|
-
import type { TenantOrganization } from "hazo_auth";
|
|
103
|
-
|
|
104
|
-
export async function GET(request: NextRequest) {
|
|
105
|
-
const auth = await hazo_get_tenant_auth(request);
|
|
106
|
-
if (!auth.authenticated || !auth.organization) {
|
|
107
|
-
return NextResponse.json({ error: "no tenant" }, { status: 403 });
|
|
108
|
-
}
|
|
109
|
-
const data = await getData(auth.organization_id); // or auth.organization.id
|
|
110
|
-
return NextResponse.json({ org: auth.organization, data });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// AFTER (v6.0)
|
|
114
|
-
import { hazo_get_tenant_auth } from "hazo_auth/server-lib";
|
|
115
|
-
import type { SelectedScope } from "hazo_auth";
|
|
116
|
-
|
|
117
|
-
export async function GET(request: NextRequest) {
|
|
118
|
-
const auth = await hazo_get_tenant_auth(request);
|
|
119
|
-
if (!auth.authenticated || !auth.selected_scope) {
|
|
120
|
-
return NextResponse.json({ error: "no tenant scope" }, { status: 403 });
|
|
121
|
-
}
|
|
122
|
-
const data = await getData(auth.selected_scope_id); // or auth.selected_scope.id
|
|
123
|
-
return NextResponse.json({ selected_scope: auth.selected_scope, data });
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**What did NOT change** (same names, same behavior, same wire format):
|
|
128
|
-
- `auth.user_scopes` — array of all scopes the user has access to
|
|
129
|
-
- `auth.scope_ok`, `auth.scope_access_via` — scope-access fields
|
|
130
|
-
- `hazo_auth_scope_id` cookie name and `X-Hazo-Scope-Id` request header
|
|
131
|
-
- All `Tenant*` type and class names: `TenantAuthResult`, `TenantAuthOptions`, `RequiredTenantAuthResult`, `TenantRequiredError`, `TenantAccessDeniedError`, `hazo_get_tenant_auth`, `require_tenant_auth`, `withAuth`'s `require_tenant` option
|
|
132
|
-
- The error response `{ code: "TENANT_REQUIRED" }` shape — only the human-readable `error` string was rephrased ("Organization context required" → "Tenant scope context required")
|
|
133
|
-
|
|
134
|
-
**One-liner upgrade for typical consumers:**
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
# Run from your app repo (NOT inside hazo_auth itself).
|
|
138
|
-
# Update the path glob to match your code layout.
|
|
139
|
-
git grep -l "organization\b\|TenantOrganization\|AuthenticatedTenantAuthWithOrg" -- 'src/**' 'app/**' 'lib/**' \
|
|
140
|
-
| xargs sed -i.bak '
|
|
141
|
-
s/auth\.organization_id\b/auth.selected_scope_id/g;
|
|
142
|
-
s/auth\.organization\b/auth.selected_scope/g;
|
|
143
|
-
s/\bTenantOrganization\b/SelectedScope/g;
|
|
144
|
-
s/\bAuthenticatedTenantAuthWithOrg\b/AuthenticatedTenantAuthWithSelectedScope/g;
|
|
145
|
-
'
|
|
146
|
-
# Then: review the diff carefully — sed is blunt. Remove .bak files when satisfied.
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
> ⚠️ The sed line is a starting point, not a blanket "trust me." It only catches `auth.organization*` and the type names. If you destructure (`const { organization } = auth`), aliased imports (`TenantOrganization as Org`), or reference `organization` for unrelated reasons (HTML autocomplete attribute, your own variables), the script either misses or wrongly rewrites them. **Always diff before committing.**
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
5
|
### What's New in v5.3.1 🔧
|
|
154
6
|
|
|
155
7
|
**`get_client_ip(request)` exported from `hazo_auth/server-lib`** — extracts the client IP from `x-forwarded-for` (first element), falling back to `x-real-ip`, then `"unknown"`. Previously private to `hazo_get_auth.server.ts`. Useful for consumers that need consistent IP extraction across handlers (e.g., `hazo_feedback` audit logging).
|
|
@@ -1792,7 +1644,7 @@ export async function proxy(request: NextRequest) {
|
|
|
1792
1644
|
|
|
1793
1645
|
#### `hazo_get_tenant_auth` (Recommended for Multi-Tenant Apps)
|
|
1794
1646
|
|
|
1795
|
-
**New:** Tenant-aware authentication function that extracts scope context from request headers or cookies and returns enriched result
|
|
1647
|
+
**New:** Tenant-aware authentication function that extracts scope context from request headers or cookies and returns enriched result with organization information.
|
|
1796
1648
|
|
|
1797
1649
|
**Location:** `src/lib/auth/hazo_get_tenant_auth.server.ts`
|
|
1798
1650
|
|
|
@@ -1826,9 +1678,8 @@ type TenantAuthResult =
|
|
|
1826
1678
|
permissions: string[];
|
|
1827
1679
|
permission_ok: boolean;
|
|
1828
1680
|
missing_permissions?: string[];
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
user_scopes: ScopeDetails[]; // All user's scopes for switching
|
|
1681
|
+
organization: TenantOrganization | null; // NEW: Tenant context
|
|
1682
|
+
user_scopes: ScopeDetails[]; // NEW: All user's scopes for switching
|
|
1832
1683
|
scope_ok: boolean;
|
|
1833
1684
|
}
|
|
1834
1685
|
| {
|
|
@@ -1836,13 +1687,12 @@ type TenantAuthResult =
|
|
|
1836
1687
|
user: null;
|
|
1837
1688
|
permissions: [];
|
|
1838
1689
|
permission_ok: false;
|
|
1839
|
-
|
|
1840
|
-
selected_scope_id: null;
|
|
1690
|
+
organization: null;
|
|
1841
1691
|
user_scopes: [];
|
|
1842
1692
|
scope_ok: false;
|
|
1843
1693
|
};
|
|
1844
1694
|
|
|
1845
|
-
type
|
|
1695
|
+
type TenantOrganization = {
|
|
1846
1696
|
id: string;
|
|
1847
1697
|
name: string;
|
|
1848
1698
|
slug: string | null; // URL-friendly identifier
|
|
@@ -1884,10 +1734,10 @@ export async function GET(request: NextRequest) {
|
|
|
1884
1734
|
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
1885
1735
|
}
|
|
1886
1736
|
|
|
1887
|
-
if (!auth.
|
|
1737
|
+
if (!auth.organization) {
|
|
1888
1738
|
return NextResponse.json(
|
|
1889
1739
|
{
|
|
1890
|
-
error: "No
|
|
1740
|
+
error: "No organization context",
|
|
1891
1741
|
available_scopes: auth.user_scopes.map(s => ({ id: s.id, name: s.name }))
|
|
1892
1742
|
},
|
|
1893
1743
|
{ status: 403 }
|
|
@@ -1895,10 +1745,10 @@ export async function GET(request: NextRequest) {
|
|
|
1895
1745
|
}
|
|
1896
1746
|
|
|
1897
1747
|
// Access tenant-specific data
|
|
1898
|
-
const data = await getTenantData(auth.
|
|
1748
|
+
const data = await getTenantData(auth.organization.id);
|
|
1899
1749
|
|
|
1900
1750
|
return NextResponse.json({
|
|
1901
|
-
|
|
1751
|
+
organization: auth.organization,
|
|
1902
1752
|
data,
|
|
1903
1753
|
// Include available scopes for UI scope switcher
|
|
1904
1754
|
available_scopes: auth.user_scopes,
|
|
@@ -1916,8 +1766,8 @@ export async function GET(request: NextRequest) {
|
|
|
1916
1766
|
required_permissions: ["view_reports"],
|
|
1917
1767
|
});
|
|
1918
1768
|
|
|
1919
|
-
// auth.
|
|
1920
|
-
const reports = await getReports(auth.
|
|
1769
|
+
// auth.organization is guaranteed non-null here
|
|
1770
|
+
const reports = await getReports(auth.organization.id);
|
|
1921
1771
|
return NextResponse.json({ reports });
|
|
1922
1772
|
} catch (error) {
|
|
1923
1773
|
if (error instanceof HazoAuthError) {
|
|
@@ -1967,16 +1817,16 @@ Helper function that wraps `hazo_get_tenant_auth` and throws typed errors for co
|
|
|
1967
1817
|
- `TenantRequiredError` (403) - No tenant context in request
|
|
1968
1818
|
- `TenantAccessDeniedError` (403) - User lacks access to requested tenant
|
|
1969
1819
|
|
|
1970
|
-
**Returns:** `RequiredTenantAuthResult` with guaranteed non-null `
|
|
1820
|
+
**Returns:** `RequiredTenantAuthResult` with guaranteed non-null `organization`
|
|
1971
1821
|
|
|
1972
1822
|
**Example:**
|
|
1973
1823
|
```typescript
|
|
1974
1824
|
export async function GET(request: NextRequest) {
|
|
1975
1825
|
try {
|
|
1976
|
-
//
|
|
1977
|
-
const {
|
|
1826
|
+
// organization is guaranteed to exist
|
|
1827
|
+
const { organization, user, permissions } = await require_tenant_auth(request);
|
|
1978
1828
|
|
|
1979
|
-
const data = await getData(
|
|
1829
|
+
const data = await getData(organization.id);
|
|
1980
1830
|
return NextResponse.json(data);
|
|
1981
1831
|
} catch (error) {
|
|
1982
1832
|
if (error instanceof HazoAuthError) {
|
|
@@ -2029,10 +1879,10 @@ export const DELETE = withAuth<{ id: string }>(
|
|
|
2029
1879
|
{ required_permissions: ["admin_system"] }
|
|
2030
1880
|
);
|
|
2031
1881
|
|
|
2032
|
-
// With tenant requirement (auth.
|
|
1882
|
+
// With tenant requirement (auth.organization guaranteed non-null)
|
|
2033
1883
|
export const GET = withAuth<{ id: string }>(
|
|
2034
1884
|
async (request, auth, { id }) => {
|
|
2035
|
-
const data = await getData(auth.
|
|
1885
|
+
const data = await getData(auth.organization.id, id);
|
|
2036
1886
|
return NextResponse.json(data);
|
|
2037
1887
|
},
|
|
2038
1888
|
{ require_tenant: true }
|
|
@@ -3128,3 +2978,51 @@ The `package.json` exports field defines the public API:
|
|
|
3128
2978
|
- Use `npx shadcn@latest add <component>` to scaffold new UI primitives.
|
|
3129
2979
|
- Centralize configurable values through `hazo_config`.
|
|
3130
2980
|
- Access backend resources exclusively via `hazo_connect`.
|
|
2981
|
+
|
|
2982
|
+
## Email OTP sign-in
|
|
2983
|
+
|
|
2984
|
+
```tsx
|
|
2985
|
+
// app/(auth)/otp/page.tsx
|
|
2986
|
+
import { OTPPage } from "hazo_auth/pages/otp";
|
|
2987
|
+
export default function Page(props) { return <OTPPage {...props} />; }
|
|
2988
|
+
```
|
|
2989
|
+
|
|
2990
|
+
Enable in config: `[hazo_auth__otp] enable_email_otp = true`. Run `npx hazo_auth migrate migrations/015_email_otp.sql`.
|
|
2991
|
+
|
|
2992
|
+
## Theming
|
|
2993
|
+
|
|
2994
|
+
```tsx
|
|
2995
|
+
import { HazoAuthThemeProvider, createTheme } from "hazo_auth/theme";
|
|
2996
|
+
|
|
2997
|
+
const my_theme = createTheme({
|
|
2998
|
+
colors: { primary: "#1D4ED8" },
|
|
2999
|
+
layout: "split",
|
|
3000
|
+
brandPanel: { logoSrc: "/logo.svg", tagline: "Welcome." },
|
|
3001
|
+
});
|
|
3002
|
+
|
|
3003
|
+
<HazoAuthThemeProvider theme={my_theme}>
|
|
3004
|
+
<LoginPage />
|
|
3005
|
+
</HazoAuthThemeProvider>
|
|
3006
|
+
```
|
|
3007
|
+
|
|
3008
|
+
Theme is auth-page scoped. Does not affect `:root`.
|
|
3009
|
+
|
|
3010
|
+
## Cookie Consent
|
|
3011
|
+
|
|
3012
|
+
```tsx
|
|
3013
|
+
import { CookieConsentBanner } from "hazo_auth/consent";
|
|
3014
|
+
// Place in your root layout:
|
|
3015
|
+
<CookieConsentBanner />
|
|
3016
|
+
```
|
|
3017
|
+
|
|
3018
|
+
Server-side consent check: `GET /api/hazo_auth/consent/me` returns `ConsentState`.
|
|
3019
|
+
|
|
3020
|
+
## String overrides
|
|
3021
|
+
|
|
3022
|
+
```tsx
|
|
3023
|
+
import { HazoAuthStringsProvider } from "hazo_auth/strings";
|
|
3024
|
+
|
|
3025
|
+
<HazoAuthStringsProvider strings={{ login: { title: "Welcome back" } }}>
|
|
3026
|
+
<LoginPage />
|
|
3027
|
+
</HazoAuthStringsProvider>
|
|
3028
|
+
```
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -958,7 +958,27 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_hazo_users_google_id_unique ON hazo_users(
|
|
|
958
958
|
CREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);
|
|
959
959
|
```
|
|
960
960
|
|
|
961
|
-
### Step 3.2.4:
|
|
961
|
+
### Step 3.2.4 (Optional): Run Email OTP Migration
|
|
962
|
+
|
|
963
|
+
Required only if you plan to enable `enable_email_otp = true` in `[hazo_auth__otp]`.
|
|
964
|
+
|
|
965
|
+
```bash
|
|
966
|
+
npx hazo_auth migrate migrations/015_email_otp.sql
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
Creates `hazo_email_otps` table for OTP codes and rate limiting.
|
|
970
|
+
|
|
971
|
+
### Step 3.2.4b (Optional): Run Facebook OAuth Migration
|
|
972
|
+
|
|
973
|
+
Required only if `enable_facebook_oauth = true` in `[hazo_auth__oauth]`.
|
|
974
|
+
|
|
975
|
+
```bash
|
|
976
|
+
npx hazo_auth migrate migrations/016_add_facebook_id_to_hazo_users.sql
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
Adds `facebook_id` column to `hazo_users`.
|
|
980
|
+
|
|
981
|
+
### Step 3.2.5: Configure OAuth in hazo_auth_config.ini
|
|
962
982
|
|
|
963
983
|
Add (or modify) the OAuth section:
|
|
964
984
|
|
|
@@ -1443,98 +1463,6 @@ export { POST } from "hazo_auth/server/routes/pin_login";
|
|
|
1443
1463
|
|
|
1444
1464
|
---
|
|
1445
1465
|
|
|
1446
|
-
## Phase 5.3: Email-OTP Sign-in Setup (Optional)
|
|
1447
|
-
|
|
1448
|
-
Email-OTP sign-in lets users authenticate with a 6-digit code sent to their email — no password or Google OAuth required. Skip this phase if your app uses only password or OAuth authentication.
|
|
1449
|
-
|
|
1450
|
-
### Step 5.3.1: Apply the OTP migration
|
|
1451
|
-
|
|
1452
|
-
```bash
|
|
1453
|
-
npm run migrate migrations/015_email_otp.sql
|
|
1454
|
-
```
|
|
1455
|
-
|
|
1456
|
-
This creates the `hazo_email_otps` table (stores hashed codes with expiry).
|
|
1457
|
-
|
|
1458
|
-
**Verify the table exists:**
|
|
1459
|
-
```bash
|
|
1460
|
-
sqlite3 data/hazo_auth.sqlite ".tables" | tr ' ' '\n' | grep hazo_email_otps
|
|
1461
|
-
# Expected: hazo_email_otps
|
|
1462
|
-
```
|
|
1463
|
-
|
|
1464
|
-
### Step 5.3.2: Add OTP config section
|
|
1465
|
-
|
|
1466
|
-
Add to `config/hazo_auth_config.ini`:
|
|
1467
|
-
|
|
1468
|
-
```ini
|
|
1469
|
-
[hazo_auth__otp]
|
|
1470
|
-
# Whether OTP sign-in is enabled
|
|
1471
|
-
enabled = true
|
|
1472
|
-
|
|
1473
|
-
# Auto-register unknown emails on first successful verify (default: false)
|
|
1474
|
-
otp_auto_register = false
|
|
1475
|
-
|
|
1476
|
-
# Code expiry in minutes (default: 10)
|
|
1477
|
-
code_expiry_minutes = 10
|
|
1478
|
-
```
|
|
1479
|
-
|
|
1480
|
-
### Step 5.3.3: Create OTP API routes
|
|
1481
|
-
|
|
1482
|
-
```bash
|
|
1483
|
-
npx hazo_auth generate-routes
|
|
1484
|
-
```
|
|
1485
|
-
|
|
1486
|
-
Or manually:
|
|
1487
|
-
|
|
1488
|
-
`app/api/hazo_auth/otp/request/route.ts`:
|
|
1489
|
-
```typescript
|
|
1490
|
-
export { otpRequestPOST as POST } from "hazo_auth/server/routes";
|
|
1491
|
-
```
|
|
1492
|
-
|
|
1493
|
-
`app/api/hazo_auth/otp/verify/route.ts`:
|
|
1494
|
-
```typescript
|
|
1495
|
-
export { otpVerifyPOST as POST } from "hazo_auth/server/routes";
|
|
1496
|
-
```
|
|
1497
|
-
|
|
1498
|
-
### Step 5.3.4: Create the OTP sign-in page
|
|
1499
|
-
|
|
1500
|
-
`app/hazo_auth/otp/page.tsx`:
|
|
1501
|
-
```typescript
|
|
1502
|
-
export { default } from "hazo_auth/pages/otp";
|
|
1503
|
-
```
|
|
1504
|
-
|
|
1505
|
-
### Step 5.3.5: Add OTP routes to middleware/proxy public_routes (REQUIRED)
|
|
1506
|
-
|
|
1507
|
-
**This step is critical.** Unauthenticated users arrive at the OTP sign-in page before they have auth cookies. If the OTP routes are not in `public_routes`, your middleware will redirect them to `/login` in a loop.
|
|
1508
|
-
|
|
1509
|
-
Edit your `middleware.ts` or `proxy.ts`:
|
|
1510
|
-
|
|
1511
|
-
```typescript
|
|
1512
|
-
const public_routes = [
|
|
1513
|
-
// ... existing entries ...
|
|
1514
|
-
"/hazo_auth/otp", // OTP sign-in page (public — users arrive unauthenticated)
|
|
1515
|
-
"/api/hazo_auth/otp", // OTP request + verify API routes
|
|
1516
|
-
];
|
|
1517
|
-
```
|
|
1518
|
-
|
|
1519
|
-
### Step 5.3.6: Install optional peer dep (if using OTPVerifyForm)
|
|
1520
|
-
|
|
1521
|
-
If you render `<OTPVerifyForm/>` directly (rather than using the zero-config page), install:
|
|
1522
|
-
|
|
1523
|
-
```bash
|
|
1524
|
-
npm install input-otp
|
|
1525
|
-
```
|
|
1526
|
-
|
|
1527
|
-
**OTP Setup Checklist:**
|
|
1528
|
-
- [ ] `hazo_email_otps` table created (`npm run migrate migrations/015_email_otp.sql`)
|
|
1529
|
-
- [ ] `[hazo_auth__otp]` section added to `hazo_auth_config.ini`
|
|
1530
|
-
- [ ] OTP API routes created (`/api/hazo_auth/otp/request` and `/api/hazo_auth/otp/verify`)
|
|
1531
|
-
- [ ] OTP page created (`/hazo_auth/otp`)
|
|
1532
|
-
- [ ] `/hazo_auth/otp` and `/api/hazo_auth/otp` added to middleware `public_routes`
|
|
1533
|
-
- [ ] `input-otp` installed (only if using `<OTPVerifyForm/>` directly)
|
|
1534
|
-
- [ ] Email delivery configured (`hazo_notify` + valid `ZEPTOMAIL_API_KEY`)
|
|
1535
|
-
|
|
1536
|
-
---
|
|
1537
|
-
|
|
1538
1466
|
## Phase 6: Verification Tests
|
|
1539
1467
|
|
|
1540
1468
|
Run these tests to verify your setup is working correctly.
|
|
@@ -2016,10 +1944,10 @@ import { hazo_get_tenant_auth } from "hazo_auth/server-lib";
|
|
|
2016
1944
|
export async function GET(request: NextRequest) {
|
|
2017
1945
|
const auth = await hazo_get_tenant_auth(request);
|
|
2018
1946
|
|
|
2019
|
-
if (auth.authenticated && auth.
|
|
2020
|
-
// auth.
|
|
1947
|
+
if (auth.authenticated && auth.organization) {
|
|
1948
|
+
// auth.organization contains tenant details
|
|
2021
1949
|
// auth.user_scopes contains all scopes user can access (for UI switcher)
|
|
2022
|
-
const data = await getTenantData(auth.
|
|
1950
|
+
const data = await getTenantData(auth.organization.id);
|
|
2023
1951
|
}
|
|
2024
1952
|
}
|
|
2025
1953
|
```
|
|
@@ -2031,8 +1959,8 @@ import { require_tenant_auth, HazoAuthError } from "hazo_auth/server-lib";
|
|
|
2031
1959
|
export async function GET(request: NextRequest) {
|
|
2032
1960
|
try {
|
|
2033
1961
|
const auth = await require_tenant_auth(request);
|
|
2034
|
-
// auth.
|
|
2035
|
-
return NextResponse.json(await getData(auth.
|
|
1962
|
+
// auth.organization is guaranteed non-null
|
|
1963
|
+
return NextResponse.json(await getData(auth.organization.id));
|
|
2036
1964
|
} catch (error) {
|
|
2037
1965
|
if (error instanceof HazoAuthError) {
|
|
2038
1966
|
return NextResponse.json(
|
|
@@ -2052,7 +1980,7 @@ import { withAuth } from "hazo_auth/server-lib";
|
|
|
2052
1980
|
// Auth + params + error handling all automatic
|
|
2053
1981
|
export const GET = withAuth<{ id: string }>(
|
|
2054
1982
|
async (request, auth, { id }) => {
|
|
2055
|
-
const data = await getData(auth.
|
|
1983
|
+
const data = await getData(auth.organization.id, id);
|
|
2056
1984
|
return NextResponse.json(data);
|
|
2057
1985
|
},
|
|
2058
1986
|
{ require_tenant: true }
|
|
@@ -2101,7 +2029,7 @@ const auth = await hazo_get_tenant_auth(request);
|
|
|
2101
2029
|
|
|
2102
2030
|
// Return available scopes to frontend
|
|
2103
2031
|
return NextResponse.json({
|
|
2104
|
-
current_scope: auth.
|
|
2032
|
+
current_scope: auth.organization,
|
|
2105
2033
|
available_scopes: auth.user_scopes.map(s => ({
|
|
2106
2034
|
id: s.id,
|
|
2107
2035
|
name: s.name,
|
package/cli-src/cli/generate.ts
CHANGED
|
@@ -127,20 +127,11 @@ ${exports}
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function generate_page_content(page: PageDefinition): string {
|
|
130
|
-
// Next 16 requires page default exports to satisfy `PageProps` (i.e. accept
|
|
131
|
-
// `{ params?, searchParams? }` and nothing else). Re-exporting the named
|
|
132
|
-
// component directly fails that check because the component carries custom
|
|
133
|
-
// props (image_src, layout, …). The wrapper below is a parameter-less
|
|
134
|
-
// function that returns the component — Next sees a `() => JSX` signature
|
|
135
|
-
// which trivially satisfies PageProps. Direct JSX consumers still use the
|
|
136
|
-
// named export from `hazo_auth/pages` and get the full custom-prop API.
|
|
137
130
|
return `// Generated by hazo_auth - do not edit manually
|
|
138
131
|
// Page: /${page.path}
|
|
139
132
|
import { ${page.component_name} } from "hazo_auth/pages";
|
|
140
133
|
|
|
141
|
-
export default
|
|
142
|
-
return <${page.component_name} />;
|
|
143
|
-
}
|
|
134
|
+
export default ${page.component_name};
|
|
144
135
|
`;
|
|
145
136
|
}
|
|
146
137
|
|
package/cli-src/cli/validate.ts
CHANGED
|
@@ -64,9 +64,6 @@ const REQUIRED_API_ROUTES = [
|
|
|
64
64
|
{ path: "api/hazo_auth/user_management/users/roles", method: "GET" },
|
|
65
65
|
{ path: "api/hazo_auth/user_management/users/roles", method: "POST" },
|
|
66
66
|
{ path: "api/hazo_auth/user_management/users/roles", method: "PUT" },
|
|
67
|
-
// OTP routes
|
|
68
|
-
{ path: "api/hazo_auth/otp/request", method: "POST" },
|
|
69
|
-
{ path: "api/hazo_auth/otp/verify", method: "POST" },
|
|
70
67
|
];
|
|
71
68
|
|
|
72
69
|
// section: helpers
|
|
@@ -537,7 +534,6 @@ const REQUIRED_TABLES = [
|
|
|
537
534
|
"hazo_role_permissions",
|
|
538
535
|
"hazo_invitations",
|
|
539
536
|
"hazo_refresh_tokens",
|
|
540
|
-
"hazo_email_otps",
|
|
541
537
|
];
|
|
542
538
|
|
|
543
539
|
const TEXT_ID_TABLES = [
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
// file_description: Type definitions and error classes for hazo_get_auth utility
|
|
2
|
-
//
|
|
3
|
-
// Naming note (v6.0.0): the field previously called `organization` (and
|
|
4
|
-
// `organization_id`) on `TenantAuthResult` was renamed to `selected_scope`
|
|
5
|
-
// (and `selected_scope_id`), and the type `TenantOrganization` was renamed
|
|
6
|
-
// to `SelectedScope`. The multi-tenancy model is scopes throughout; the
|
|
7
|
-
// old name was a legacy synonym for "the currently selected scope" derived
|
|
8
|
-
// from the scope-selection cookie/header. No deprecation shim is provided.
|
|
9
|
-
//
|
|
10
2
|
// section: types
|
|
11
3
|
|
|
12
4
|
/**
|
|
@@ -131,11 +123,10 @@ export type ScopeDetails = {
|
|
|
131
123
|
};
|
|
132
124
|
|
|
133
125
|
/**
|
|
134
|
-
*
|
|
135
|
-
* Simplified view of
|
|
136
|
-
* `X-Hazo-Scope-Id` header.
|
|
126
|
+
* Tenant/organization information returned in tenant auth results
|
|
127
|
+
* Simplified view of scope for API responses
|
|
137
128
|
*/
|
|
138
|
-
export type
|
|
129
|
+
export type TenantOrganization = {
|
|
139
130
|
id: string;
|
|
140
131
|
name: string;
|
|
141
132
|
slug: string | null;
|
|
@@ -176,9 +167,9 @@ export type TenantAuthResult =
|
|
|
176
167
|
permissions: string[];
|
|
177
168
|
permission_ok: boolean;
|
|
178
169
|
missing_permissions?: string[];
|
|
179
|
-
|
|
180
|
-
/** Shorthand for
|
|
181
|
-
|
|
170
|
+
organization: TenantOrganization | null;
|
|
171
|
+
/** Shorthand for organization?.id - commonly used for DB query filters */
|
|
172
|
+
organization_id: string | null;
|
|
182
173
|
user_scopes: ScopeDetails[];
|
|
183
174
|
scope_ok?: boolean;
|
|
184
175
|
scope_access_via?: ScopeAccessInfo;
|
|
@@ -188,20 +179,20 @@ export type TenantAuthResult =
|
|
|
188
179
|
user: null;
|
|
189
180
|
permissions: [];
|
|
190
181
|
permission_ok: false;
|
|
191
|
-
|
|
192
|
-
/** Shorthand for
|
|
193
|
-
|
|
182
|
+
organization: null;
|
|
183
|
+
/** Shorthand for organization?.id - commonly used for DB query filters */
|
|
184
|
+
organization_id: null;
|
|
194
185
|
user_scopes: [];
|
|
195
186
|
scope_ok?: false;
|
|
196
187
|
};
|
|
197
188
|
|
|
198
189
|
/**
|
|
199
|
-
* Guaranteed authenticated result with non-null
|
|
200
|
-
* Returned by require_tenant_auth when validation passes
|
|
190
|
+
* Guaranteed authenticated result with non-null organization
|
|
191
|
+
* Returned by require_tenant_auth when validation passes
|
|
201
192
|
*/
|
|
202
193
|
export type RequiredTenantAuthResult = TenantAuthResult & {
|
|
203
194
|
authenticated: true;
|
|
204
|
-
|
|
195
|
+
organization: TenantOrganization;
|
|
205
196
|
};
|
|
206
197
|
|
|
207
198
|
// section: tenant_error_classes
|