Sessions + OAuth (GitHub, Google) with Drizzle, for Hono and Next.js
Code9 filesContext~670 tokensscan passed
Install
$
genpm add @core/authWhat you get
- Source in src/lib/auth/, 9 files. (23.2 kB)
- AI rules in src/lib/auth/AGENTS.md, plus IDE rule files.
- Env vars added to .env.example: AUTH_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET.
- Resolves @core/db for you.
README
This package has no README.
~670 tokens→ src/lib/auth/AGENTS.md→ .cursor/rules/genpm-core-auth.mdc
This is exactly what your AI reads when it works in src/lib/auth. Nothing else is added to its context.
@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.
The exact tree that will be injected, after .genpmignore. Pinned to
// Adaptador Hono: `app.route('/auth', authRoutes())`, `app.use(sessionMiddleware)` y `requireUser` en rutas privadas.
import type { MiddlewareHandler } from 'hono';
import { Hono } from 'hono';
import { AuthError, enabledProviders, finishOAuth, getUserFromCookieHeader, type Provider, signOut, startOAuth, type User } from '../index.js';
export type AuthVariables = { user: User | null };
/** Carga `c.get('user')` (o null) en cada petición. */
export const sessionMiddleware: MiddlewareHandler<{ Variables: AuthVariables }> = async (c, next) => {
c.set('user', await getUserFromCookieHeader(c.req.header('cookie')));
await next();
};
/** 401 si no hay usuario. Úsalo después de `sessionMiddleware`. */
export const requireUser: MiddlewareHandler<{ Variables: AuthVariables }> = async (c, next) => {
if (!c.get('user')) return c.json({ error: 'unauthorized' }, 401);
await next();
};
const isProvider = (p: string): p is Provider => (enabledProviders() as string[]).includes(p);
/** GET /login/:provider?returnTo=/x · GET /callback/:provider · POST /logout. Monta en '/auth'. */
export function authRoutes() {
return new Hono()
.get('/login/:provider', (c) => {
const provider = c.req.param('provider');
if (!isProvider(provider)) return c.json({ error: 'unknown_provider' }, 404);
const { url, setCookie } = startOAuth(provider, { origin: new URL(c.req.url).origin, returnTo: c.req.query('returnTo') });
c.header('set-cookie', setCookie);
return c.redirect(url.toString(), 302);
})
.get('/callback/:provider', async (c) => {
const provider = c.req.param('provider');
if (!isProvider(provider)) return c.json({ error: 'unknown_provider' }, 404);
try {
const r = await finishOAuth(provider, { url: c.req.url, cookieHeader: c.req.header('cookie') });
for (const cookie of r.setCookies) c.header('set-cookie', cookie, { append: true });
return c.redirect(r.returnTo, 302);
} catch (e) {
if (e instanceof AuthError) return c.json({ error: e.code }, e.code === 'invalid_state' ? 400 : 502);
throw e;
}
})
.post('/logout', async (c) => {
c.header('set-cookie', await signOut(c.req.header('cookie')));
return c.body(null, 204);
});
}
This package declares no MCP servers.
| Version | Commit | Published | Scan |
|---|---|---|---|
| 1.0.0 | 12c4918 | 3 hours ago | ✔ scan passed |
- genpm
- @core/db ^1.0.0
- proposed
- GenPM proposes the npm command and runs it only if you say yes.
- scan
- scan passed · 0 findings
- commit
- v1.0.0 → 12c4918f68aa7cb6062a976347bf6a7d691cc218 · verified after fetch
- scripts
- None. GenPM never runs package code.
- license
- MIT
- report
- See something wrong?