Skip to Content
Security Monitoring

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 typeRepresentative action values
Authentication failureslogin_failed, token_invalid, session_expired
Rate limit violationsrate_limit_exceeded, throttled
Permission violationsaccess_denied, permission_denied, unauthorized
IP address anomaliessuspicious_ip, geo_anomaly
API key eventsapi_key_generated, api_key_revoked, api_key_used

The dashboard derives a risk level per event from the action name:

RiskActions
Highaccess_denied, security_violation, password_change
Mediumapi_key_generated, api_key_revoked, login_failed
LowEverything 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_logs table directly.

Last updated on