
hono-authentication
by AgentiveCity
A skill factory for managing Claude Code skills
SKILL.md
name: "hono-authentication" description: "Use this skill whenever the user wants to design, implement, or refactor authentication and authorization in a Hono + TypeScript backend, including JWT, sessions/cookies, middleware, guards-like patterns, and route protection for Node/Edge/Workers runtimes."
Hono Authentication Skill
Purpose
You are a specialized assistant for authentication and authorization in Hono-based backends.
Use this skill to:
- Set up or refactor auth flows in a Hono + TypeScript project
- Implement JWT-based auth (access tokens, optional refresh)
- Implement cookie/session-based auth when appropriate
- Add auth middleware to protect routes
- Implement role/permission checks in a Hono-friendly way
- Integrate auth with different runtimes:
- Node (
@hono/node-server) - Cloudflare Workers
- Vercel Edge / Bun
- Node (
Do not use this skill for:
- Core Hono project scaffolding → use
hono-app-scaffold - Database design / ORM setup → use TypeORM / Supabase skills
- Frontend/Next.js auth – that’s a separate concern
If CLAUDE.md exists, follow any auth-related decisions there (JWT vs sessions, token lifetime, cookie security, etc.).
When To Apply This Skill
Trigger this skill when the user asks for things like:
- “Add auth to this Hono API.”
- “Protect these Hono routes with JWT.”
- “Implement login / signup / logout endpoints in Hono.”
- “Check roles on these Hono routes.”
- “Use cookies for authentication in a Hono app on Cloudflare/Node.”
- “Refactor this Hono auth middleware; it’s messy.”
Avoid this skill when:
- The task is purely about routing or performance without security considerations.
- The app’s auth is handled completely outside Hono (e.g., API gateway layer) and Hono only sees already-authenticated requests.
Default Auth Approach (Configurable)
By default, this skill prefers:
- JWT access tokens for API auth (stateless)
- Optional refresh token flow (often cookie-based)
Authorization: Bearer <token>header for protected routes- Auth middleware that:
- Decodes/validates tokens
- Attaches user info to
c.var(context variables)
- Role-based checks via helpers/middleware
Adjust based on project constraints:
- Cookies (httpOnly, secure) for browser-centric apps
- External identity providers (OAuth) at a high-level pattern
High-Level Architecture
Assume Hono app structure like:
src/
app.ts
routes/
v1/
auth.routes.ts
users.routes.ts
middlewares/
auth.ts
require-role.ts
config/
auth.ts
This skill will:
- Create or refine
auth.routes.tsfor login/signup/me endpoints - Create or refine
middlewares/auth.ts(JWT parsing & verification) - Optionally create
middlewares/require-role.tsfor roles/permissions - Use a configurable secret and token lifetime (env-based)
Config & Environment
Define auth-related config in a dedicated module where possible:
// src/config/auth.ts
export type AuthConfig = {
jwtSecret: string;
accessTokenTtlSeconds: number;
};
export function getAuthConfig(): AuthConfig {
return {
jwtSecret: process.env.JWT_SECRET || "dev-secret-change-me",
accessTokenTtlSeconds: Number(process.env.JWT_ACCESS_TTL ?? 15 * 60),
};
}
For Cloudflare Workers, use c.env with a typed Env interface instead of process.env.
Environment variables (example):
JWT_SECRET=super-secret-key
JWT_ACCESS_TTL=900
This skill must:
- Avoid hardcoding secrets for production
- Use correct env access method depending on runtime
JWT Utilities
Use a JWT library compatible with the runtime (e.g. jose is a good cross-runtime option).
Example helpers (Node/Workers-safe, using jose):
// src/middlewares/jwt-utils.ts
import { SignJWT, jwtVerify } from "jose";
export type JwtPayload = {
sub: string;
email?: string;
roles?: string[];
};
export async function signAccessToken(secret: string, payload: JwtPayload, ttlSeconds: number) {
const key = new TextEncoder().encode(secret);
const now = Math.floor(Date.now() / 1000);
return new SignJWT(payload)
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt(now)
.setExpirationTime(now + ttlSeconds)
.sign(key);
}
export async function verifyAccessToken(secret: string, token: string): Promise<JwtPayload> {
const key = new TextEncoder().encode(secret);
const { payload } = await jwtVerify<JwtPayload>(token, key);
return payload;
}
This skill should:
- Choose/correct the JWT library usage based on environment
- Use async-safe and Edge-compatible APIs where needed
Auth Middleware
Add a middleware that:
- Extracts JWT from
Authorizationheader (or cookie if configured) - Verifies it
- Attaches user info to
c.var
Example:
// src/middlewares/auth.ts
import type { MiddlewareHandler } from "hono";
import { getAuthConfig } from "../config/auth";
import { verifyAccessToken } from "./jwt-utils";
export type AuthUser = {
id: string;
email?: string;
roles?: string[];
};
declare module "hono" {
interface ContextVariableMap {
user?: AuthUser;
}
}
export const authMiddleware: MiddlewareHandler = async (c, next) => {
const authHeader = c.req.header("Authorization");
if (!authHeader?.startsWith("Bearer ")) {
// unauthenticated, let protected routes handle this
return c.json({ message: "Unauthorized" }, 401);
}
const token = authHeader.slice("Bearer ".length);
const config = getAuthConfig();
try {
const payload = await verifyAccessToken(config.jwtSecret, token);
c.set("user", {
id: payload.sub,
email: payload.email,
roles: payload.roles ?? [],
});
await next();
} catch (err) {
console.error("JWT validation failed:", err);
return c.json({ message: "Unauthorized" }, 401);
}
};
Alternative: For some apps, you may want a “soft” auth that sets user only when token exists, allowing both public and authenticated access. This skill can implement that variant too.
Role-Based Authorization
Implement a helper middleware to require certain roles:
// src/middlewares/require-role.ts
import type { MiddlewareHandler } from "hono";
export function requireRole(requiredRoles: string[]): MiddlewareHandler {
return async (c, next) => {
const user = c.get("user");
if (!user) {
return c.json({ message: "Unauthorized" }, 401);
}
const hasRole = user.roles?.some((role) => requiredRoles.includes(role));
if (!hasRole) {
return c.json({ message: "Forbidden" }, 403);
}
await next();
};
}
Usage in routes:
import { authMiddleware } from "../../middlewares/auth";
import { requireRole } from "../../middlewares/require-role";
app.get(
"/admin/stats",
authMiddleware,
requireRole(["admin"]),
(c) => c.json({ ok: true }),
);
This skill should:
- Encourage composition (
authMiddleware+requireRole) per route/route-group - Avoid hardcoding roles in many places; centralize where possible
Auth Routes
Create an auth.routes.ts under versioned routes (e.g., /v1/auth):
// src/routes/v1/auth.routes.ts
import { Hono } from "hono";
import { getAuthConfig } from "../../config/auth";
import { signAccessToken } from "../../middlewares/jwt-utils";
// In a real app, inject or import user storage/service
async function findUserByEmail(email: string) {
// TODO: use real DB lookup (TypeORM, Supabase, etc.)
return null as any;
}
export function authRoutes() {
const app = new Hono();
app.post("/login", async (c) => {
const body = await c.req.json<{ email: string; password: string }>();
// Validate inputs (this skill may integrate with a Hono validation skill later)
if (!body.email || !body.password) {
return c.json({ message: "Email and password are required" }, 400);
}
const user = await findUserByEmail(body.email);
if (!user) {
return c.json({ message: "Invalid credentials" }, 401);
}
// TODO: verify password using bcrypt/argon2 library
const config = getAuthConfig();
const accessToken = await signAccessToken(
config.jwtSecret,
{
sub: user.id,
email: user.email,
roles: user.roles ?? [],
},
config.accessTokenTtlSeconds,
);
return c.json({ accessToken });
});
app.get("/me", async (c) => {
const user = c.get("user");
if (!user) {
return c.json({ message: "Unauthorized" }, 401);
}
return c.json(user);
});
return app;
}
In routes/v1/index.ts, mount them:
import { authRoutes } from "./auth.routes";
export function createV1Routes() {
const app = new Hono();
app.route("/auth", authRoutes());
// other routes
return app;
}
This skill should:
- Keep auth routes small and composable.
- Defer actual user storage to DB/ORM skills.
Cookies & Sessions (Optional Variation)
For browser-centric apps, this skill can:
- Set
httpOnly,securecookies with tokens on login. - Read them from
c.req.cookie()(orc.req.header('Cookie')) in middleware.
Example sketch:
// login route snippet
c.header(
"Set-Cookie",
`access_token=${accessToken}; HttpOnly; Secure; Path=/; Max-Age=${config.accessTokenTtlSeconds}`,
);
return c.json({ ok: true });
Middleware variant:
const token = c.req.cookie("access_token");
Adjust for runtime (Workers vs Node) and security (HTTPS only, domain, same-site).
Integration with Other Skills
hono-app-scaffold:- This skill assumes a structured app with
routes/&middlewares/ready to extend.
- This skill assumes a structured app with
hono-typeorm-backend(future):- Provides user entity + repository; this auth skill will call into those.
nestjs-authentication(conceptual similarities):- Shares patterns for JWT, roles, and password handling.
Example Prompts That Should Use This Skill
- “Add JWT auth middleware and protect
/v1/usersroutes.” - “Implement login and
GET /mein this Hono API.” - “Use roles and protect admin routes in Hono.”
- “Switch auth from header-based to cookie-based for browser clients.”
- “Refactor our ad-hoc Hono auth into a clean middleware + routes setup.”
For these tasks, rely on this skill to build a clean, composable, runtime-aware auth layer for Hono, integrating with your chosen user storage, ORM, and deployment environment.
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon