Sesiones + OAuth (GitHub, Google) con Drizzle, para Hono y Next.js
Código9 archivosContexto~670 tokensescaneo superado
Instalar
$
genpm add @core/authQué obtienes
- Código en src/lib/auth/, 9 archivos. (23,2 kB)
- Reglas de IA en src/lib/auth/AGENTS.md, más archivos de reglas para tu IDE.
- Variables añadidas a .env.example: AUTH_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET.
- Resuelve @core/db por ti.
README
Este paquete no tiene README.
~670 tokens→ src/lib/auth/AGENTS.md→ .cursor/rules/genpm-core-auth.mdc
Esto es exactamente lo que lee tu IA cuando trabaja en src/lib/auth. No se añade nada más a su contexto.
@core/auth — rules for AI agents
Purpose
Cookie sessions (random token, only its SHA-256 stored, 30-day sliding expiry, rotation) and OAuth login with GitHub
and Google via arctic. Tables: users, auth_sessions, oauth_accounts. No roles or permissions (out of scope:
build them in your app on top of users.id). No passwords.
Map
index.ts— public API:getUserFromCookieHeader,signOut,startOAuth,finishOAuth, session functions,User.adapters/hono.ts—sessionMiddleware,requireUser,authRoutes().adapters/next.ts—loginRoute,callbackRoute,logoutRoute,getUser(cookies).schema.ts— Drizzle tables. Depends on../db(@core/db).
Integration
- Env:
AUTH_SECRET(≥ 32 random chars, e.g.openssl rand -base64 32),GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET. Optional Google:GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET. Providers without both vars are disabled. - OAuth app callback URL:
<origin>/auth/callback/github(and/auth/callback/google). - Generate and apply migrations (see
src/lib/db/AGENTS.md). - Hono:
Next.js (App Router): createimport { authRoutes, requireUser, sessionMiddleware } from './lib/auth/adapters/hono.js'; app.use(sessionMiddleware); app.route('/auth', authRoutes()); app.get('/api/me', requireUser, (c) => c.json(c.get('user')));app/auth/login/[provider]/route.tswithexport { loginRoute as GET } from '@/lib/auth/adapters/next', the same forcallback/[provider](callbackRoute) andapp/auth/logout/route.ts(logoutRoute as POST). In Server Components:const user = await getUser(await cookies()). Delete the adapter of the framework you don't use (adapters/hono.tsimportshono). - Login link:
<a href="/auth/login/github?returnTo=/dashboard">. Logout:POST /auth/logout. - Verify: open
/auth/login/github, finish the flow, thenGET /api/mereturns the user.
Conventions
- Read the current user only through
sessionMiddleware/getUser; never parse the cookie yourself. - Other modules reference
users.id(text,usr_…) withonDelete: 'cascade'orset null. - Call
rotateSessionafter a privilege change andinvalidateUserSessionswhen an account is compromised. - If you installed
@core/dbwith--dest, fix the../db/index.jsimports here.
Don't
- Don't store or log session tokens, OAuth codes or
AUTH_SECRET. - Don't link accounts by unverified email;
upsertOAuthUseralready enforces it. - Don't accept absolute
returnToURLs (open redirect); usesafeReturnTo. - Don't make GET requests log users out, and don't disable
HttpOnly/SameSiteon the cookie.
# @core/auth — rules for AI agents
## Purpose
Cookie sessions (random token, only its SHA-256 stored, 30-day sliding expiry, rotation) and OAuth login with GitHub
and Google via `arctic`. Tables: `users`, `auth_sessions`, `oauth_accounts`. No roles or permissions (out of scope:
build them in your app on top of `users.id`). No passwords.
## Map
- `index.ts` — public API: `getUserFromCookieHeader`, `signOut`, `startOAuth`, `finishOAuth`, session functions, `User`.
- `adapters/hono.ts` — `sessionMiddleware`, `requireUser`, `authRoutes()`.
- `adapters/next.ts` — `loginRoute`, `callbackRoute`, `logoutRoute`, `getUser(cookies)`.
- `schema.ts` — Drizzle tables. Depends on `../db` (@core/db).
## Integration
1. Env: `AUTH_SECRET` (≥ 32 random chars, e.g. `openssl rand -base64 32`), `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`.
Optional Google: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`. Providers without both vars are disabled.
2. OAuth app callback URL: `<origin>/auth/callback/github` (and `/auth/callback/google`).
3. Generate and apply migrations (see `src/lib/db/AGENTS.md`).
4. Hono:
```ts
import { authRoutes, requireUser, sessionMiddleware } from './lib/auth/adapters/hono.js';
app.use(sessionMiddleware);
app.route('/auth', authRoutes());
app.get('/api/me', requireUser, (c) => c.json(c.get('user')));
```
Next.js (App Router): create `app/auth/login/[provider]/route.ts` with `export { loginRoute as GET } from '@/lib/auth/adapters/next'`,
the same for `callback/[provider]` (`callbackRoute`) and `app/auth/logout/route.ts` (`logoutRoute as POST`).
In Server Components: `const user = await getUser(await cookies())`.
Delete the adapter of the framework you don't use (`adapters/hono.ts` imports `hono`).
5. Login link: `<a href="/auth/login/github?returnTo=/dashboard">`. Logout: `POST /auth/logout`.
6. Verify: open `/auth/login/github`, finish the flow, then `GET /api/me` returns the user.
## Conventions
- Read the current user only through `sessionMiddleware`/`getUser`; never parse the cookie yourself.
- Other modules reference `users.id` (text, `usr_…`) with `onDelete: 'cascade'` or `set null`.
- Call `rotateSession` after a privilege change and `invalidateUserSessions` when an account is compromised.
- If you installed `@core/db` with `--dest`, fix the `../db/index.js` imports here.
## Don't
- Don't store or log session tokens, OAuth codes or `AUTH_SECRET`.
- Don't link accounts by unverified email; `upsertOAuthUser` already enforces it.
- Don't accept absolute `returnTo` URLs (open redirect); use `safeReturnTo`.
- Don't make GET requests log users out, and don't disable `HttpOnly`/`SameSite` on the cookie.
El árbol exacto que se inyectará, tras aplicar .genpmignore. Anclado a
// Adaptador Next.js (App Router). Sin importar `next`: usa Request/Response estándar.
// app/auth/login/[provider]/route.ts → export const GET = loginRoute;
// app/auth/callback/[provider]/route.ts → export const GET = callbackRoute;
// app/auth/logout/route.ts → export const POST = logoutRoute;
// Server Components: `const user = await getUser(await cookies())` (cookies de 'next/headers').
import { AuthError, enabledProviders, finishOAuth, getUserFromCookieHeader, type Provider, SESSION_COOKIE, signOut, startOAuth, type User } from '../index.js';
type Ctx = { params: Promise<{ provider: string }> };
type CookieStore = { get(name: string): { value: string } | undefined };
const isProvider = (p: string): p is Provider => (enabledProviders() as string[]).includes(p);
const json = (body: unknown, status: number) => Response.json(body, { status });
export async function loginRoute(req: Request, ctx: Ctx): Promise<Response> {
const { provider } = await ctx.params;
if (!isProvider(provider)) return json({ error: 'unknown_provider' }, 404);
const url = new URL(req.url);
const { url: to, setCookie } = startOAuth(provider, { origin: url.origin, returnTo: url.searchParams.get('returnTo') });
return new Response(null, { status: 302, headers: { location: to.toString(), 'set-cookie': setCookie } });
}
export async function callbackRoute(req: Request, ctx: Ctx): Promise<Response> {
const { provider } = await ctx.params;
if (!isProvider(provider)) return json({ error: 'unknown_provider' }, 404);
try {
const r = await finishOAuth(provider, { url: req.url, cookieHeader: req.headers.get('cookie') });
const headers = new Headers({ location: r.returnTo });
for (const c of r.setCookies) headers.append('set-cookie', c);
return new Response(null, { status: 302, headers });
} catch (e) {
if (e instanceof AuthError) return json({ error: e.code }, e.code === 'invalid_state' ? 400 : 502);
throw e;
}
}
export async function logoutRoute(req: Request): Promise<Response> {
return new Response(null, { status: 204, headers: { 'set-cookie': await signOut(req.headers.get('cookie')) } });
}
/** Usuario actual en Server Components / Route Handlers: `getUser(await cookies())`. */
export async function getUser(cookies: CookieStore): Promise<User | null> {
const token = cookies.get(SESSION_COOKIE)?.value;
return token ? getUserFromCookieHeader(`${SESSION_COOKIE}=${encodeURIComponent(token)}`) : null;
}
Este paquete no declara servidores MCP.
| Versión | Commit | Publicado | Escaneo |
|---|---|---|---|
| 1.0.0 | 12c4918 | hace 4 horas | ✔ escaneo superado |
- genpm
- @core/db ^1.0.0
- propuesta
- GenPM propone el comando npm y solo lo ejecuta si dices que sí.
- escaneo
- escaneo superado · 0 hallazgos
- commit
- v1.0.0 → 12c4918f68aa7cb6062a976347bf6a7d691cc218 · verificado tras la descarga
- scripts
- Ninguno. GenPM nunca ejecuta código del paquete.
- licencia
- MIT
- reporte
- ¿Ves algo raro?