Documentation Index
Fetch the complete documentation index at: https://thenile.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
Installation
@niledatabase/react contains components and hooks for using the API. It handles sessions, cookies, fetching data, and comes with built-in components to be used as either templates or directly in your application to handle common user tasks. It is designed to be used with @niledatabase/server, which handles API calls itself or forwards them to the regional API for your database.
npm install @niledatabase/react @niledatabase/client
Using the Auth Provider
@niledatabase/react comes with two providers, <SignedIn /> and <SignedOut /> which wrap a central <SessionProvider />. By default, they will fetch a session.
<SignedIn /> will only render children if the user is logged in. Conversely, <SignedOut /> will always render its children unless signed in.
<SignedIn>Jerry, hello!</SignedIn>
<SignedOut>No soup for you!</SignedOut>
It is also possible to be explicit and obtain the session server side. To do that, you would use the following:
import { SignedIn } from '@niledatabase/react';
import { nile } from '@/lib/nile';
export default async function SignUpPage() {
const nileCtx = nile.withContext({ headers }); // headers from request
const session = await nileCtx.auth.getSession();
if (session.status === 'unauthenticated') {
return <div>No soup for you!</div>;
}
return <SignedIn session={session}>Jerry, hello!</SignedIn>;
}
Functions
signIn
makes a POST request to the sign in endpoint. Expects a provider, and optional params for callbackUrl. For the cases of credentials (email + password) and email, you can opt out of redirection by passing redirect: false in the options
signIn('google', { callbackUrl: '/dashboard' });
signIn('credentials', { callbackUrl: '/dashboard' });
signOut
makes a POST request to the sign out endpoint, with an optional params for callbackUrl to redirect the user, and redirect to leave the user on the page, but delete the session and notify the session providers the user has been logged out.
signOut({ callbackUrl: '/sign-in' }); // go back to some sign in page
signOut({ redirect: false }); // Log out, leave the user on the page they're on
Hooks
useSession
You can obtain the current session via useSession(). This must be called within a <SignedIn /> or <SignedOut /> provider.
import { useSession, UserInfo } from '@niledatabase/react';
export default function SignUpPage() {
const session = useSession();
if (session.status !== 'authenticated') {
return <div>Loading...</div>;
}
return <UserInfo />;
}
useTenantId
The useTenantId hook manages the current tenant ID, persisting it in cookies and refetching tenant data when necessary. A tenant id is accessible via document.cookie with the name nile.tenant_id. This cookie is used by the server side SDK to make requests to the auth service.
import { useTenantId } from '@niledatabase/react';
export default function TenantSelector() {
const [tenantId, setTenantId] = useTenantId();
return (
<div>
<p>Current Tenant: {tenantId ?? 'None'}</p>
<button onClick={() => setTenantId('new-tenant-id')}>
Change Tenant
</button>
</div>
);
}
| Value | Type | Description |
|---|
tenantId | string | undefined | The current tenant ID. |
setTenantId | (tenant: string) => void | Function to update the tenant ID. |
| Name | Type | Default | Description |
|---|
params | HookProps & { tenant: Tenant } | undefined | Initial tenant data. |
client | QueryClient | undefined | React Query client instance. |
export type HookProps = {
tenants?: Tenant[]; // a list of tenants
onError?: (e: Error) => void; // failure callback
baseUrl?: string; // fetch origin
};
- Initializes the tenant ID from
params.tenant.id, if provided.
- If no tenant is found, it attempts to read from a cookie (
nile.tenant_id).
- If no cookie exists, it triggers a refetch of tenants.
- Calling
setTenantId(tenantId) updates both state and cookie.
useTenants
The useTenants hook fetches a list of tenants from an API endpoint using React Query. It supports optional preloaded data and can be disabled to prevent automatic queries.
import { useTenants } from '@niledatabase/react';
export default function TenantList() {
const { data: tenants, isLoading, error } = useTenants();
if (isLoading) return <p>Loading tenants...</p>;
if (error) return <p>Error loading tenants</p>;
return (
<ul>
{tenants?.map((tenant) => (
<li key={tenant.id}>{tenant.name}</li>
))}
</ul>
);
}
This hook returns the result of useQuery, which includes:
| Property | Type | Description |
|---|
data | Tenant[] | undefined | List of tenants. |
isLoading | boolean | true while fetching data. |
error | Error | null | Fetch error, if any. |
refetch | () => void | Function to manually refetch tenants. |
Parameters
| Name | Type | Default | Description |
|---|
params | HookProps & { disableQuery?: boolean } | undefined | Hook configuration options. |
client | QueryClient | undefined | Optional React Query client instance. |
export type HookProps = {
tenants?: Tenant[];
onError?: (e: Error) => void;
baseUrl?: string;
};
- If
disableQuery is true, the query is disabled.
- If
tenants is provided and not empty (in the event of hydration), the query is also disabled.
- Otherwise, it fetches tenants from
${baseUrl}/api/tenants using fetch.
- The request runs only once unless manually refetched.
useEmailSignIn
The useEmailSignIn hook provides a mutation for signing in a user using nile auth. It allows customizing the request with callbacks and options for redirection.
import { useSignIn } from '@your-library/react';
export default function Login() {
const signIn = useEmailSignIn({
onSuccess: () => console.log('Login successful'),
onError: (error) => console.error('Login failed', error),
redirect: true,
});
return (
<button onClick={() => signIn({ email: 'user@example.com' })}>
Sign In
</button>
);
}
| Name | Type | Default | Description |
|---|
onSuccess | (data: Response) => void | undefined | Callback after a successful sign-in. |
onError | (error: Error) => void | undefined | Callback if sign-in fails. |
beforeMutate | (data: any) => any | undefined | Function to modify data before mutation. |
callbackUrl | string | undefined | URL to redirect after login. |
redirect | boolean | false | Whether to redirect after login. |
- Calls
signIn('email', data) with optional modifications via beforeMutate.
- Throws an error if authentication fails.
- Redirects if
redirect is true.
useMe
useMe is a React hook that fetches and returns the current authenticated user. It allows preloading a user via props or fetching from an API endpoint if no user is provided.
'use client';
import { useMe } from '@niledatabase/react';
export default function Profile() {
const user = useMe();
if (!user) return <p>Loading...</p>;
return <div>Welcome, {user.name}!</div>;
}
| Name | Type | Default | Description |
|---|
fetchUrl | string | /api/me | API endpoint to fetch the user data. |
user | User | undefined | null | undefined | Initial user data, avoids fetching if provided. |
- If a
user is passed in props, it is set immediately.
- If
user is not provided, the hook fetches from fetchUrl and updates the state.
- The request runs only once when the component mounts.
useResetPassword
The useResetPassword hook provides a way to handle password reset functionality. It sends reset requests to an authentication API and supports optional callbacks and preprocessing of request data.
import { useResetPassword } from '@niledatabase/react';
export default function ResetPasswordForm() {
const resetPassword = useResetPassword({
onSuccess: () => alert('Password reset successful'),
onError: (err) => console.error('Error resetting password:', err),
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
resetPassword({
email: formData.get('email') as string,
});
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
required
placeholder="Enter your email"
/>
<button type="submit">Reset Password</button>
</form>
);
}
| Name | Type | Default | Description |
|---|
params | Params | undefined | Hook configuration options. |
export type Params = {
onSuccess?: (data: Response) => void;
onError?: (error: Error) => void;
beforeMutate?: (data: MutateFnParams) => MutateFnParams;
callbackUrl?: string;
baseUrl?: string;
fetchUrl?: string;
};
- Calls the API at
${baseUrl}/api/auth/reset-password (or a custom fetchUrl).
- Uses PUT for password updates and POST for reset requests.
- Calls
onSuccess or onError based on the request outcome.
- Runs a CSRF request when the hook is initialized.
- Allows modifying data before sending using
beforeMutate.
useSignUp
The useSignUp hook provides a way to handle user sign-up requests. It supports tenant creation, API customization, and session updates after successful registration.
import { useSignUp } from '@niledatabase/react';
export default function SignUpForm() {
const signUp = useSignUp({
onSuccess: () => alert('Sign-up successful!'),
onError: (err) => console.error('Sign-up failed:', err),
createTenant: true, // Optionally create a tenant with the email of the user
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
signUp({
email: formData.get('email') as string,
password: formData.get('password') as string,
});
};
return (
<form onSubmit={handleSubmit}>
<input type="email" name="email" required placeholder="Email" />
<input type="password" name="password" required placeholder="Password" />
<button type="submit">Sign Up</button>
</form>
);
}
| Name | Type | Default | Description |
|---|
params | Props | undefined | Hook configuration options. |
client | QueryClient (optional) | undefined | React Query client instance. |
export type Props = {
onSuccess?: (data: Response, variables: unknown) => void; // success callback
onError?: (error: Error) => void; // error callback
beforeMutate?: (data: SignUpInfo) => SignUpInfo; // optional modifications to the data prior to the API call
callbackUrl?: string; // where the server should redirect users upon successful login
baseUrl?: string; // configure fetch origin
createTenant?: boolean | string; // if boolean, will create a tenant named with the user's email, else will be whatever name is provided (maps to /api/tenants?newTenantName=<name>)
};
export type SignUpInfo = {
email: string;
password: string;
tenantId?: string;
newTenantName?: string;
fetchUrl?: string;
};
- Sends a
POST request to /api/signup (or a custom fetchUrl).
- If
createTenant is true, assigns newTenantName as the user’s email.
- If
createTenant is a string, it is used as the tenant name.
- After a successful sign-up:
- Updates the session.
- Redirects to
callbackUrl if provided, otherwise reloads the page.
- Prefetches authentication providers and CSRF tokens on mount.
useSignIn
The useSignIn hook provides a simple way to authenticate users. It supports pre-processing login data before submission and handles authentication via credentials.
import { useSignIn } from '@niledatabase/react';
export default function SignInForm() {
const signIn = useSignIn({
onSuccess: () => alert('Login successful!'),
onError: (err) => console.error('Login failed:', err),
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
signIn({
email: formData.get('email') as string,
password: formData.get('password') as string,
});
};
return (
<form onSubmit={handleSubmit}>
<input type="email" name="email" required placeholder="Email" />
<input type="password" name="password" required placeholder="Password" />
<button type="submit">Sign In</button>
</form>
);
}
| Name | Type | Default | Description |
|---|
params | Props | undefined | Hook configuration options. |
export type Props = {
onSuccess?: () => void;
onError?: (error: Error) => void;
beforeMutate?: (data: LoginInfo) => LoginInfo;
callbackUrl?: string;
};
export type LoginInfo = {
email: string;
password: string;
};
- Sends a sign-in request using NextAuth’s
signIn('credentials', data).
- If
beforeMutate is provided, it modifies the login data before the request.
- Calls
onSuccess if login succeeds.
- Calls
onError if login fails.
Multi-factor (Client)
Client-side MFA enrollment, challenge, and removal flows powered by the React SDK. The User object (obtained via useSession) will include a multiFactor property when MFA is enabled for the user.
Features
- Authenticator app or email one-time-code enrollment against
/auth/mfa
- Recovery codes for authenticator challenges with remaining-count feedback
- Redirect-aware helpers that work with custom routers or default navigation (
ChallengeRedirect)
- UI building blocks (
MultiFactor* components) plus a lightweight hook
- Optional low-level
mfa helper for bespoke prompts or headless flows
Overview
Nile Auth exposes a single /auth/mfa endpoint for starting MFA setup, completing challenges, and removing an enrolled method. The React SDK wraps the endpoint in useMultiFactor and UI components that parse server responses into ready-to-render experiences.
Tokens returned from setup or sign-in responses must be echoed back on subsequent calls (challenge verification or removal). When the backend needs the browser to redirect, the helper returns { url: string } (a ChallengeRedirect) so you can route accordingly.
Installation
npm install @niledatabase/react @niledatabase/client
Quick start
Enroll with an authenticator app
import { useMultiFactor, MultiFactorAuthenticator } from '@niledatabase/react';
export function MfaEnrollment() {
const { setup, loading, startSetup } = useMultiFactor({
method: 'authenticator',
currentMethod: null,
onRedirect: (url) => window.location.assign(url), // optional
});
return (
<>
<button onClick={startSetup} disabled={loading}>
{loading ? 'Starting...' : 'Enable authenticator MFA'}
</button>
{setup?.scope === 'setup' && setup.method === 'authenticator' ? (
<MultiFactorAuthenticator
setup={setup}
onError={console.error}
onSuccess={(scope) => scope === 'setup' && window.location.reload()}
/>
) : null}
</>
);
}
Handle a challenge prompt (sign-in or removal)
import { useMultiFactor, MultiFactorChallenge } from '@niledatabase/react';
export function ChallengePrompt({ existingToken }: { existingToken: string }) {
const { setup, startDisable } = useMultiFactor({
method: 'authenticator',
currentMethod: 'authenticator',
});
return (
<>
{/* Example: Disabling MFA requires a challenge verification first */}
<button onClick={startDisable}>Disable MFA</button>
{setup?.scope === 'challenge' ? (
<MultiFactorChallenge
payload={setup}
isEnrolled
message="Enter code from your authenticator app"
onSuccess={() => window.location.replace('/app')}
/>
) : null}
</>
);
}
API
useMultiFactor(options)
| Name | Type | Default | Description |
|---|
method | 'authenticator' | 'email' | (required) | MFA mechanism to enable or disable. |
currentMethod | 'authenticator' | 'email' | null | null | Currently enrolled method; blocks switching until disabled. |
onRedirect | (url: string) => void | window.location.assign | Optional handler when the backend responds with a url to visit (ChallengeRedirect). |
onChallengeRedirect | (params: { token; method; scope; destination? }) => void | Internal /mfa/prompt navigation | Override the default challenge redirect builder. |
Returns { setup, loading, errorType, startSetup, startDisable }.
setup: null or an MFA payload. For authenticator: { method: 'authenticator'; token; scope; otpauthUrl?; secret?; recoveryKeys? }. For email: { method: 'email'; token; scope; maskedEmail? }.
startSetup(): begins enrollment (POST /auth/mfa); setup.scope will be "setup" or "challenge" if a verification step is required.
startDisable(): starts removal for the given method. If verification is required, setup.scope will be "challenge".
errorType: one of setup, disable, parseSetup, parseDisable, or null for success.
Components
MultiFactorAuthenticator — renders QR code, recovery keys, and a verification form.
Props: setup: AuthenticatorSetup, onError(message: string | null), onSuccess(scope: 'setup' | 'challenge').
MultiFactorEmail — shows masked email messaging and a verification form.
Props: setup: EmailSetup, onSuccess(scope: 'setup' | 'challenge').
MultiFactorChallenge — shared challenge UI for either method (used for disable flows or sign-in prompts).
Props: payload: { token: string; scope: ChallengeScope; method: MfaMethod }, message: string, isEnrolled: boolean, onSuccess(scope).
Error handling
- Non-200 responses are coerced into
{ url: string } (ChallengeRedirect) with an error search param. MfaVerifyForm and the examples above parse this for user-friendly messaging.
- If
code is missing or shorter than 6 digits, the React forms set a validation error before calling the API.
Additional notes
- Codes are expected to be 6 digits for authenticator/email verification; recovery codes are string tokens issued during setup.
- Challenge tokens expire; expect 410 responses for stale tokens and 404 for unknown challenges.
- Email MFA may return a
maskedEmail and require the same token on verification and disable flows.