A local MVP authentication provider (like Clerk / WorkOS) for development. Spin it up with Docker and use it as the auth backend while building your apps β then swap it out for a real provider when going to production.
docker compose up --build- Dashboard: http://localhost:5173
- Backend API: http://localhost:3001
Two example applications are included to demonstrate different approaches:
Demonstrates using the official LocalAuth SDK with React. Best for quick integration.
cd example/vite-with-sdk
npm install
npm run devFeatures:
LocalAuthProviderwrapperuseAuthhook for authentication state- Login/Register forms
- Protected dashboard
Demonstrates direct API integration without the SDK. Useful for understanding how the API works or when you need custom authentication logic.
cd example/vite-no-sdk
npm install
npm run devFeatures:
- Custom
AuthContextimplementation - Direct API calls using fetch
- React Router protected routes
- Login/Register/Dashboard pages
Both examples use environment variables. Copy .env.example to .env:
cp .env.example .env| Variable | Description |
|---|---|
VITE_API_URL |
Backend URL (default: http://localhost:3001) |
VITE_APP_API_KEY |
Your LocalAuth app API key |
Create an app via the Dashboard to get an API key.
- Open the Dashboard at
http://localhost:5173 - Create a new App β it gets a unique API key (e.g.
la_abc123...) - Use the API key in your app's requests to register/authenticate users
- Each app has its own isolated SQLite database β deleting the app deletes all its data
All auth endpoints require the x-api-key header with your app's API key.
curl -X POST http://localhost:3001/api/auth/signup \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"email": "user@example.com",
"username": "johndoe",
"password": "securepassword",
"fullName": "John Doe",
"phone": "+1234567890"
}'curl -X POST http://localhost:3001/api/auth/signin \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"email": "user@example.com", "password": "securepassword"}'curl http://localhost:3001/api/auth/me \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"curl -X PUT http://localhost:3001/api/auth/me \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"fullName": "Jane Doe", "phone": "+9876543210"}'No auth required (local development only).
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/apps |
List all apps |
POST |
/api/apps |
Create an app |
GET |
/api/apps/:id |
Get app details |
DELETE |
/api/apps/:id |
Delete app + data |
GET |
/api/apps/:id/users |
List users for app |
DELETE |
/api/apps/:id/users/:userId |
Delete a user |
Each user record contains:
email(required, unique per app)username(optional, unique per app)password(required, bcrypt hashed)full_namephonemetadata(JSON object for custom fields)
LocalAuth provides an official SDK for TypeScript/JavaScript applications, including React support.
npm install localauth-sdkUse the LocalAuthClient for vanilla JS/TS applications:
import { LocalAuthClient } from 'localauth-sdk';
const auth = new LocalAuthClient({
apiKey: 'your_api_key',
apiUrl: 'http://localhost:3001'
});
// Sign up
await auth.signUp({
email: 'user@example.com',
username: 'johndoe',
password: 'securepassword',
fullName: 'John Doe'
});
// Sign in
await auth.signIn({
email: 'user@example.com',
password: 'securepassword'
});
// Get current user
const { user } = await auth.getMe();
// Update user
await auth.updateMe({ fullName: 'Jane Doe' });
// Sign out
await auth.signOut();
// Access user state
console.log(auth.user); // Current user or null
console.log(auth.token); // JWT token or null
console.log(auth.isAuthenticated); // booleanWrap your app with LocalAuthProvider and use the useAuth hook:
import { LocalAuthProvider, useAuth } from 'localauth-sdk/react';
function App() {
return (
<LocalAuthProvider config={{ apiKey: 'your_api_key' }}>
<YourApp />
</LocalAuthProvider>
);
}
function LoginForm() {
const { signIn, user, isLoading, error } = useAuth();
const handleSubmit = async (e) => {
e.preventDefault();
await signIn({ email: 'user@example.com', password: 'password' });
};
if (isLoading) return <div>Loading...</div>;
return (
<form onSubmit={handleSubmit}>
{error && <div>{error.message}</div>}
{user ? (
<p>Welcome, {user.full_name}!</p>
) : (
<button type="submit">Sign In</button>
)}
</form>
);
}| Property | Type | Description |
|---|---|---|
user |
User | null |
Current authenticated user |
isAuthenticated |
boolean |
Whether user is logged in |
isLoading |
boolean |
Initial loading state |
error |
LocalAuthError | null |
Any auth error |
signUp(params) |
Promise<void> |
Register new user |
signIn(params) |
Promise<void> |
Sign in user |
signOut() |
Promise<void> |
Sign out user |
updateMe(params) |
Promise<void> |
Update user profile |
clearError() |
void |
Clear error state |
- Backend: Express + TypeScript + better-sqlite3
- Frontend: React + TypeScript + Vite
- SDK: TypeScript with React support
- Database: SQLite (one main db for apps, one per-app db for users)
- Auth: JWT tokens signed with per-app secret keys
- Deployment: Docker Compose