@onion-az/identity
v0.0.3
Published
A minimal, framework-agnostic identity factory for React. You bring your own auth backend (Firebase, Supabase, custom API, anything), and this library provides a consistent, typed, runtime-safe identity layer.
Readme
@onion-az/identity
A minimal, framework-agnostic identity factory for React.
You bring your own auth backend (Firebase, Supabase, custom API, anything),
and this library provides a consistent, typed, runtime-safe identity layer.
Designed to be tiny, type-safe, and auth-provider neutral.
Features
- Zero dependencies (React only)
- Bring-your-own authentication logic
- Fully typed
userandcapabilities - Provider + hook API
- Works with any auth backend
- Extremely small surface area
- No assumptions about your auth model
- Universal: works with Bun, Node, Vite, and npm
Installation
npm
npm install @onion-az/identitybun
bun add @onion-az/identitypnpm
pnpm add @onion-az/identityQuick Start
1. Define your user type
// types.ts
import type { BaseUser } from "@onion-az/identity";
export interface MyUser extends BaseUser<string> {
email: string;
roles: string[];
}Extend BaseUser in any way you need.
2. Create your identity instance
// identity.ts
import { createIdentityFactory } from "@onion-az/identity";
import type { MyUser } from "./types";
export const Identity = createIdentityFactory<
MyUser,
{ logout: () => Promise<void> }
>();This produces:
Identity.ProviderIdentity.useAuth()
3. Provide the identity state
You control how your user is loaded, refreshed, and managed.
import { Identity } from "./identity";
import { useEffect, useState } from "react";
function App() {
const [user, setUser] = useState<MyUser | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/me")
.then(res => res.json())
.then(setUser)
.finally(() => setLoading(false));
}, []);
const capabilities = {
logout: async () => {
await fetch("/api/logout", { method: "POST" });
setUser(null);
}
};
return (
<Identity.Provider
value={{
user,
loading,
error: null,
capabilities
}}
>
<AppRoutes />
</Identity.Provider>
);
}Using useAuth()
import { Identity } from "./identity";
function Dashboard() {
const { user, loading, error, capabilities } = Identity.useAuth();
if (loading) return <p>Loading...</p>;
if (!user) return <p>You must sign in.</p>;
return (
<div>
<h1>Welcome {user.email}</h1>
<button onClick={capabilities.logout}>Log out</button>
</div>
);
}Identity Context Shape
interface IdentityContext<TUser, TCapabilities> {
user: TUser | null;
loading: boolean;
error: unknown | null;
capabilities: TCapabilities;
}You define:
- your user model
- your roles
- your capabilities (logout, delete account, refresh token, etc.)
License
MIT © OnionAZ
