@creezio/auth
v0.26.1
Published
Session / login / logout / recovery — natif Creezio (sqlite core + JWT + UI)
Readme
@creezio/auth
Rôle
@creezio/auth porte l'authentification native Creezio : credentials en SQLite core, store memoire pour tests, sessions JWT en cookie, routes/middlewares Hono, UI login/session React, IPC Electron et recovery key crypto reexportee depuis @creezio/platform-core.
Le package est independant de la marque : il ne connait ni le nom du cookie, ni les permissions de navigation, ni le bridge desktop, ni les tables metier users d'une app. Ces elements sont injectes au boot.
Surfaces publiees :
| Import | Usage |
|---|---|
| @creezio/auth | config, store, JWT/cookies, Hono, IPC, recovery |
| @creezio/auth/ui | LoginPage (split-screen brand-configurable), LoginForm, SessionProvider, useSession |
Périmètre (kit vs marque)
Ce qui appartient au kit :
AUTH_CORE_SQLpour les tablescreezio_usersetcreezio_sessionsdans SQLite core ;createMemoryAuthStorepour tests/sandbox ;createSqliteAuthStorepour persistance credentials/session danscore.db;- hash password/token, generation de tokens ;
- configuration
configureAuth({ cookieName, ownerPermissions }); - JWT HS256 via
joseet helperscreateSessionToken,verifySessionToken,getSession; - options cookie Hono/Next (
sessionCookieOptions,clearSessionCookieOptions,toHonoCookie) ; - middlewares Hono (
createHonoAuth) ; - routes Hono (
createAuthRoutes) : login/logout/me, impersonation, AI workspace session ; - composants React
LoginPage(page /login split-screen 50/50 : formulaire- panneau brand configuré par
ShellUiBrand.login, défaut neutre sans config),LoginForm,SessionProvider,useSession;
- panneau brand configuré par
- IPC Electron sur
IpcChannels.auth; - recovery key crypto reexportee depuis
@creezio/platform-core.
Ce qui reste dans la marque :
- nom de cookie et permissions owner ;
- source des users/roles/permissions (
ALL_NAV_PERMISSIONS,authenticateUser,listUsers, etc.) ; - prefixe et verification des API keys publiques ;
- resolution
securedes cookies derriere tunnel/proxy ; - contenu brand du panneau login (tagline, highlights, logo, gradient) via
loginsurCreezioUiBoot— le layout split-screen lui-même est kit ; - redirections post-login (
defaultRedirect,next) ; - config
@creezio/shell-uipour le bridge desktop UI ; - OAuth MCP (
src/lib/mcp-oauth.ts,src/server/mcp/oauth.ts) : cela appartient a@creezio/mcp-facade, pas a@creezio/auth.
Installation / build
npm install
npm run build -w @creezio/auth
npm run typecheck -w @creezio/authArtefacts :
- ESM :
dist/ - CJS Electron :
dist-cjs/ - UI source :
ui/
Dependances directes : @creezio/platform-core, @creezio/shell, @creezio/shell-ui, @hono/zod-openapi, hono, jose, zod. react, next et lucide-react sont des peer dependencies optionnelles pour ./ui.
Configuration
Configuration obligatoire au boot marque
import { configureAuth } from "@creezio/auth";
import { ALL_NAV_PERMISSIONS } from "@/lib/nav-config";
configureAuth({
cookieName: "mybrand_crm_session",
ownerPermissions: ALL_NAV_PERMISSIONS,
});cookieName est obligatoire avant tout appel a getSession, sessionCookieOptions ou createHonoAuth. ownerPermissions alimente les sessions owner et le mode AUTH_DISABLED.
Options complémentaires :
isSessionActive(session): vérification de l'état courant du compte après validation cryptographique, à chaque lecture du JWT. Seultrueautorise la session ;falseou une erreur du resolver la refuse. La surfaceapp-runtimele câble automatiquement au store plateforme : compte actif, rôle inchangé et acteur propriétaire actif en cas d'impersonation. Les cookies et Bearer déjà émis sont ainsi refusés dès la désactivation ; la réactivation rétablit les sessions encore valides. Sans adapter (usage autonome), la compatibilité JWT existante est conservée. Les flux par clé API et le mode de testAUTH_DISABLEDgardent leur contrat propre.userAdminPermission: les gardesPOST/PATCHusers acceptent le owner OU une session collaborateur portant cette permission (défaut : owner-only).resolveBrandRole(userId, db): rôle métier marque exposé en session (ex.backoffice,pos), résolu à la volée depuis la db métier de la marque — jamais stocké dans le JWT. Servi parGET /api/v1/auth/me(champbrand_role, résolu pour la cible en impersonation) et exposé côté UI viauseSession().me.brandRole(démo interactive par rôle, lanceurs conditionnels…). Option absente =brand_rolenull. Le wiringapp-runtimepasse automatiquement la db brand au resolver.
Variables lues par le kit :
| Variable | Usage |
|---|---|
| AUTH_SECRET | secret JWT HS256. En NODE_ENV=production, absent ou egal au fallback dev → signature ET verification refusees (fail-closed). Hors production, fallback dev insecure tolere avec erreur console (AUTH_ALLOW_DEV_SECRET=1 pour l'assumer). Les boots serveur kit le persistent par instance via composeBrandOs |
| AUTH_DISABLED | 1/true/yes cree une session owner virtuelle |
| AUTH_USER, AUTH_PASSWORD | credentials legacy/env pour compat et migration |
| AGENT_API_KEY | middleware agent key Hono |
| CREEZIO_CORE_DB_PATH / DB_PATH | store kit env via getKitAuthStore |
Store credentials SQLite core
import { createSqliteAuthStore } from "@creezio/auth";
import { resolveCoreDbPath } from "@creezio/platform-core";
const authStore = createSqliteAuthStore({
coreDbPath: resolveCoreDbPath(ctx),
});Le store execute AUTH_CORE_SQL, normalise les emails, hash les mots de passe et les tokens, purge les sessions expirees a la lecture.
Pour tests :
import { createMemoryAuthStore } from "@creezio/auth";
const authStore = createMemoryAuthStore();UI et bridge desktop
Le package auth ne configure pas window.*Desktop. Pour l'UI desktop, la marque configure @creezio/shell-ui :
import { configureShellUiBrand } from "@creezio/shell-ui";
configureShellUiBrand({
desktopApiGlobal: "mybrandDesktop",
productName: "Ma Marque",
});API publique (exports + exemples)
Config
Exports :
configureAuthgetAuthConfiggetAuthCookieNameresetAuthConfigForTests- type
AuthConfig
configureAuth({
cookieName: "certivan_crm_session",
cookieMaxAge: 60 * 60 * 24 * 14,
ownerPermissions: ALL_NAV_PERMISSIONS,
});Store, password et SQLite
Exports :
AUTH_CORE_SQLcreateMemoryAuthStore,createSqliteAuthStoreopenNodeSqliteDatabasehashPassword,verifyPassword,hashToken,newToken- types
AuthStore,AuthUser,AuthSession,AuthAccountPublic
const account = await authStore.register({
email: "[email protected]",
password: "secret",
displayName: "Owner",
});
const session = await authStore.login({
email: "[email protected]",
password: "secret",
stayLoggedIn: true,
});Session JWT / cookies
Exports :
isAuthDisabled,getAuthCredentials,validateEnvCredentialscreateSessionToken,createSessionTokenForUsername,verifySessionToken,getSessionsessionCookieOptions,clearSessionCookieOptions,toHonoCookiesessionActorIsOwner,sessionIsImpersonating,sessionCanAccessPath
import {
createSessionToken,
sessionCookieOptions,
toHonoCookie,
} from "@creezio/auth";
const token = await createSessionToken({ user });
const cookie = toHonoCookie(sessionCookieOptions(token, { secure: true }));getSession() lit les cookies Next via import dynamique de next/headers. En mode AUTH_DISABLED, il retourne une session owner virtuelle avec ownerPermissions.
Routes et middlewares Hono
import { createAuthRoutes, createHonoAuth } from "@creezio/auth";
import { resolveCookieSecure } from "@creezio/shell-ui";
import * as apiKeys from "@/lib/api-keys";
import * as users from "@/lib/users";
import { ALL_NAV_PERMISSIONS } from "@/lib/nav-config";
const honoAuth = createHonoAuth({
apiKeyPrefix: apiKeys.API_KEY_PREFIX,
verifyApiKey: apiKeys.verifyApiKey,
checkRateLimit: apiKeys.checkRateLimit,
rateLimitPerMinute: apiKeys.RATE_LIMIT_PER_MINUTE,
apiKeyAllowsMethod: apiKeys.apiKeyAllowsMethod,
apiKeyAllowsTasks: apiKeys.apiKeyAllowsTasks,
});
export const {
getSessionFromContext,
requireSession,
requireNavPermission,
requireOwnerNotImpersonating,
requireSessionOrAgentKey,
requireSessionOrApiKey,
requireSessionOrTasksApiKey,
} = honoAuth;
export const authRoutes = createAuthRoutes({
...users,
ownerPermissions: ALL_NAV_PERMISSIONS,
getSessionFromContext,
resolveCookieSecure: (c) =>
resolveCookieSecure(
{ get: (name) => c.req.header(name) ?? null },
{
appPublicUrl: process.env.APP_PUBLIC_URL,
appBaseUrl: process.env.APP_BASE_URL,
},
),
});Routes exposees par createAuthRoutes :
| Methode | Chemin | Rôle |
|---|---|---|
| POST | /login | authentifie, migre credentials kit si besoin, pose cookie |
| POST | /logout | supprime le cookie |
| GET | /me | session courante et permissions |
| POST | /impersonate | owner -> collaborateur/IA |
| POST | /stop-impersonate | retour au compte owner |
| POST | /ai-workspace-session | session workspace IA |
Middlewares exposes par createHonoAuth :
requireSessionrequireNavPermission(permission)requireOwnerNotImpersonatingrequireAgentKeyrequireSessionOrAgentKeyrequireSessionOrApiKeyrequireSessionOrTasksApiKeysiapiKeyAllowsTasksest fourni.
UI React
Page login mince :
import { redirect } from "next/navigation";
import { isAuthDisabled } from "@creezio/auth";
import { LoginForm } from "@creezio/auth/ui";
export default function LoginPage() {
if (isAuthDisabled()) redirect("/dashboard");
return <LoginForm title="Ma Marque CRM" />;
}Lien secondaire de la page login (optionnel) : LoginPage affiche sous
le formulaire un lien d'action secondaire quand la marque le configure via
ShellUiBrand.login.secondaryLink (CreezioUiBoot) — ex. inscription POS :
configureShellUiBrand({
login: {
secondaryLink: { label: "Créer un compte", href: "/inscription" },
},
});Clé absente = rien ne s'affiche (aucun défaut kit, aucun libellé hardcodé).
Session provider :
import { SessionProvider } from "@creezio/auth/ui";
import { ALL_NAV_PERMISSIONS } from "@/lib/nav-config";
export function Providers({ children }) {
return (
<SessionProvider ownerPermissions={ALL_NAV_PERMISSIONS}>
{children}
</SessionProvider>
);
}Consommation :
import { useSession } from "@creezio/auth/ui";
const { me, loading, refresh } = useSession();IPC Electron
Exports :
bindAuthIpcHandlersauthLoginWithStore- types
AuthIpcBindings,IpcHandleFn
import { bindAuthIpcHandlers } from "@creezio/auth";
const bindings = bindAuthIpcHandlers(ipcMain.handle.bind(ipcMain), authStore);Handlers generiques branches sur IpcChannels.auth : account, logout, stay logged in, change password, recovery key. googleLogin et recoverPassword restent des stubs documentes a brancher par la marque si necessaire.
Recovery
Reexports depuis @creezio/platform-core :
generateRecoveryKeynormalizeRecoveryKeycreateRecoveryVerifierverifyRecoveryKeywrapSecretsWithRecoveryKeyunwrapSecretsWithRecoveryKey
Flux / fonctionnement
- La marque appelle
configureAuthau boot. - Le store SQLite core cree ou lit les credentials depuis
creezio_users. createAuthRoutes().POST /logintente le login kit-first (authenticateViaKit), puis fallback marque/env, puis migration one-shot vers le store kit.- Une session JWT est signee avec
AUTH_SECRET, le cookie est pose avec le nom configure. createHonoAuthlit le cookie via Hono et place la session dans le contexte ou refuse.- Les permissions de navigation sont verifiees via
requireNavPermission. - L'UI
SessionProviderexpose/meau client React. - En desktop, IPC utilise le meme store pour account/logout/password/recovery.
Intégration marques
Checklist :
- Appeler
configureAuth({ cookieName, ownerPermissions })dans un fichier boot commun. - Initialiser le store SQLite core avec
createSqliteAuthStore. - Monter
createAuthRoutessous le prefixe auth de l'API Hono. - Exporter les middlewares
createHonoAuthpour proteger les routes API. - Remplacer les pages/forms locales par
LoginForm. - Remplacer le provider session local par
SessionProvider. - Utiliser
resolveCookieSecurede@creezio/shell-uipour les tunnels/proxies. - Brancher
bindAuthIpcHandlersdans Electron si l'app desktop utilise les canaux auth. - Laisser OAuth MCP dans
@creezio/mcp-facadeet lui injecter les helpers session auth.
Fichiers marque remplacés par le kit (ne pas les recréer) :
| Fichier marque | Remplacement |
|---|---|
| src/app/login/login-form.tsx | @creezio/auth/ui -> LoginForm |
| src/components/auth/session-provider.tsx | @creezio/auth/ui -> SessionProvider |
| src/lib/auth.ts | config + reexports minces |
| src/server/routes/auth.ts | createAuthRoutes(...) |
| src/server/hono-auth.ts | createHonoAuth(...) |
| electron/recovery-key.ts | reexports @creezio/platform-core via auth |
Dépendances @creezio/*
| Dependance | Rôle |
|---|---|
| @creezio/platform-core | recovery key crypto et chemins core DB cote marque |
| @creezio/shell | IpcChannels.auth pour Electron |
| @creezio/shell-ui | helpers cookie/origin et bridge desktop UI |
Interactions :
@creezio/mcp-facadeconsomme session/credentials auth pour OAuth MCP, mais reste proprietaire d'OAuth.- Les apps marques fournissent users, permissions et API keys.
Voir aussi → AGENTS.md + docs/FILES.md
AGENTS.md: consignes de modification pour agents.docs/FILES.md: inventaire fichier par fichier des exports et responsabilites.
