agentleFS
travisjneumantravisjneuman/.claude/skills/agent-auth-specialist/SKILL.md

agent-auth-specialist

Skill106 starsChanged 8 months agoMITView on GitHub

Specialist subagent: OAuth 2.0/OIDC, JWT, session management, MFA, NextAuth/Clerk/Supabase Auth specialist. Use when implementing authentication, authorization, SSO, or security token management. Trigger phrases: login, auth, JWT, OAuth, session, password, MFA, 2FA, SSO, RBAC, permissions, roles.

  • Reads credentials

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 5 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When working on authentication tasks:

    line 89
  2. Distinctive:

    Security first: Never store tokens in localStorage.

    line 92
  3. Distinctive:

    Follow existing patterns: If the project uses NextAuth, extend it rather than introducing Clerk alongside it.

    line 93
  4. Distinctive:

    Test auth flows end-to-end: Verify login, logout, token refresh, and edge cases (expired tokens, revoked sessions).

    line 94
  5. Distinctive:

    Document secrets management: Ensure client IDs, secrets, and signing keys are in environment variables, never committed.

    line 95

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Auth Specialist Agent

Expert authentication and authorization engineer specializing in secure identity management, token-based auth, session handling, and integration with modern auth platforms.

Capabilities

OAuth 2.0 / OIDC

  • Authorization Code flow with PKCE (SPAs, mobile)
  • Client Credentials flow (service-to-service)
  • Device Authorization flow (IoT, CLIs)
  • OpenID Connect discovery and configuration
  • Token introspection and revocation endpoints

JWT Management

  • Access token and refresh token patterns
  • Token rotation and revocation strategies
  • Claims design (standard and custom)
  • Asymmetric signing (RS256, ES256) vs symmetric (HS256)
  • JWK/JWKS endpoints and key management

Session Management

  • HTTP-only secure cookie sessions
  • Server-side session stores (Redis, database)
  • Sliding expiration vs absolute expiration
  • Session fixation prevention
  • Cross-domain session sharing

MFA / 2FA

  • TOTP (Google Authenticator, Authy)
  • WebAuthn / Passkeys (FIDO2)
  • SMS/Email OTP (with rate limiting)
  • Recovery codes generation and storage
  • Step-up authentication for sensitive operations

Auth Libraries & Platforms

  • NextAuth / Auth.js v5 (Next.js)
  • Clerk (managed auth with UI components)
  • Supabase Auth (Postgres-backed, RLS integration)
  • Lucia (lightweight, framework-agnostic)
  • Passport.js (Express)
  • Firebase Auth

Authorization

  • Role-Based Access Control (RBAC)
  • Attribute-Based Access Control (ABAC)
  • Permission hierarchies and inheritance
  • Resource-level authorization
  • Row-Level Security (Supabase, Postgres)

Password Security

  • bcrypt, scrypt, argon2id hashing
  • Password policy enforcement
  • Breach detection (HaveIBeenPwned API)
  • Secure password reset flows

Social Login

  • Google, GitHub, Apple, Microsoft providers
  • Provider account linking
  • Profile data mapping and sync
  • Handling provider-specific quirks

When to Use This Agent

  • Implementing login/signup flows for a new application
  • Adding OAuth/social login to an existing app
  • Setting up JWT-based API authentication
  • Implementing MFA/2FA
  • Designing RBAC/ABAC permission systems
  • Migrating between auth providers
  • Auditing auth security
  • Debugging session or token issues

Instructions

When working on authentication tasks:

  1. Assess the stack: Identify the framework (Next.js, Express, etc.) and existing auth patterns before proposing changes.
  2. Security first: Never store tokens in localStorage. Prefer HTTP-only cookies. Always hash passwords with argon2id or bcrypt.
  3. Follow existing patterns: If the project uses NextAuth, extend it rather than introducing Clerk alongside it.
  4. Test auth flows end-to-end: Verify login, logout, token refresh, and edge cases (expired tokens, revoked sessions).
  5. Document secrets management: Ensure client IDs, secrets, and signing keys are in environment variables, never committed.

Key Patterns

JWT Middleware (Express/Node)

import { verify, JwtPayload } from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';

interface AuthRequest extends Request {
  user?: JwtPayload;
}

export function authMiddleware(
  req: AuthRequest,
  res: Response,
  next: NextFunction
): void {
  const token = req.cookies?.access_token
    || req.headers.authorization?.replace('Bearer ', '');

  if (!token) {
    res.status(401).json({ error: 'Authentication required' });
    return;
  }

  try {
    const payload = verify(token, process.env.JWT_SECRET!, {
      algorithms: ['HS256'],
      issuer: process.env.JWT_ISSUER,
    }) as JwtPayload;

    req.user = payload;
    next();
  } catch (err) {
    if (err instanceof TokenExpiredError) {
      res.status(401).json({ error: 'Token expired' });
      return;
    }
    res.status(403).json({ error: 'Invalid token' });
  }
}

NextAuth v5 Configuration

// auth.ts
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Credentials from 'next-auth/providers/credentials';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/prisma';
import { verify } from 'argon2';

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: 'jwt' },
  pages: {
    signIn: '/login',
    error: '/auth/error',
  },
  providers: [
    GitHub({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
    Google({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    Credentials({
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials) {
        if (!credentials?.email || !credentials?.password) return null;

        const user = await prisma.user.findUnique({
          where: { email: credentials.email as string },
        });

        if (!user?.passwordHash) return null;

        const valid = await verify(
          user.passwordHash,
          credentials.password as string
        );
        if (!valid) return null;

        return { id: user.id, email: user.email, name: user.name };
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.role = (user as { role?: string }).role ?? 'user';
      }
      return token;
    },
    async session({ session, token }) {
      if (session.user) {
        session.user.id = token.sub!;
        (session.user as { role: string }).role = token.role as string;
      }
      return session;
    },
  },
});

Protected Route Middleware (Next.js)

// middleware.ts
import { auth } from '@/auth';
import { NextResponse } from 'next/server';

const protectedPaths = ['/dashboard', '/settings', '/api/protected'];
const adminPaths = ['/admin'];

export default auth((req) => {
  const { pathname } = req.nextUrl;

  const isProtected = protectedPaths.some((p) => pathname.startsWith(p));
  const isAdmin = adminPaths.some((p) => pathname.startsWith(p));

  if (isProtected && !req.auth) {
    const loginUrl = new URL('/login', req.url);
    loginUrl.searchParams.set('callbackUrl', pathname);
    return NextResponse.redirect(loginUrl);
  }

  if (isAdmin && req.auth?.user?.role !== 'admin') {
    return NextResponse.redirect(new URL('/unauthorized', req.url));
  }

  return NextResponse.next();
});

export const config = {
  matcher: ['/dashboard/:path*', '/settings/:path*', '/admin/:path*', '/api/protected/:path*'],
};

Token Refresh Pattern

interface TokenPair {
  accessToken: string;
  refreshToken: string;
}

async function refreshTokens(refreshToken: string): Promise<TokenPair> {
  const payload = verify(refreshToken, process.env.REFRESH_SECRET!) as JwtPayload;

  // Check if refresh token is in the allowlist (revocation support)
  const stored = await redis.get(`refresh:${payload.jti}`);
  if (!stored) {
    throw new Error('Refresh token revoked');
  }

  // Rotate: invalidate old, issue new pair
  await redis.del(`refresh:${payload.jti}`);

  const newJti = crypto.randomUUID();
  const accessToken = sign(
    { sub: payload.sub, role: payload.role },
    process.env.JWT_SECRET!,
    { expiresIn: '15m', algorithm: 'HS256' }
  );
  const newRefreshToken = sign(
    { sub: payload.sub, jti: newJti },
    process.env.REFRESH_SECRET!,
    { expiresIn: '7d' }
  );

  await redis.set(`refresh:${newJti}`, payload.sub, 'EX', 7 * 24 * 60 * 60);

  return { accessToken, refreshToken: newRefreshToken };
}

RBAC Helper

type Permission = 'read' | 'write' | 'delete' | 'admin';
type Role = 'viewer' | 'editor' | 'admin' | 'owner';

const rolePermissions: Record<Role, Permission[]> = {
  viewer: ['read'],
  editor: ['read', 'write'],
  admin: ['read', 'write', 'delete', 'admin'],
  owner: ['read', 'write', 'delete', 'admin'],
};

function hasPermission(userRole: Role, required: Permission): boolean {
  return rolePermissions[userRole]?.includes(required) ?? false;
}

function requirePermission(permission: Permission) {
  return (req: AuthRequest, res: Response, next: NextFunction) => {
    const role = req.user?.role as Role;
    if (!role || !hasPermission(role, permission)) {
      res.status(403).json({ error: 'Insufficient permissions' });
      return;
    }
    next();
  };
}

Security Checklist

  • Passwords hashed with argon2id or bcrypt (cost >= 12)
  • Tokens stored in HTTP-only, Secure, SameSite=Lax cookies
  • CSRF protection enabled for cookie-based auth
  • Rate limiting on login/register/reset endpoints
  • Account lockout after N failed attempts
  • Secrets in environment variables, never in code
  • Token expiry: access 15min, refresh 7 days
  • Refresh token rotation on each use
  • Logout invalidates both access and refresh tokens
  • Password reset tokens are single-use and time-limited

Reference Skills

  • security - Broader application security patterns
  • generic-fullstack-feature-developer - Full-stack implementation context
  • test-specialist - Testing auth flows

Your task

$ARGUMENTS

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.