Token导航 LogoToken导航TokenDH.com
开发敏感数据github未标认证来源可访问clear审计通过

jwt-securityJWT 安全

Agent Skill

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

总安装

13,991

周安装

601

GitHub Stars

87

下载量

4,904
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:jwt-security(JWT 安全)
来源仓库:https://github.com/mindrally/skills
仓库路径:skills/jwt-security
安装命令:
npx skills add https://github.com/mindrally/skills --skill jwt-security
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/mindrally/skills --skill jwt-security

简介

jwt-security 用于辅助安全审计、权限检查和认证流程分析。

  • 适合梳理敏感配置、检查依赖风险或生成安全复核清单。
  • 使用时不能把工具输出直接当最终结论。
  • 安装命令:npx skills add https://github.com/mindrally/skills --skill jwt-security
  • 涉及密钥或用户数据时应确认最小权限和操作边界。

SKILL.md

JWT Security

You are an expert in JSON Web Token (JWT) security implementation. Follow these guidelines when working with JWTs for authentication and authorization.

Core Principles

  • JWTs are not inherently secure - security depends on implementation
  • Always validate tokens server-side, even for internal services
  • Use asymmetric signing (RS256, ES256) when possible
  • Keep tokens short-lived and implement proper refresh mechanisms
  • Never store sensitive data in JWT payloads

Token Structure

A JWT consists of three parts: Header, Payload, and Signature.

header.payload.signature

Header Best Practices

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-identifier-for-rotation"
}
  • Always include kid (key ID) for key rotation support
  • Use typ: "JWT" explicitly
  • Never accept alg: "none"

Payload Best Practices

{
  "iss": "https://auth.example.com",
  "sub": "user-uuid-here",
  "aud": "https://api.example.com",
  "exp": 1704067200,
  "iat": 1704063600,
  "nbf": 1704063600,
  "jti": "unique-token-id"
}

Required claims:

  • iss (issuer): Who created the token
  • sub (subject): Who the token represents
  • aud (audience): Who the token is intended for
  • exp (expiration): When the token expires
  • iat (issued at): When the token was created

Recommended claims:

  • nbf (not before): Token not valid before this time
  • jti (JWT ID): Unique identifier for token revocation

Signing Algorithm Selection

Recommended: Asymmetric Algorithms

// RS256 - RSA with SHA-256 (most widely supported)
// ES256 - ECDSA with P-256 and SHA-256 (smaller keys)
// EdDSA - Edwards-curve Digital Signature Algorithm (most secure)

const ALLOWED_ALGORITHMS = ['RS256', 'ES256', 'EdDSA'];

When Symmetric is Required

// HS256 - HMAC with SHA-256
// Only use with a strong secret (minimum 256 bits / 32 bytes)
const secret = crypto.randomBytes(64).toString('hex');

Token Creation

Using RS256 (Recommended)

const jwt = require('jsonwebtoken');
const fs = require('fs');

const privateKey = fs.readFileSync('private.pem');

function createToken(userId, roles) {
  const payload = {
    sub: userId,
    roles: roles,
    // Keep custom claims minimal
  };

  const options = {
    algorithm: 'RS256',
    expiresIn: '15m', // Short-lived access tokens
    issuer: 'https://auth.example.com',
    audience: 'https://api.example.com',
    keyid: 'current-key-id',
  };

  return jwt.sign(payload, privateKey, options);
}

Token Lifetime Guidelines

const TOKEN_LIFETIMES = {
  accessToken: '15m',      // 15 minutes max
  refreshToken: '7d',      // 7 days with rotation
  idToken: '1h',           // 1 hour
  passwordReset: '15m',    // 15 minutes
  emailVerification: '24h', // 24 hours
};

Token Validation

Complete Validation Example

const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

// JWKS client for fetching public keys
const client = jwksClient({
  jwksUri: 'https://auth.example.com/.well-known/jwks.json',
  cache: true,
  cacheMaxAge: 600000, // 10 minutes
  rateLimit: true,
  jwksRequestsPerMinute: 10,
});

async function validateToken(token) {
  // 1. Decode header without verification to get kid
  const decoded = jwt.decode(token, { complete: true });

  if (!decoded) {
    throw new Error('Invalid token format');
  }

  // 2. Validate algorithm against whitelist
  if (!ALLOWED_ALGORITHMS.includes(decoded.header.alg)) {
    throw new Error(`Algorithm ${decoded.header.alg} not allowed`);
  }

  // 3. Get signing key
  const key = await client.getSigningKey(decoded.header.kid);
  const publicKey = key.getPublicKey();

  // 4. Verify signature and claims
  const verified = jwt.verify(token, publicKey, {
    algorithms: ALLOWED_ALGORITHMS, // Whitelist algorithms
    issuer: 'https://auth.example.com',
    audience: 'https://api.example.com',
    clockTolerance: 30, // 30 seconds clock skew tolerance
  });

  return verified;
}

Validation Checklist

function validateTokenClaims(decoded) {
  const now = Math.floor(Date.now() / 1000);

  // 1. Check expiration
  if (decoded.exp && decoded.exp < now) {
    throw new Error('Token expired');
  }

  // 2. Check not before
  if (decoded.nbf && decoded.nbf > now) {
    throw new Error('Token not yet valid');
  }

  // 3. Check issuer
  if (decoded.iss !== EXPECTED_ISSUER) {
    throw new Error('Invalid issuer');
  }

  // 4. Check audience
  const audiences = Array.isArray(decoded.aud) ? decoded.aud : [decoded.aud];
  if (!audiences.includes(EXPECTED_AUDIENCE)) {
    throw new Error('Invalid audience');
  }

  // 5. Check required claims exist
  if (!decoded.sub) {
    throw new Error('Missing subject claim');
  }

  return true;
}

Security Vulnerabilities to Prevent

1. Algorithm Confusion Attack

// WRONG: Accepting any algorithm
jwt.verify(token, secret); // Vulnerable!

// CORRECT: Whitelist allowed algorithms
jwt.verify(token, key, { algorithms: ['RS256'] });

2. None Algorithm Attack

// Always reject 'none' algorithm
if (decoded.header.alg === 'none' || decoded.header.alg.toLowerCase() === 'none') {
  throw new Error('Algorithm none is not allowed');
}

3. Key Confusion (RS256 vs HS256)

// When using asymmetric keys, never allow symmetric algorithms
const ASYMMETRIC_ONLY = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'EdDSA'];

jwt.verify(token, publicKey, { algorithms: ASYMMETRIC_ONLY });

4. Weak HMAC Secrets

// Minimum 256-bit (32 byte) secret for HS256
// Minimum 384-bit (48 byte) secret for HS384
// Minimum 512-bit (64 byte) secret for HS512

function generateHmacSecret(algorithm) {
  const bits = parseInt(algorithm.slice(2)); // HS256 -> 256
  const bytes = bits / 8;
  return crypto.randomBytes(Math.max(bytes, 32)).toString('hex');
}

Token Storage

Browser Storage Security

// Best: HttpOnly cookie (requires backend support)
// Server sets:
res.cookie('access_token', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  maxAge: 900000, // 15 minutes
});

// Acceptable: In-memory (lost on refresh)
let accessToken = null;
function setToken(token) {
  accessToken = token;
}

// Avoid: localStorage (vulnerable to XSS)
// Avoid: sessionStorage for sensitive tokens

Token Transmission

// Always use Authorization header
fetch('/api/resource', {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

// Never put tokens in URLs (logged, cached, visible in history)
// WRONG: /api/resource?token=eyJ...

Refresh Token Implementation

// Refresh tokens should be:
// 1. Stored securely (httpOnly cookie or secure server-side storage)
// 2. Rotated on each use
// 3. Bound to the client (if possible)

async function refreshAccessToken(refreshToken) {
  // Validate refresh token
  const decoded = await validateRefreshToken(refreshToken);

  // Check if token has been revoked
  const isRevoked = await checkTokenRevocation(decoded.jti);
  if (isRevoked) {
    throw new Error('Refresh token has been revoked');
  }

  // Generate new tokens
  const newAccessToken = createAccessToken(decoded.sub);
  const newRefreshToken = createRefreshToken(decoded.sub);

  // Revoke old refresh token (rotation)
  await revokeToken(decoded.jti);

  return { accessToken: newAccessToken, refreshToken: newRefreshToken };
}

Token Revocation

// Maintain a revocation list for early token invalidation
const revokedTokens = new Set(); // Use Redis in production

function revokeToken(jti) {
  revokedTokens.add(jti);
}

function isTokenRevoked(jti) {
  return revokedTokens.has(jti);
}

// Include revocation check in validation
async function validateToken(token) {
  const decoded = jwt.verify(token, key, options);

  if (decoded.jti && isTokenRevoked(decoded.jti)) {
    throw new Error('Token has been revoked');
  }

  return decoded;
}

Key Rotation

// Support multiple keys during rotation
const keyStore = {
  'key-2024-01': { /* current key */ },
  'key-2023-12': { /* previous key, still valid */ },
};

// JWKS endpoint should expose all valid public keys
app.get('/.well-known/jwks.json', (req, res) => {
  const keys = Object.entries(keyStore).map(([kid, key]) => ({
    kid,
    kty: 'RSA',
    use: 'sig',
    alg: 'RS256',
    n: key.publicKey.n,
    e: key.publicKey.e,
  }));

  res.json({ keys });
});

Express Middleware Example

const expressJwt = require('express-jwt');
const jwksRsa = require('jwks-rsa');

const jwtMiddleware = expressJwt({
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: 'https://auth.example.com/.well-known/jwks.json',
  }),
  audience: 'https://api.example.com',
  issuer: 'https://auth.example.com',
  algorithms: ['RS256'],
});

// Protected route
app.get('/api/protected', jwtMiddleware, (req, res) => {
  // req.auth contains the decoded token
  res.json({ user: req.auth.sub });
});

Testing

describe('JWT Validation', () => {
  it('should reject expired tokens', async () => {
    const expiredToken = createToken({ exp: Math.floor(Date.now() / 1000) - 3600 });
    await expect(validateToken(expiredToken)).rejects.toThrow('expired');
  });

  it('should reject tokens with wrong issuer', async () => {
    const wrongIssuer = createToken({ iss: 'https://evil.com' });
    await expect(validateToken(wrongIssuer)).rejects.toThrow('issuer');
  });

  it('should reject none algorithm', async () => {
    const noneAlg = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIn0.';
    await expect(validateToken(noneAlg)).rejects.toThrow('algorithm');
  });
});

Common Anti-Patterns to Avoid

  1. Using JWTs for session management (prefer server-side sessions for web apps)
  2. Storing sensitive data in JWT payload (it's only encoded, not encrypted)
  3. Not validating all claims
  4. Using weak or hardcoded secrets
  5. Not implementing token expiration
  6. Trusting the algorithm header without validation
  7. Not implementing refresh token rotation
  8. Logging full tokens

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

29.71%
按下载量换算1,457

Antigravity

24.6%
按下载量换算1,206

OpenCode

19.8%
按下载量换算971

Gemini CLI

13.66%
按下载量换算670

github-copilot

7.36%
按下载量换算361

Cursor

3.71%
按下载量换算182

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills