{
  "rule": {
    "id": "S049",
    "name": "Authentication tokens should have short validity periods",
    "description": "Authentication tokens (JWT, session tokens, etc.) should have appropriately short validity periods to minimize the risk of token compromise. Long-lived tokens increase the attack surface and potential impact of token theft.",
    "category": "security",
    "severity": "error",
    "languages": ["typescript", "javascript"],
    "frameworks": ["express", "nestjs", "node"],
    "version": "1.0.0",
    "status": "stable",
    "tags": ["security", "authentication", "tokens", "jwt", "session", "owasp"],
    "references": [
      "https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/04-Authentication_Testing/01-Testing_for_Credentials_Transported_over_an_Encrypted_Channel",
      "https://owasp.org/www-project-application-security-verification-standard/",
      "https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html",
      "https://tools.ietf.org/html/rfc7519#section-4.1.4"
    ]
  },
  "configuration": {
    "enableJWTValidityCheck": true,
    "enableSessionTokenCheck": true,
    "enableOAuthTokenCheck": true,
    "maxValidityPeriods": {
      "accessToken": 3600,
      "refreshToken": 86400,
      "sessionToken": 1800,
      "idToken": 3600,
      "authToken": 3600
    },
    "jwtProperties": [
      "exp",
      "expiresIn",
      "expiry",
      "expires",
      "ttl",
      "maxAge",
      "lifetime"
    ],
    "tokenMethods": [
      "sign",
      "create",
      "generate",
      "issue",
      "encode"
    ],
    "jwtLibraries": [
      "jsonwebtoken",
      "jose",
      "@nestjs/jwt",
      "jwt-simple",
      "node-jsonwebtoken",
      "passport-jwt"
    ],
    "sessionMethods": [
      "session",
      "cookie",
      "maxAge",
      "expires"
    ],
    "sessionLibraries": [
      "express-session",
      "connect-session",
      "cookie-session",
      "client-sessions"
    ],
    "oauthProperties": [
      "access_token_lifetime",
      "refresh_token_lifetime",
      "token_lifetime",
      "expires_in"
    ],
    "timeUnits": {
      "seconds": 1,
      "minutes": 60,
      "hours": 3600,
      "days": 86400,
      "weeks": 604800,
      "months": 2592000,
      "years": 31536000
    },
    "dangerousPatterns": [
      "no-expire",
      "never-expire",
      "permanent",
      "forever",
      "infinite",
      "unlimited"
    ],
    "exemptedScenarios": [
      "test",
      "testing",
      "mock",
      "development",
      "dev"
    ]
  },
  "examples": {
    "violations": [
      {
        "description": "JWT token with excessive expiration time",
        "code": "jwt.sign(payload, secret, { expiresIn: '30d' })"
      },
      {
        "description": "Session with very long max age",
        "code": "session({ maxAge: 30 * 24 * 60 * 60 * 1000 })"
      },
      {
        "description": "Token with no expiration",
        "code": "jwt.sign(payload, secret)"
      }
    ],
    "clean": [
      {
        "description": "JWT token with appropriate expiration",
        "code": "jwt.sign(payload, secret, { expiresIn: '1h' })"
      },
      {
        "description": "Session with reasonable max age",
        "code": "session({ maxAge: 30 * 60 * 1000 })"
      }
    ]
  }
}
