Security Monitoring
The Security Monitoring dashboard (Builder UI → Security) surfaces security-relevant events from the audit_logs table and the audit_log_stats_by_org materialized view. It lets you review authentication failures, rate limit violations, permission errors, and API key activity across all end-users in your organization.
What is monitored
| Event type | Representative action values |
|---|---|
| Authentication failures | login_failed, token_invalid, session_expired |
| Rate limit violations | rate_limit_exceeded, throttled |
| Permission violations | access_denied, permission_denied, unauthorized |
| IP address anomalies | suspicious_ip, geo_anomaly |
| API key events | api_key_generated, api_key_revoked, api_key_used |
The dashboard derives a risk level per event from the action name:
| Risk | Actions |
|---|---|
| High | access_denied, security_violation, password_change |
| Medium | api_key_generated, api_key_revoked, login_failed |
| Low | Everything else |
The Security Violations KPI card estimates ~10% of all events as violations. The Risk Level card rolls this into High / Medium / Low: High above 50 violations, Medium above 20, Low otherwise.
Suspicious IP detection
An IP is flagged as suspicious when it appears in more than 5 events in the loaded window. Risk is assigned by event count: Low ≤ 10, Medium ≤ 20, High > 20. Only the top 10 IPs are shown.
Time ranges
The dashboard filters events on the client side across four windows: Last 7 days, Last 30 days, Last 90 days, All time.
Reading the dashboard
- Security Events tab — filterable table with timestamp, organization, actor (type + ID), action, IP address, risk badge, and metadata details.
- Suspicious Activity tab — per-IP aggregation showing event count, unique action count, first/last seen, and risk level.
- Analytics tab — top-10 action frequency list and a Security Status panel (RLS, encryption, audit logging, rate limiting).
Builder API
Security event data is exposed exclusively through the Hasura GraphQL endpoint. There is no REST API for security events today — this is a known gap flagged for future remediation.
Use your organization token (see API Keys) to query the tables directly.
Query audit logs
query GetSecurityEvents($appId: uuid!, $limit: Int = 50, $offset: Int = 0) {
audit_logs(
where: { application_id: { _eq: $appId } }
limit: $limit
offset: $offset
order_by: { created_at: desc }
) {
id
organization_id
application_id
actor_type
actor_id
actor_email
action
target_type
target_id
ip_address
metadata
created_at
}
}Query aggregate stats
The audit_log_stats_by_org materialized view is refreshed periodically by the platform. It provides pre-aggregated counts without scanning the full log table.
query GetSecurityStats($orgId: uuid!) {
audit_log_stats_by_org(
where: { organization_id: { _eq: $orgId } }
) {
organization_id
period_days
total_logs
unique_actors
unique_sessions
top_actions
top_targets
recent_activity
last_updated
}
}Query recent activity
query GetRecentActivity($orgId: uuid!, $limit: Int = 20) {
recent_audit_activity(
where: { organization_id: { _eq: $orgId } }
limit: $limit
order_by: { created_at: desc }
) {
id
organization_id
actor_type
actor_id
actor_email
action
target_type
created_at
}
}Filter by action
Append a where clause to the audit_logs query:
audit_logs(
where: {
application_id: { _eq: $appId }
action: { _in: ["access_denied", "login_failed", "rate_limit_exceeded"] }
}
...
)Write an event
The LogAuditEvent Hasura action lets you emit custom audit entries from your own infrastructure:
mutation LogSecurityEvent(
$orgId: uuid!
$actorType: String!
$action: String!
$targetType: String!
$ipAddress: String
$metadata: jsonb
) {
LogAuditEvent(
orgId: $orgId
actorType: $actorType
action: $action
targetType: $targetType
ipAddress: $ipAddress
metadata: $metadata
) {
id
}
}API gap note: A dedicated REST endpoint for querying and filtering security events does not exist yet. The Hasura GraphQL queries above are the only programmatic access path. Builders who need webhook-style delivery or server-side alerting must poll the
audit_logstable directly.