Authentication overview
Covara ships a complete authentication and authorization stack. There are two ways to authenticate users, and one consistent way to authorize them.
Follow the Auth quickstart — the fastest path to email/password (with email confirmation) plus GitHub social login, and the one table you actually need to create.
Two authentication approaches
| Approach | Use when | Page |
|---|---|---|
| OIDC provider | You want a standards-based identity server (OAuth2/OIDC, PKCE, federated login, JWT access tokens) for one or many apps. | OIDC provider |
Session-based useAuth | You want classic email/password sessions with cookies, the fastest path to login/signup/logout. | Sessions |
Both populate the same request context, so authorization scopes, subscriptions, and the client useAuth hook work identically regardless of which you choose.
On top of either approach you can layer: social login (sign in with GitHub/Discord/Google/… via any Passport.js strategy), JWT tokens, federated login, API keys, MFA/TOTP, magic links, a password policy, and account-security flows (CSRF, login throttling, email verification, password reset).
The request user
After auth middleware runs, the authenticated user is available in any Hono handler:
import { getUser, requireUser, getSession } from "covara";
app.get("/api/profile", (c) => {
const user = requireUser(c); // throws 401 if absent
return c.json(user);
});
getUser(c) returns the user or null; requireUser(c) throws an UnauthorizedError; getSession(c) returns the session. These read from Hono's typed ContextVariableMap (user, session, requestId, apiVersion).
Quick session setup
useAuth decouples how the identity is persisted (a session strategy — cookieSession or jwtSession) from who the user is (credential providers — login, signup, social, …), so any provider composes with any session type.
import { createCovara, cookieSession, useAuth, hashPassword, verifyPassword } from "covara";
import { eq } from "drizzle-orm";
const auth = useAuth({
// swap for jwtSession({ secret, getUserById }) to issue JWTs instead
session: cookieSession({
getUserById: async (id) => db.query.users.findFirst({ where: eq(users.id, id) }),
}),
login: {
validateCredentials: async (email, password) => {
const user = await db.query.users.findFirst({ where: eq(users.email, email) });
return user && (await verifyPassword(password, user.passwordHash))
? { id: user.id, email: user.email, name: user.name }
: null;
},
},
signup: {
createUser: async ({ email, password, name }) => {
const [u] = await db.insert(users)
.values({ id: crypto.randomUUID(), email, name, passwordHash: await hashPassword(password) })
.returning();
return { id: u.id, email: u.email, name: u.name };
},
},
});
const app = createCovara({ auth }); // mounts /api/auth/* and the middleware
This creates four routes:
| Route | Method | Description |
|---|---|---|
/api/auth/me | GET | Current user, or { user: null } |
/api/auth/login | POST | Email/password login |
/api/auth/signup | POST | Create account |
/api/auth/logout | POST | Clear session |
Full options and adapters: Sessions.
Route guards
import { requireAuth, requireRole, requirePermission, getUser } from "covara";
app.get("/profile", requireAuth(), (c) => c.json(getUser(c)));
app.get("/admin", requireRole("admin"), (c) => c.json({ ok: true }));
app.post("/posts", requirePermission("posts:create"), async (c) => { /* ... */ });
Authorization
Authentication answers who is this; authorization answers what can they touch. Covara enforces row-level access with RSQL scopes on every read, write, subscription, and search — combined with the request filter and impossible to bypass from the client. See Authorization scopes and Secure queries.
Client-side useAuth
The React useAuth hook exposes the auth state and supports several strategies — cookie sessions, JWT, bearer token, API key, or auto-detect:
import { useAuth } from "covara/client/react";
function App() {
const { user, isAuthenticated, isLoading, logout } = useAuth<User>();
if (isLoading) return <div>Loading…</div>;
if (!isAuthenticated) return <LoginPage />;
return <button onClick={logout}>Sign out {user?.name}</button>;
}
See Client auth for every strategy and the OIDC PKCE flow.
Related
- Quickstart · Sessions · Social login · JWT · OIDC provider · Federated login
- Scopes · Secure queries · Passwords
- Auth contract — the threat model and guarantees