OAuth Logs & LogQL Queries
Plugged.in uses structured JSON logging with automatic redaction and Loki integration for powerful log aggregation and querying.
Log Structure
All OAuth logs follow a consistent JSON structure:
{
"level": 30,
"time": 1699564800000,
"service_name": "pluggedin-app",
"version": "2.14.0",
"trace_id": "abc123def456",
"event": "oauth_token_refresh_success",
"serverUuid": "server-uuid-123",
"userId": "user-id-456",
"duration_ms": 850,
"msg": "Token refresh succeeded"
}
Log Fields
Log level: 10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal
Unix timestamp in milliseconds
Always “pluggedin-app” for the main application
Application version (from package.json)
Unique trace ID for correlating related logs across operations
Event type (e.g., “oauth_token_refresh_success”, “oauth_integrity_violation”)
Human-readable log message
Error details including stack trace (only for errors)
OAuth Event Types
Flow Events
// OAuth flow initiation
{
"event": "oauth_flow_initiated",
"provider": "github-mcp-server",
"serverUuid": "...",
"discoveryMethod": "rfc9728"
}
// OAuth flow success
{
"event": "oauth_flow_success",
"provider": "github-mcp-server",
"duration_ms": 3500,
"hasRefreshToken": true
}
// OAuth flow failure
{
"event": "oauth_flow_failure",
"provider": "github-mcp-server",
"duration_ms": 1200,
"error": "invalid_grant"
}
PKCE Events
// PKCE state created
{
"event": "pkce_state_created",
"state": "[REDACTED]",
"serverUuid": "...",
"expiresIn": 300
}
// PKCE validation success
{
"event": "pkce_validation_success",
"state": "[REDACTED]",
"serverUuid": "...",
"userId": "..."
}
// PKCE validation failure
{
"event": "pkce_validation_failure",
"state": "[REDACTED]",
"reason": "expired",
"expiredAt": "2024-01-15T10:30:00Z"
}
Token Events
// Token refresh initiated
{
"event": "token_refresh_initiated",
"serverUuid": "...",
"userId": "...",
"tokenExpired": true
}
// Token refresh success
{
"event": "token_refresh_success",
"serverUuid": "...",
"duration_ms": 850,
"hasNewRefreshToken": true
}
// Token rotation complete
{
"event": "token_rotation_complete",
"serverUuid": "...",
"hasNewRefreshToken": true
}
Security Events
// Refresh token reuse detected (CRITICAL)
{
"level": 60,
"event": "oauth_refresh_token_reuse_detected",
"userId": "...",
"serverUuid": "...",
"tokenUsedAt": "2024-01-15T10:29:45Z",
"currentAttempt": "2024-01-15T10:30:00Z",
"severity": "critical"
}
// Code injection attempt (CRITICAL)
{
"level": 60,
"event": "oauth_code_injection_attempt",
"attackerUserId": "...",
"victimUserId": "...",
"state": "[REDACTED]",
"serverUuid": "...",
"severity": "critical"
}
// Integrity violation (HIGH)
{
"level": 50,
"event": "oauth_integrity_violation",
"violationType": "hash_mismatch",
"state": "[REDACTED]",
"expectedHash": "...",
"actualHash": "...",
"severity": "high"
}
// Ownership violation (HIGH)
{
"level": 50,
"event": "oauth_ownership_violation",
"userId": "...",
"serverUuid": "...",
"expectedUserId": "...",
"actualUserId": "...",
"severity": "high"
}
Cleanup Events
// PKCE cleanup
{
"event": "pkce_cleanup_completed",
"deletedCount": 15,
"cutoffTime": "2024-01-15T10:20:00Z"
}
// Server PKCE cleanup
{
"event": "pkce_server_cleanup_completed",
"serverUuid": "...",
"deletedCount": 3
}
LogQL Queries
Basic Queries
All OAuth events from last hour:
{service_name="pluggedin-app"} |= "oauth"
OAuth events for specific server:
{service_name="pluggedin-app"}
| json
| serverUuid="server-uuid-123"
| event =~ "oauth_.*"
OAuth events by user:
{service_name="pluggedin-app"}
| json
| userId="user-id-456"
| event =~ "oauth_.*"
Security Monitoring
Critical security events (P0):
{service_name="pluggedin-app"}
| json
| severity="critical"
| event =~ "(token_reuse|code_injection)"
All integrity violations:
{service_name="pluggedin-app"}
| json
| event="oauth_integrity_violation"
Failed PKCE validations:
{service_name="pluggedin-app"}
| json
| event="pkce_validation_failure"
| line_format "{{.reason}}: {{.msg}}"
Ownership violations by user:
{service_name="pluggedin-app"}
| json
| event="oauth_ownership_violation"
| line_format "User {{.userId}} attempted access to server {{.serverUuid}}"
Token refresh operations over 2 seconds:
{service_name="pluggedin-app"}
| json
| event="token_refresh_success"
| duration_ms > 2000
| line_format "Slow refresh: {{.duration_ms}}ms for server {{.serverUuid}}"
OAuth flow duration distribution:
sum by (provider) (
count_over_time(
{service_name="pluggedin-app"}
| json
| event="oauth_flow_success"
[1h]
)
)
Average token refresh time:
avg_over_time(
{service_name="pluggedin-app"}
| json
| event="token_refresh_success"
| unwrap duration_ms
[5m]
) / 1000
Error Tracking
OAuth errors in last 24h:
{service_name="pluggedin-app"}
| json
| level >= 50
| event =~ "oauth_.*"
Token refresh failures with reasons:
{service_name="pluggedin-app"}
| json
| event="token_refresh_failure"
| line_format "{{.reason}}: {{.err.message}}"
Discovery failures by method:
sum by (discoveryMethod) (
count_over_time(
{service_name="pluggedin-app"}
| json
| event="oauth_discovery_failure"
[1h]
)
)
Trace Correlation
Complete OAuth flow by trace_id:
{service_name="pluggedin-app"}
| json
| trace_id="abc123def456"
| event =~ "oauth_.*"
Related operations for a server:
{service_name="pluggedin-app"}
| json
| serverUuid="server-uuid-123"
| event =~ "(oauth_|pkce_|token_)"
Alerting Queries
Token reuse in last 5 minutes (CRITICAL ALERT):
count_over_time(
{service_name="pluggedin-app"}
| json
| event="oauth_refresh_token_reuse_detected"
[5m]
) > 0
High rate of code injection attempts (>10/hour):
count_over_time(
{service_name="pluggedin-app"}
| json
| event="oauth_code_injection_attempt"
[1h]
) > 10
OAuth flow success rate below 95%:
(
sum(count_over_time({service_name="pluggedin-app"} | json | event="oauth_flow_success" [5m]))
/
sum(count_over_time({service_name="pluggedin-app"} | json | event =~ "oauth_flow_(success|failure)" [5m]))
) < 0.95
Token refresh failures spiking (>20/min):
rate(
{service_name="pluggedin-app"}
| json
| event="token_refresh_failure"
[1m]
) * 60 > 20
Log Aggregation Patterns
Count Events by Type
sum by (event) (
count_over_time(
{service_name="pluggedin-app"}
| json
| event =~ "oauth_.*"
[1h]
)
)
Top Error Messages
topk(10,
sum by (msg) (
count_over_time(
{service_name="pluggedin-app"}
| json
| level >= 50
| event =~ "oauth_.*"
[24h]
)
)
)
Users with Most OAuth Activity
topk(20,
sum by (userId) (
count_over_time(
{service_name="pluggedin-app"}
| json
| event =~ "oauth_.*"
[24h]
)
)
)
Servers Requiring Most Token Refreshes
topk(10,
sum by (serverUuid) (
count_over_time(
{service_name="pluggedin-app"}
| json
| event="token_refresh_success"
[24h]
)
)
)
Sensitive Data Redaction
Sensitive fields are automatically redacted in logs:
Never log these fields in plaintext:
access_token
refresh_token
code_verifier
client_secret
authorization_code
Example redacted log:
{
"event": "token_refresh_success",
"access_token": "[REDACTED]",
"refresh_token": "[REDACTED]",
"serverUuid": "visible-server-id"
}
Best Practices
Use Trace IDs
Correlate related operations across services using trace_id field
Filter by Time Range
Always specify time ranges to avoid scanning entire log history
Index by Service
Use service_name label for efficient querying in multi-service deployments
Alert on Security Events
Set up Grafana alerts for critical security events (token reuse, code injection)
Monitor Performance
Track p50, p95, p99 for token refresh duration to detect degradation
Example Grafana Queries
Panel: OAuth Flow Success Rate (Last 24h)
Query:
(
sum(count_over_time({service_name="pluggedin-app"} | json | event="oauth_flow_success" [$__range]))
/
sum(count_over_time({service_name="pluggedin-app"} | json | event =~ "oauth_flow_(success|failure)" [$__range]))
) * 100
Panel Type: Stat
Unit: Percent (0-100)
Panel: Top OAuth Errors (Last 6h)
Query:
topk(5,
sum by (msg) (
count_over_time(
{service_name="pluggedin-app"}
| json
| level >= 50
| event =~ "oauth_.*"
[6h]
)
)
)
Panel Type: Bar Chart
Panel: Security Events Timeline
Query:
{service_name="pluggedin-app"}
| json
| severity =~ "(critical|high)"
| event =~ "(token_reuse|code_injection|integrity_violation|ownership_violation)"
| line_format "[{{.severity}}] {{.event}}: {{.msg}}"
Panel Type: Logs
Troubleshooting
Check environment:# Ensure NODE_ENV is NOT 'development' for JSON logs
NODE_ENV=production npm start
Development mode uses pino-pretty for human-readable logs. Sensitive data appearing in logs
Verify redaction is enabled in lib/observability/logger.ts:const redactPaths = [
'access_token',
'refresh_token',
'code_verifier',
'client_secret',
'authorization_code'
];
- Reduce time range
- Add more specific filters before parsing JSON
- Use indexed labels (service_name) first
- Consider using metric queries instead for aggregations
Ensure trace_id is generated for each request:import { generateTraceId } from '@/lib/observability/logger';
const traceId = generateTraceId();
Next Steps