@xenterprises/nuxt-x-auth-nile
v0.2.0
Published
Nile Auth (thenile.dev) authentication layer for Nuxt
Readme
@xenterprises/nuxt-x-auth-nile
Nuxt 4 authentication layer providing client-only (SPA) authentication against a Nile Auth API via @niledatabase/client (^5.3.1). Includes built-in auth pages, multi-tenancy management, email verification gate, two-factor authentication (TOTP & email), magic links, OAuth/SSO buttons, route guard, and cross-component shared state.
ssr: false — The browser talks to a Nile Auth API. There are no Nitro/server handlers in this layer; mount endpoints on same-origin /api via @xenterprises/fastify-xauth-nile (or an equivalent proxy).
Features
- Multi-Tenancy: Organization creation, switching, settings, and member management. Active tenant state automatically synchronizes with cookie (
nile.tenant-id) and request headers (x-tenant-id). - Email Verification Gate: Built-in route gate (enabled by default) protecting authenticated routes until email verification is confirmed against authoritative
/me. - Two-Factor Authentication (MFA): Authenticator setup with QR code and secret key, sign-in challenge handling, and MFA removal flow.
- Magic Links: Passwordless email sign-in using Nile's email provider.
- Shared State: Built with persistent Nuxt
useStaterefs across layout, pages, and components with automatic probe deduplication. - Aggregator Parity: Compatible with workspace conventions (
$getAuthToken,$getCurrentUser,$logout,$xTenantId,$xTenantHeaders()). - Branded Layouts: Grizzly photo card with glassmorphism or split hero layouts.
Installation
npm install @xenterprises/nuxt-x-auth-nileAdd the layer to your nuxt.config.ts:
export default defineNuxtConfig({
extends: ["@xenterprises/nuxt-x-auth-nile"],
});Consumer Quickstart
Consuming applications configure the layer via app/app.config.ts and environment variables.
1. Configure Environment (.env)
# API origin (empty = same origin as the frontend)
NUXT_PUBLIC_NILE_BASE_URL=
# Base path prefix on that origin (default /api)
NUXT_PUBLIC_NILE_BASE_PATH=/api2. Configure app/app.config.ts
export default defineAppConfig({
xAuth: {
redirects: {
afterLogin: "/dashboard",
},
features: {
oauth: true,
mfa: true,
magicLink: true,
requireEmailVerified: true,
signup: true,
},
tenant: {
enabled: true,
required: false,
signup: {
collectName: "optional", // "off" | "optional" | "required"
},
},
oauthProviders: [
{ id: "google", label: "Google", icon: "i-simple-icons-google" },
{ id: "github", label: "GitHub", icon: "i-simple-icons-github" },
],
},
});Backend Contract (Fastify / Proxy)
Browser requests talk to a same-origin /api prefix mounted by @xenterprises/fastify-xauth-nile (or backend proxy).
| Purpose | Method + Path | Details |
|---|---|---|
| CSRF | GET /auth/csrf | Supplies { csrfToken } for unauthenticated mutations |
| Session | GET /auth/session | SDK session probe |
| Credentials Sign-In | POST /auth/callback/credentials | Email/password sign-in (401 + challenge = MFA) |
| Sign-Up | POST /signup | Creates account; accepts createTenant |
| Magic Link | POST /auth/signin/email | Requests magic link |
| Verify Email | POST /auth/verify-email | Sends or resends verification email |
| Password Reset (send) | POST /auth/reset-password | Sends reset email without ?json=true |
| Password Reset (complete) | PUT /auth/reset-password | Completes reset using token from email cookie |
| MFA | GET/POST/PUT/DELETE /auth/mfa | MFA enrollment, challenge, and removal |
| Authoritative Profile | GET /me, PUT /me | Canonical source for emailVerified, multiFactor, and profile updates |
| Tenants (Organizations) | GET /tenants, POST /tenants | Lists and creates organizations for current user |
| Tenant Details | GET/PUT/DELETE /tenants/{id} | Updates name or deletes organization |
| Tenant Members | GET/tenants/{id}/users | Lists members with access |
| Member Link/Unlink | PUT/DELETE /tenants/{id}/users/{userId} | Adds member or leaves organization |
Host Requirements
- Cookie Path: Configure
cookiePath: "/"on the xAuthNile instance (or host proxy) soPath=/is returned to the client and session cookies cover non-API routes. - Tenant Context: Pass the
nile.tenant-idcookie andx-tenant-idheader into Nile's server context. - Tenants Mount: Mount
GET /tenants(part of the standard nile-auth surface; resolvesuserIdfrom session itself). - SMTP: Configure SMTP in the Nile console for email verification, magic link, and password reset emails.
- Auto-send Verification: Fastify plugin handles auto-sending verification emails on signup
400 verification-required; this layer expects that and does not POST/api/auth/verify-emailafter signup.
Configuration Reference (xAuth)
| Option | Type | Default | Description |
|---|---|---|---|
| publicRoutes | string[] | [] | Extra paths treated as public by route guard (exact or prefix match) |
| middleware.enabled | boolean | true | Middleware kill-switch |
| middleware.public | string[] | [] | Extra public paths extending built-in public routes |
| middleware.guestOnly | string[] | undefined | Overrides the default guest-only routes list |
| pages.* | boolean | true | Enable/disable individual auth pages (login, signup, mfa, magicLink, verifyEmail, account, tenant). Disabled pages return 404. |
| redirects.login | string | "/auth/login" | Login page route |
| redirects.signup | string | "/auth/signup" | Sign-up page route |
| redirects.forgotPassword | string | "/auth/forgot-password" | Password reset request route |
| redirects.resetPassword | string | "/auth/reset-password" | Password reset completion route |
| redirects.mfa | string | "/auth/mfa" | Sign-in MFA challenge route |
| redirects.mfaSetup | string | "/auth/mfa/setup" | MFA enrollment route |
| redirects.magicLink | string | "/auth/magic-link" | Magic link sign-in route |
| redirects.verifyEmail | string | "/auth/verify-email" | Email verification gate route |
| redirects.account | string | "/account" | Account settings page |
| redirects.afterLogin | string | "/" | Destination after sign-in |
| redirects.afterSignup | string | "/" | Destination after registration |
| redirects.afterLogout | string | "/auth/login" | Destination after sign-out |
| redirects.afterVerify | string | undefined | Destination after email verification |
| redirects.afterMfaSetup | string | undefined | Destination after MFA enrollment |
| redirects.preserveReturnTo | boolean | true | Preserve requested destination on redirect to login (?redirect=...) |
| features.oauth | boolean | false | Enable OAuth buttons |
| features.mfa | boolean | false | Enable two-factor authentication |
| features.forgotPassword | boolean | true | Enable password reset |
| features.signup | boolean | true | Enable account registration |
| features.createTenant | boolean \| string | false | Create organization on signup (boolean or default name) |
| features.requireEmailVerified | boolean | true | Gate protected routes behind email verification |
| features.magicLink | boolean | false | Enable passwordless magic link sign-in |
| features.account | boolean | true | Enable account profile settings page |
| tenant.enabled | boolean | true | Enable multi-tenancy |
| tenant.required | boolean | false | Force users with zero organizations into onboarding |
| tenant.cookieName | string | "nile.tenant-id" | Cookie storing active tenant ID |
| tenant.headerName | string | "x-tenant-id" | Header carrying active tenant ID |
| tenant.signup.collectName | "off" \| "optional" \| "required" | "off" | Collect organization name during registration |
| tenant.allowCreate | boolean | true | Allow users to create organizations |
| tenant.allowRename | boolean | true | Allow users to rename organizations |
| tenant.allowDelete | boolean | false | Allow users to delete organizations |
| tenant.allowLeave | boolean | true | Allow users to leave organizations |
| tenant.redirects.onboarding | string | "/auth/tenant" | Onboarding page route |
| tenant.redirects.settings | string | "/account/organization" | Organization management route |
| ui.card.glass | boolean | false | Enable frosted glass card styling |
| ui.card.glassIntensity | "subtle" \| "medium" \| "strong" | "medium" | Glass intensity |
Composables
useXAuth()
High-level authentication composable with toast notifications, shared reactive state, and automatic routing.
const {
user, // Ref<NileUser | null>
isAuthenticated, // Ref<boolean>
isLoading, // Ref<boolean>
login, // (email, password) => Promise<NileUser | null>
signup, // (email, password, options?) => Promise<NileUser | null>
loginWithMagicLink, // (email) => Promise<boolean>
logout, // () => Promise<boolean>
restore, // ({ force? }) => Promise<NileUser | null>
refresh, // () => Promise<NileUser | null>
updateProfile, // ({ name }) => Promise<{ ok: boolean } | { error: string }>
getAuthHeaders, // () => Promise<Record<string, string>>
authorizer, // Raw @niledatabase/client Authorizer singleton
} = useXAuth();useXTenant()
Multi-tenancy composable managing user organizations, active selection, and member access.
const {
tenants, // Ref<NileTenant[]>
activeTenantId, // Ref<string | null>
activeTenant, // ComputedRef<NileTenant | null>
setActiveTenant, // (id: string | null) => void
fetchTenants, // () => Promise<NileTenant[]>
createTenant, // (name: string) => Promise<{ status: "ok", data: NileTenant } | ...>
renameTenant, // (id: string, name: string) => Promise<...>
deleteTenant, // (id: string) => Promise<...>
fetchMembers, // (tenantId: string) => Promise<NileMember[]>
addMember, // (tenantId: string, userId: string) => Promise<...>
removeMember, // (tenantId: string, userId: string) => Promise<...>
leaveTenant, // (tenantId: string, userId: string) => Promise<...>
} = useXTenant();useXNileApi()
Authenticated HTTP client built on ofetch rooted at getApiRoot() (runtimeConfig.public.nile) with credentials inclusion, CSRF helper, and error normalization.
Plugin Injections
The layer provides standard global helpers:
nuxtApp.$getAuthToken: Returns null (Nile sessions use cookies).nuxtApp.$getCurrentUser: Returns the activeNileUserobject (id,name,email,avatar,picture,emailVerified,multiFactor).nuxtApp.$logout: Signs out the user, resets state, and redirects.nuxtApp.$xTenantId: ReactiveRef<string | null>with the active organization ID.nuxtApp.$xTenantHeaders(): Returns{ [headerName]: activeTenantId }when an organization is active.
In consuming apps utilizing nuxt-x-app, inject tenant headers into API requests:
// app.config.ts
export default defineAppConfig({
xApp: {
defaultHeaders: () => useNuxtApp().$xTenantHeaders(),
},
});License
See LICENSE in repository.
