Security
GraphQL API security features and protections
Security Features
The GraphQL API implements comprehensive security measures to protect against common vulnerabilities and attacks.
Rate Limiting
Protection: Prevents API abuse through request throttling
Default Limit: 100 requests per minute per client
Enforcement: Based on authenticated user ID or IP address
Storage: Redis-based for distributed systems, in-memory fallback for single instances
When rate limit is exceeded:
{
"errors": [{
"message": "Rate limit exceeded",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"limit": 100,
"windowMs": 60000,
"retryAfter": 45
}
}]
}Query Depth Limiting
Protection: Prevents deeply nested queries that could overwhelm the server
Default Limit: 10 levels deep
Scope: Applies to all field selections
Example of rejected query:
{
"errors": [{
"message": "Query depth limit exceeded. Maximum depth: 10, requested: 12",
"extensions": {
"code": "DEPTH_LIMIT_EXCEEDED",
"maxDepth": 10,
"actualDepth": 12
}
}]
}Query Complexity Limiting
Protection: Prevents expensive queries based on complexity analysis
Default Limit: 1000 complexity points
Calculation: Each field adds complexity, lists multiply based on limit argument
Example:
{
"errors": [{
"message": "Query complexity limit exceeded. Maximum complexity: 1000, requested: 1250",
"extensions": {
"code": "COMPLEXITY_LIMIT_EXCEEDED",
"maxComplexity": 1000,
"actualComplexity": 1250
}
}]
}Field Count Limiting
Protection: Prevents queries that request too many fields
Default Limit: 100 fields per query
Scope: Counts all selected fields across the entire query
Batch Query Protection
Protection: Prevents batching attacks where multiple operations are sent in a single request
Default Limit: 5 operations per request
Enforcement: Applied before query execution
Rejected batch request:
{
"errors": [{
"message": "Too many operations in batch. Maximum: 5, requested: 10",
"extensions": {
"code": "BATCH_LIMIT_EXCEEDED",
"maxBatch": 5,
"actualBatch": 10
}
}]
}Request Size Limiting
Protection: Prevents DoS attacks through large payloads
Query Limit: 100KB maximum
Variables Limit: 50KB maximum
CSRF Protection
Protection: Prevents cross-site request forgery attacks
Requirement: Custom header required for mutations in production
Header: x-graphql-request: true
Without the required header:
{
"errors": [{
"message": "CSRF protection: Missing required header 'x-graphql-request' for mutations",
"extensions": {
"code": "CSRF_PROTECTION_FAILED",
"requiredHeader": "x-graphql-request",
"hint": "Add header 'x-graphql-request: true' to your GraphQL client"
}
}]
}Schema Introspection Control
Protection: Prevents schema enumeration in production
Access: Admin users only in production, all users in development
Benefit: Reduces attack surface by hiding schema structure
GraphQL Armor Protection
Additional protections provided by GraphQL Armor:
- Alias Limiting: Maximum 15 aliases per query (prevents alias flooding attacks)
- Token Limiting: Maximum 1000 tokens per query (prevents huge query strings)
- Directive Limiting: Maximum 50 directives per query (prevents directive abuse)
- Cost Analysis: Advanced query cost calculation with 5000 point limit
- Field Suggestion Blocking: Disables field name suggestions in production errors
Error Masking
Protection: Prevents information disclosure through error messages
Behavior: Internal errors are masked in production, detailed in development
Code Assignment: All errors include a standardized code in the extensions field
Production error example:
{
"errors": [{
"message": "Internal server error",
"extensions": {
"code": "INTERNAL_SERVER_ERROR"
}
}]
}Query Timeout
Protection: Prevents long-running queries from consuming resources
Default Timeout: 10 seconds
Enforcement: Query execution is terminated if it exceeds the timeout
Authorization
All queries and mutations enforce proper authorization:
- Authentication Required: Many queries require valid authentication
- Role-Based Access: Admin-only operations are protected
- Resource Ownership: Users can only access their own data (except admins)
- Field-Level Security: Sensitive fields are conditionally available based on permissions
Example authorization error:
{
"errors": [{
"message": "Authentication required",
"extensions": {
"code": "UNAUTHENTICATED"
}
}]
}