@githat/nextjs
v0.2.7
Published
GitHat identity SDK for Next.js applications
Readme
@githat/nextjs
SDK for connecting your Next.js or React app to GitHat's identity platform — auth, orgs, teams, API keys, and more.
GitHat is your backend. This SDK connects your app to api.githat.io with pre-built UI components, hooks, and middleware. No backend to deploy.
Quick Start · Components · Hooks · Middleware · Server-Side · Docs
Features
- Pre-built UI Components — Sign-in, sign-up, password reset, email verification — all themed and ready to go
- React Hooks —
useAuth(),useGitHat(), anduseData()for full control over auth state and API calls - Next.js Middleware — Protect routes at the edge with a single line of config
- Server-Side Auth — Verify tokens, wrap API routes, and inject auth headers
- Customer Data API — Store and query app data in GitHat's managed DynamoDB
- Multi-Tenant — Organizations, team invitations, and role-based access — managed by GitHat's backend
- MCP & Agent Verification — Verify MCP servers and AI agents on-chain
- Dark Theme Included — Import
@githat/nextjs/stylesfor a polished dark UI out of the box - TypeScript First — Full type definitions for every component, hook, and utility
- Dual Output — Ships ESM + CJS so it works everywhere
- Hosted Backend — All features powered by GitHat's platform (
api.githat.io). No backend deployment required
Quick Start
1. Install
npm install @githat/nextjs2. Get Your Publishable Key
Sign up at githat.io and grab your publishable key from the dashboard.
3. Wrap Your App with GitHatProvider
// app/layout.tsx (Next.js App Router)
import { GitHatProvider } from '@githat/nextjs';
import '@githat/nextjs/styles';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<GitHatProvider
config={{
publishableKey: process.env.NEXT_PUBLIC_GITHAT_KEY!,
afterSignInUrl: '/dashboard',
afterSignOutUrl: '/',
}}
>
{children}
</GitHatProvider>
</body>
</html>
);
}4. Add Sign-In and Sign-Up Pages
// app/sign-in/page.tsx
import { SignInForm } from '@githat/nextjs';
export default function SignInPage() {
return (
<div style={{ maxWidth: 400, margin: '80px auto' }}>
<SignInForm signUpUrl="/sign-up" forgotPasswordUrl="/forgot-password" />
</div>
);
}// app/sign-up/page.tsx
import { SignUpForm } from '@githat/nextjs';
export default function SignUpPage() {
return (
<div style={{ maxWidth: 400, margin: '80px auto' }}>
<SignUpForm signInUrl="/sign-in" />
</div>
);
}5. Protect Routes with Middleware
Next.js 14-15 (middleware.ts)
// middleware.ts (project root)
import { authMiddleware } from '@githat/nextjs/middleware';
export default authMiddleware({
publicRoutes: ['/', '/sign-in', '/sign-up', '/forgot-password'],
});
export const config = {
matcher: ['/((?!_next|api|.*\\..*).*)'],
};Next.js 16+ (proxy.ts)
// proxy.ts (project root)
import { authProxy } from '@githat/nextjs/proxy';
export const proxy = authProxy({
publicRoutes: ['/', '/sign-in', '/sign-up', '/forgot-password'],
});
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};6. Use Auth State Anywhere
'use client';
import { useAuth, UserButton, OrgSwitcher } from '@githat/nextjs';
export default function DashboardHeader() {
const { user, org, isSignedIn } = useAuth();
if (!isSignedIn) return null;
return (
<header>
<span>Welcome, {user?.name}</span>
<OrgSwitcher />
<UserButton />
</header>
);
}That's it. You now have a fully authenticated app with sign-in, sign-up, route protection, and org switching.
Components
Provider
| Component | Description | Key Props |
|------------------|------------------------------------------|-----------------------------------------------------------|
| GitHatProvider | Wraps your app and provides auth context | config (required) — see Configuration |
Authentication Forms
| Component | Description | Props |
|----------------------|--------------------------------------|-----------------------------------------------------|
| SignInForm | Email + password sign-in form | onSuccess?, signUpUrl?, forgotPasswordUrl? |
| SignUpForm | Name + email + password sign-up form | onSuccess?, signInUrl? |
| ForgotPasswordForm | Request password reset email | onSuccess?, onError?, signInUrl? |
| ResetPasswordForm | Reset password with token | token, onSuccess?, onError?, signInUrl?, minPasswordLength? |
| VerifyEmailStatus | Auto-verify email from URL token | token, onSuccess?, onError?, signInUrl?, redirectDelay? |
| ChangePasswordForm | Change password (authenticated) | onSuccess?, onError?, minPasswordLength? |
Navigation
| Component | Description | Props |
|----------------|---------------------------------------------|------------------------------------|
| SignInButton | Link/button to your sign-in page | className?, children?, href? |
| SignUpButton | Link/button to your sign-up page | className?, children?, href? |
| UserButton | Avatar dropdown with user info and sign-out | — (uses context) |
| OrgSwitcher | Dropdown to switch between organizations | — (uses context) |
Protection & Verification
| Component | Description | Props |
|------------------|--------------------------------------------|--------------------------------------------------|
| ProtectedRoute | Redirects unauthenticated users to sign-in | children, fallback? |
| VerifiedBadge | Displays MCP/agent verification status | type: 'mcp' \| 'agent', identifier, label? |
Example: Password Reset Flow
// app/forgot-password/page.tsx
import { ForgotPasswordForm } from '@githat/nextjs';
export default function ForgotPasswordPage() {
return (
<div style={{ maxWidth: 400, margin: '80px auto' }}>
<ForgotPasswordForm signInUrl="/sign-in" />
</div>
);
}// app/reset-password/page.tsx
'use client';
import { ResetPasswordForm } from '@githat/nextjs';
import { useSearchParams } from 'next/navigation';
export default function ResetPasswordPage() {
const searchParams = useSearchParams();
const token = searchParams.get('token') || '';
return (
<div style={{ maxWidth: 400, margin: '80px auto' }}>
<ResetPasswordForm token={token} signInUrl="/sign-in" />
</div>
);
}Example: Email Verification
// app/verify-email/page.tsx
'use client';
import { VerifyEmailStatus } from '@githat/nextjs';
import { useSearchParams } from 'next/navigation';
export default function VerifyEmailPage() {
const searchParams = useSearchParams();
const token = searchParams.get('token') || '';
return (
<div style={{ maxWidth: 400, margin: '80px auto' }}>
<VerifyEmailStatus token={token} signInUrl="/sign-in" />
</div>
);
}Example: Protected Dashboard
import { ProtectedRoute } from '@githat/nextjs';
export default function DashboardPage() {
return (
<ProtectedRoute fallback={<p>Checking authentication...</p>}>
<h1>Dashboard</h1>
<p>Only authenticated users see this.</p>
</ProtectedRoute>
);
}Example: Verified Badge
import { VerifiedBadge } from '@githat/nextjs';
export default function AgentCard() {
return (
<div>
<h3>My MCP Server</h3>
<VerifiedBadge type="mcp" identifier="tools.example.com" label="Verified" />
</div>
);
}Hooks
useAuth()
Access the full authentication state and actions. Must be used within a <GitHatProvider>.
const {
// State
user, // GitHatUser | null
org, // GitHatOrg | null
isSignedIn, // boolean
isLoading, // boolean
authError, // string | null
// Actions
signIn, // (email: string, password: string) => Promise<void>
signUp, // (data: SignUpData) => Promise<SignUpResult>
signOut, // () => Promise<void>
switchOrg, // (orgId: string) => Promise<void>
} = useAuth();Example: Custom sign-in flow
'use client';
import { useAuth } from '@githat/nextjs';
import { useState } from 'react';
export function CustomLogin() {
const { signIn, isLoading, authError } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await signIn(email, password);
// Redirects automatically based on afterSignInUrl config
};
return (
<form onSubmit={handleSubmit}>
<input value={email} onChange={e => setEmail(e.target.value)} placeholder="Email" />
<input value={password} onChange={e => setPassword(e.target.value)} type="password" />
<button disabled={isLoading}>Sign In</button>
{authError && <p>{authError}</p>}
</form>
);
}useGitHat()
Access the GitHat API client for authenticated requests, org management, password reset, email verification, and more.
const {
// API Client
fetch, // <T>(path: string, init?: RequestInit) => Promise<T>
getUserOrgs, // () => Promise<{ orgs: GitHatOrg[] }>
// MCP & Agent Verification
verifyMCP, // (domain: string) => Promise<{ verified: boolean }>
verifyAgent, // (wallet: string) => Promise<{ verified: boolean }>
// Organization Metadata
getOrgMetadata, // () => Promise<OrgMetadata>
updateOrgMetadata, // (updates: OrgMetadata) => Promise<OrgMetadata>
// Password Management
forgotPassword, // (email: string) => Promise<{ success: boolean }>
resetPassword, // (token: string, newPassword: string) => Promise<{ success: boolean }>
changePassword, // (currentPassword: string, newPassword: string) => Promise<{ success: boolean }>
// Email Verification
verifyEmail, // (token: string) => Promise<{ success: boolean }>
resendVerificationEmail, // (email: string) => Promise<{ success: boolean }>
} = useGitHat();Example: Fetching user organizations
'use client';
import { useGitHat } from '@githat/nextjs';
import { useEffect, useState } from 'react';
import type { GitHatOrg } from '@githat/nextjs';
export function OrgList() {
const { getUserOrgs } = useGitHat();
const [orgs, setOrgs] = useState<GitHatOrg[]>([]);
useEffect(() => {
getUserOrgs().then(data => setOrgs(data.orgs));
}, [getUserOrgs]);
return (
<ul>
{orgs.map(org => (
<li key={org.id}>{org.name} ({org.role})</li>
))}
</ul>
);
}Example: Calling a custom API endpoint
const { fetch } = useGitHat();
// Authenticated request — tokens are attached automatically
const apps = await fetch<{ apps: App[] }>('/user/apps');Example: Organization metadata
const { getOrgMetadata, updateOrgMetadata } = useGitHat();
// Read metadata
const meta = await getOrgMetadata();
console.log(meta.stripeAccountId);
// Update metadata (requires admin or owner role)
await updateOrgMetadata({ stripeAccountId: 'acct_xxx', features: ['pos'] });
// Delete a key by setting it to null
await updateOrgMetadata({ oldKey: null });Example: Password reset flow (programmatic)
const { forgotPassword, resetPassword, changePassword } = useGitHat();
// Request reset email
await forgotPassword('[email protected]');
// Reset with token (from email link)
await resetPassword(token, 'NewSecurePassword123!');
// Change password (authenticated user)
await changePassword('currentPassword', 'newSecurePassword123!');Example: Email verification (programmatic)
const { verifyEmail, resendVerificationEmail } = useGitHat();
// Verify with token from email link
await verifyEmail(token);
// Resend verification email
await resendVerificationEmail('[email protected]');useData()
Access GitHat's Customer Data API for storing app data in managed DynamoDB. Must be used within a <GitHatProvider>.
const {
put, // <T>(collection: string, data: T) => Promise<PutResult<T>>
get, // <T>(collection: string, id: string) => Promise<T | null>
query, // <T>(collection: string, options?: QueryOptions) => Promise<QueryResult<T>>
remove, // (collection: string, id: string) => Promise<DeleteResult>
batch, // (collection: string, operations: BatchOperation[]) => Promise<BatchResult>
} = useData();Example: CRUD operations
'use client';
import { useData } from '@githat/nextjs';
interface Order {
id: string;
amount: number;
status: 'pending' | 'completed' | 'cancelled';
createdAt: string;
}
export function OrderManager() {
const { put, get, query, remove, batch } = useData();
// Create or update an item
const createOrder = async () => {
const result = await put<Order>('orders', {
id: 'order_123',
amount: 99.99,
status: 'pending',
createdAt: new Date().toISOString(),
});
console.log(result.created ? 'Created' : 'Updated');
};
// Get a single item
const getOrder = async () => {
const order = await get<Order>('orders', 'order_123');
if (order) {
console.log(`Order: $${order.amount}`);
}
};
// Query with filters and pagination
const getPendingOrders = async () => {
const { items, nextCursor } = await query<Order>('orders', {
filter: { status: 'pending' },
limit: 20,
});
console.log(`Found ${items.length} pending orders`);
};
// Delete an item
const deleteOrder = async () => {
await remove('orders', 'order_123');
};
// Batch operations (max 100 per request)
const bulkUpdate = async () => {
await batch('orders', [
{ type: 'put', id: 'order_1', data: { amount: 50, status: 'completed' } },
{ type: 'put', id: 'order_2', data: { amount: 75, status: 'pending' } },
{ type: 'delete', id: 'order_3' },
]);
};
return (
<div>
<button onClick={createOrder}>Create Order</button>
<button onClick={getOrder}>Get Order</button>
<button onClick={getPendingOrders}>List Pending</button>
<button onClick={deleteOrder}>Delete Order</button>
<button onClick={bulkUpdate}>Bulk Update</button>
</div>
);
}Data API Tier Limits
| Tier | Max Items | |------------|-----------| | Free | 1,000 | | Basic | 10,000 | | Pro | 100,000 | | Enterprise | Unlimited |
Middleware
The authMiddleware function protects your Next.js routes at the edge. Unauthenticated users are redirected to your sign-in page with a redirect_url query parameter for post-login redirect.
// middleware.ts (Next.js 14-15)
import { authMiddleware } from '@githat/nextjs/middleware';
export default authMiddleware({
publicRoutes: ['/', '/sign-in', '/sign-up', '/pricing'],
signInUrl: '/sign-in',
injectHeaders: true, // Optional: inject x-githat-* headers
});
export const config = {
matcher: ['/((?!_next|api|.*\\..*).*)'],
};Middleware Options
| Option | Type | Default | Description |
|--------------------|------------|-------------------------|------------------------------------------------------|
| publicRoutes | string[] | ['/'] | Routes accessible without authentication |
| signInUrl | string | '/sign-in' | Where to redirect unauthenticated users |
| tokenCookie | string | 'githat_access' | Cookie name for httpOnly access token |
| legacyTokenCookie| string | 'githat_access_token' | Legacy cookie name (localStorage bridge) |
| injectHeaders | boolean | false | Inject x-githat-* headers into requests |
| secretKey | string | — | Secret key for local JWT verification (recommended) |
Header Injection
When injectHeaders: true, the middleware decodes the JWT and adds these headers to downstream requests:
| Header | Value |
|---------------------|----------------------------|
| x-githat-user-id | User's unique ID |
| x-githat-email | User's email address |
| x-githat-org-id | Current organization ID |
| x-githat-org-slug | Current organization slug |
| x-githat-role | User's role (owner/admin/member) |
This allows API routes to access user info without re-verifying the token.
⚠️ Important: API routes are NOT protected by the middleware/proxy. Both
authMiddlewareandauthProxyautomatically skip all/apiroutes (pathname.startsWith('/api')→ pass-through). This is by design — API routes should usewithAuth()orgetAuth()from@githat/nextjs/serverto verify tokens. See Server-Side Authentication below.
Next.js 16+ Proxy
Next.js 16 renamed middleware.ts to proxy.ts and the export from export default middleware to export const proxy. Use authProxy for Next.js 16+:
// proxy.ts (Next.js 16+)
import { authProxy } from '@githat/nextjs/proxy';
export const proxy = authProxy({
publicRoutes: ['/', '/about', '/pricing', '/sign-in', '/sign-up'],
signInUrl: '/sign-in',
injectHeaders: true,
secretKey: process.env.GITHAT_SECRET_KEY, // Recommended
});
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};The authProxy function accepts the same options as authMiddleware.
⚠️ Important: API routes are NOT protected by
authProxyorauthMiddleware. Both automatically skip all/apiroutes. You must usewithAuth()orgetAuth()from@githat/nextjs/serverto protect your API route handlers. See below.
Server-Side Authentication
The @githat/nextjs/server module provides utilities for server-side token verification in API routes and middleware.
Import
import {
verifyToken,
getAuth,
withAuth,
getOrgMetadata,
updateOrgMetadata,
COOKIE_NAMES,
type AuthPayload,
type VerifyOptions,
} from '@githat/nextjs/server';verifyToken(token, options?)
Verify a JWT token and return the decoded auth payload.
// Local verification (fast, ~1ms) — recommended for production
const auth = await verifyToken(token, {
secretKey: process.env.GITHAT_SECRET_KEY,
});
// API-based verification (simpler setup, ~50-100ms)
const auth = await verifyToken(token);Returns AuthPayload:
interface AuthPayload {
userId: string;
email: string;
orgId: string | null;
orgSlug: string | null;
role: 'owner' | 'admin' | 'member' | null;
tier: 'free' | 'basic' | 'pro' | 'enterprise' | null;
}getAuth(request, options?)
Extract and verify the auth token from a Next.js request. Checks cookies first, then Authorization header.
// app/api/orders/route.ts
import { getAuth } from '@githat/nextjs/server';
export async function GET(request: Request) {
const auth = await getAuth(request, {
secretKey: process.env.GITHAT_SECRET_KEY,
});
if (!auth) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// auth.userId, auth.orgId, auth.role available
return Response.json({ userId: auth.userId });
}withAuth(handler, options?)
Wrap an API route handler with authentication. The handler only runs if the request has a valid token. This is required for every protected API route — the middleware/proxy does not protect /api routes.
// app/api/orders/route.ts
import { withAuth } from '@githat/nextjs/server';
export const GET = withAuth(
async (request, auth) => {
// auth is guaranteed to be valid here
const orders = await db.orders.findMany({
where: { orgId: auth.orgId },
});
return Response.json({ orders });
},
{ secretKey: process.env.GITHAT_SECRET_KEY }
);Custom unauthorized response
export const GET = withAuth(
async (request, auth) => {
return Response.json({ userId: auth.userId });
},
{
secretKey: process.env.GITHAT_SECRET_KEY,
onUnauthorized: () => Response.redirect('/sign-in'),
}
);getOrgMetadata(orgId, options) / updateOrgMetadata(orgId, metadata, options)
Server-side org metadata operations.
import { getOrgMetadata, updateOrgMetadata } from '@githat/nextjs/server';
// Get metadata
const meta = await getOrgMetadata(orgId, {
token: accessToken,
apiUrl: 'https://api.githat.io',
});
console.log(meta.stripeAccountId);
// Update metadata
await updateOrgMetadata(
orgId,
{ stripeAccountId: 'acct_xxx' },
{ token: accessToken }
);COOKIE_NAMES
Constants for cookie names used by the SDK.
import { COOKIE_NAMES } from '@githat/nextjs/server';
// COOKIE_NAMES.accessToken = 'githat_access'
// COOKIE_NAMES.refreshToken = 'githat_refresh'Configuration
GitHatConfig
Pass this to <GitHatProvider config={...}>:
| Property | Type | Required | Default | Description |
|------------------|--------------------------------|----------|---------------------------|--------------------------------------|
| publishableKey | string | Yes | — | Your GitHat publishable key |
| apiUrl | string | No | 'https://api.githat.io' | API base URL |
| signInUrl | string | No | '/sign-in' | Sign-in page route |
| signUpUrl | string | No | '/sign-up' | Sign-up page route |
| afterSignInUrl | string | No | '/' | Redirect after sign-in |
| afterSignOutUrl| string | No | '/' | Redirect after sign-out |
| tokenStorage | 'localStorage' \| 'cookie' | No | 'localStorage' | Token storage mode (see below) |
Token Storage Modes
| Mode | Description |
|----------------|--------------------------------------------------------------------------|
| localStorage | Default. Tokens stored in browser localStorage. Simple client-side setup. |
| cookie | Tokens stored in httpOnly cookies. More secure, XSS-resistant. Better for SSR. |
When using cookie mode:
- Login/refresh automatically set httpOnly cookies
- SDK reads auth state from cookies server-side
- Better security for apps with server-side rendering
- Required for
getAuth()andwithAuth()server utilities
Environment Variables
# .env.local
NEXT_PUBLIC_GITHAT_KEY=pk_live_your_key_here
GITHAT_SECRET_KEY=sk_live_your_secret_key # For server-side verificationReact/Vite Setup
The SDK works with any React 18+ app. For Vite or Create React App, wrap your root component the same way:
// main.tsx (Vite)
import { GitHatProvider } from '@githat/nextjs';
import '@githat/nextjs/styles';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<GitHatProvider config={{ publishableKey: import.meta.env.VITE_GITHAT_KEY }}>
<App />
</GitHatProvider>
);Note: The middleware/proxy exports are Next.js-specific. For Vite/CRA apps, use
<ProtectedRoute>for client-side route protection.
Styling
Import the built-in dark theme:
import '@githat/nextjs/styles';This provides styled defaults for all components (SignInForm, SignUpForm, ForgotPasswordForm, ResetPasswordForm, VerifyEmailStatus, ChangePasswordForm, UserButton, OrgSwitcher, etc.). All class names are prefixed with githat- to avoid conflicts.
Customization
Override any styles using CSS specificity:
/* Your global CSS */
.githat-sign-in-form {
--githat-primary: #6366f1;
--githat-bg: #0a0a0a;
--githat-text: #fafafa;
border-radius: 12px;
}
.githat-btn-primary {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
}Or skip the built-in styles entirely and style from scratch using the className props.
TypeScript
Every export is fully typed. Import types directly:
import type {
// Core types
GitHatUser,
GitHatOrg,
GitHatConfig,
AuthState,
AuthActions,
SignUpData,
SignUpResult,
GitHatContextValue,
// Password & Email
PasswordResetResult,
EmailVerificationResult,
// Server-side
AuthPayload,
VerifyOptions,
OrgMetadata,
WithAuthOptions,
AuthenticatedHandler,
// Customer Data API
DataItem,
QueryOptions,
QueryResult,
PutResult,
DeleteResult,
BatchOperation,
BatchResult,
// Middleware/Proxy
AuthHandlerOptions,
AuthProxyOptions,
} from '@githat/nextjs';Key Types
interface GitHatUser {
id: string;
email: string;
name: string;
avatarUrl: string | null;
emailVerified: boolean;
}
interface GitHatOrg {
id: string;
name: string;
slug: string;
role: string;
tier: string;
}
interface AuthPayload {
userId: string;
email: string;
orgId: string | null;
orgSlug: string | null;
role: 'owner' | 'admin' | 'member' | null;
tier: 'free' | 'basic' | 'pro' | 'enterprise' | null;
}
interface SignUpData {
email: string;
password: string;
name: string;
acceptMarketing?: boolean;
}
interface SignUpResult {
requiresVerification: boolean;
email: string;
}Scaffolding a New Project
Use the companion CLI to scaffold a complete Next.js or React app with GitHat auth pre-configured:
npx create-githat-app my-appThis generates a full project connected to GitHat's hosted backend — sign-in, sign-up, password reset, email verification, dashboard, settings, and team management pages. No backend to deploy.
Known Limitations
These are things GitHat does not provide today. They are not blockers — each has a recommended workaround.
No webhooks / event system
GitHat does not send server-side notifications when users register, verify email, or delete accounts. Use onSuccess callbacks on form components to call your own API endpoint instead:
<SignUpForm
onSuccess={async (result) => {
// result: { requiresVerification: boolean, email: string }
// Call your API to sync user, send welcome email, etc.
await fetch('/api/on-signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: result.email }),
});
}}
/>
<VerifyEmailStatus
token={token}
onSuccess={async () => {
// Email verified — trigger your post-verification logic
await fetch('/api/on-email-verified', { method: 'POST' });
}}
/>No user metadata API
Org metadata exists (getOrgMetadata / updateOrgMetadata), but there is no per-user equivalent. Use the Customer Data API or your own database:
import { useData, useAuth } from '@githat/nextjs';
function useUserPreferences() {
const { user } = useAuth();
const { put, get } = useData();
const getPreferences = async () => {
if (!user) return null;
return get('user-preferences', user.id);
};
const updatePreferences = async (prefs: Partial<Preferences>) => {
if (!user) throw new Error('Not authenticated');
const current = await getPreferences() || { theme: 'dark', notifications: true };
return put('user-preferences', { id: user.id, ...current, ...prefs });
};
return { getPreferences, updatePreferences };
}No bulk user import
There is no self-service API to import existing users from another auth provider. For beta or new apps, users re-register. For production migrations, contact us for enterprise import.
API routes not protected by middleware
authMiddleware and authProxy skip /api routes by design. Use withAuth() or getAuth() per-route — see Server-Side Authentication.
Migrating from Clerk?
See the Clerk Migration Guide for a step-by-step walkthrough of switching from Clerk to GitHat with zero downtime.
Compatibility
| Runtime | Version | Support | |------------------------|---------|--------------------| | React | >= 18 | Full | | Next.js (App Router) | >= 14 | Full | | Next.js (Pages Router) | >= 14 | Components + Hooks | | Vite + React | >= 5 | Components + Hooks | | Create React App | >= 5 | Components + Hooks |
Links
License
Proprietary — see LICENSE for details.
