AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Authentication Patterns

skill-bradtaylorsf-alphaagent-team-authentication-patterns · by bradtaylorsf

Patterns for implementing authentication and authorization in backend applications

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-bradtaylorsf-alphaagent-team-authentication-patterns

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-bradtaylorsf-alphaagent-team-authentication-patterns)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
6mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Authentication Patterns? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Authentication Patterns Skill

Patterns for implementing secure authentication and authorization.

Authentication Methods

JWT (JSON Web Tokens)

import jwt from 'jsonwebtoken';

const JWT_SECRET = process.env.JWT_SECRET!;
const JWT_EXPIRES_IN = '15m';
const REFRESH_TOKEN_EXPIRES_IN = '7d';

// Generate tokens
function generateTokens(userId: string) {
  const accessToken = jwt.sign(
    { userId, type: 'access' },
    JWT_SECRET,
    { expiresIn: JWT_EXPIRES_IN }
  );

  const refreshToken = jwt.sign(
    { userId, type: 'refresh' },
    JWT_SECRET,
    { expiresIn: REFRESH_TOKEN_EXPIRES_IN }
  );

  return { accessToken, refreshToken };
}

// Verify token
function verifyToken(token: string): JwtPayload {
  return jwt.verify(token, JWT_SECRET) as JwtPayload;
}

// Refresh token endpoint
app.post('/auth/refresh', async (req, res) => {
  const { refreshToken } = req.body;

  try {
    const payload = verifyToken(refreshToken);

    if (payload.type !== 'refresh') {
      throw new Error('Invalid token type');
    }

    // Check if refresh token is still valid in database
    const storedToken = await getStoredRefreshToken(refreshToken);
    if (!storedToken || storedToken.revoked) {
      throw new Error('Token revoked');
    }

    // Generate new tokens
    const tokens = generateTokens(payload.userId);

    // Revoke old refresh token
    await revokeRefreshToken(refreshToken);

    // Store new refresh token
    await storeRefreshToken(tokens.refreshToken, payload.userId);

    res.json(tokens);
  } catch (error) {
    res.status(401).json({ error: 'Invalid refresh token' });
  }
});

API Keys

// Generate API key
function generateApiKey(): string {
  return `sk_${crypto.randomBytes(32).toString('hex')}`;
}

// Hash API key for storage
function hashApiKey(key: string): string {
  return crypto.createHash('sha256').update(key).digest('hex');
}

// Validate API key
async function validateApiKey(key: string) {
  const hash = hashApiKey(key);
  const apiKey = await prisma.apiKey.findUnique({
    where: { hash },
    include: { user: true },
  });

  if (!apiKey || apiKey.revoked || apiKey.expiresAt  {
  try {
    // Find or create user
    let user = await prisma.user.findUnique({
      where: { googleId: profile.id },
    });

    if (!user) {
      user = await prisma.user.create({
        data: {
          googleId: profile.id,
          email: profile.emails?.[0].value,
          name: profile.displayName,
        },
      });
    }

    done(null, user);
  } catch (error) {
    done(error);
  }
}));

// Routes
app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

app.get('/auth/google/callback',
  passport.authenticate('google', { session: false }),
  (req, res) => {
    const tokens = generateTokens(req.user.id);
    res.redirect(`/auth/callback?token=${tokens.accessToken}`);
  }
);

Authorization Patterns

Role-Based Access Control (RBAC)

// Define roles and permissions
const PERMISSIONS = {
  admin: ['read', 'write', 'delete', 'manage-users'],
  editor: ['read', 'write'],
  viewer: ['read'],
} as const;

type Role = keyof typeof PERMISSIONS;
type Permission = (typeof PERMISSIONS)[Role][number];

// Check permission middleware
function requirePermission(permission: Permission) {
  return (req: Request, res: Response, next: NextFunction) => {
    const userRole = req.user?.role as Role;

    if (!userRole || !PERMISSIONS[userRole]?.includes(permission)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }

    next();
  };
}

// Usage
app.delete('/users/:id',
  authenticate,
  requirePermission('delete'),
  userController.delete
);

Attribute-Based Access Control (ABAC)

// Policy definition
interface Policy {
  action: string;
  resource: string;
  condition: (user: User, resource: any) => boolean;
}

const policies: Policy[] = [
  {
    action: 'update',
    resource: 'post',
    condition: (user, post) => post.authorId === user.id || user.role === 'admin',
  },
  {
    action: 'delete',
    resource: 'post',
    condition: (user, post) => post.authorId === user.id || user.role === 'admin',
  },
];

// Check policy
function can(user: User, action: string, resource: string, resourceData?: any): boolean {
  const policy = policies.find(p => p.action === action && p.resource === resource);

  if (!policy) {
    return false;
  }

  return policy.condition(user, resourceData);
}

// Middleware
function authorize(action: string, resource: string, getResource: (req: Request) => Promise) {
  return async (req: Request, res: Response, next: NextFunction) => {
    const resourceData = await getResource(req);

    if (!can(req.user, action, resource, resourceData)) {
      return res.status(403).json({ error: 'Access denied' });
    }

    req.resource = resourceData;
    next();
  };
}

// Usage
app.put('/posts/:id',
  authenticate,
  authorize('update', 'post', (req) => prisma.post.findUnique({ where: { id: req.params.id } })),
  postController.update
);

Resource Ownership

// Check ownership middleware
async function checkOwnership(req: Request, res: Response, next: NextFunction) {
  const resource = await prisma.post.findUnique({
    where: { id: req.params.id },
  });

  if (!resource) {
    return res.status(404).json({ error: 'Resource not found' });
  }

  // Allow if owner or admin
  if (resource.userId !== req.user.id && req.user.role !== 'admin') {
    return res.status(403).json({ error: 'Access denied' });
  }

  req.resource = resource;
  next();
}

Security Best Practices

Password Hashing

import bcrypt from 'bcrypt';

const SALT_ROUNDS = 12;

async function hashPassword(password: string): Promise {
  return bcrypt.hash(password, SALT_ROUNDS);
}

async function verifyPassword(password: string, hash: string): Promise {
  return bcrypt.compare(password, hash);
}

Secure Headers

import helmet from 'helmet';

app.use(helmet());
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    scriptSrc: ["'self'"],
    imgSrc: ["'self'", 'data:', 'https:'],
  },
}));

CORS Configuration

import cors from 'cors';

app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key'],
}));

Rate Limiting by User

import rateLimit from 'express-rate-limit';

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts
  message: { error: 'Too many login attempts' },
  keyGenerator: (req) => req.body.email || req.ip,
});

app.post('/auth/login', authLimiter, authController.login);

Session Management

// Secure session configuration
import session from 'express-session';
import RedisStore from 'connect-redis';

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET!,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === 'production',
    httpOnly: true,
    maxAge: 24 * 60 * 60 * 1000, // 24 hours
    sameSite: 'strict',
  },
}));

Integration

Used by:

  • backend-developer agent
  • All backend stack skills

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.