Audit Logging Guide

Overview

Audit logging provides an immutable record of all permission changes in your organization, enabling compliance tracking, debugging, and accountability. Logs are append-only, never modified, and automatically cleaned up based on retention policy.

How It Works

Log Lifecycle

  1. Event Occurs — A role, team, or membership change happens
  2. Log Created — The change is recorded with actor, IP, timestamp, and details
  3. Stored Permanently — Log becomes immutable (read-only forever)
  4. Queryable — Admins can search by actor, resource, action, or date
  5. Cleaned Up — Logs older than retention period are deleted by cleanup job

Audit Actions (MVP)

ActionTriggered ByDetails
member_role_assignedAssign custom role to memberBefore: [], After: [role_id]
member_role_removedRemove custom role from memberBefore: [role_id], After: []
member_custom_roles_updatedUpdate multiple roles at onceBefore: [old_ids], After: [new_ids]
custom_role_createdCreate a new custom roleRole name, permissions
custom_role_updatedModify custom role permissionsBefore: [perms], After: [perms]
custom_role_deletedDelete a custom roleRole name, reason
team_createdCreate new teamTeam name, description
team_updatedModify team metadataBefore: , After:
team_deletedDelete teamTeam name
team_role_assignedAssign role to teamRole ID, Team ID
team_role_removedRemove role from teamRole ID, Team ID
member_added_to_teamAdd member to teamMember ID, Team ID
member_removed_from_teamRemove member from teamMember ID, Team ID

Querying Audit Logs

Basic Query

Get all audit logs for your organization:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit" \
  -H "Authorization: Bearer <token>"

Filter by Actor

Find all changes made by a specific user:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?actor_id=user_abc123" \
  -H "Authorization: Bearer <token>"
This is useful for auditing a specific admin’s activities or seeing if someone made unauthorized changes.

Filter by Resource

Track all changes to a specific role:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?resource_type=role&resource_id=role_abc123" \
  -H "Authorization: Bearer <token>"
Supported resource types:
  • role — Custom role changes
  • team — Team CRUD operations
  • member — Member changes (added, removed, role assignments)

Filter by Date Range

Get logs from the last 30 days:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?start_date=2026-03-25&end_date=2026-04-25" \
  -H "Authorization: Bearer <token>"

Combined Filters

Find all role-related changes by an admin in the last week:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?actor_id=user_xyz&resource_type=role&start_date=2026-04-18&pageSize=50" \
  -H "Authorization: Bearer <token>"

Log Format

Example Audit Log Entry

{
  "id": "audit_abc123",
  "orgId": "org_xyz789",
  "actorId": "user_admin_456",
  "action": "member_role_assigned",
  "resourceType": "member",
  "resourceId": "member_xyz789",
  "changes": {
    "before": {
      "customRoleIds": ["role_viewer"]
    },
    "after": {
      "customRoleIds": ["role_viewer", "role_editor"]
    }
  },
  "ipAddress": "192.168.1.100",
  "sessionContext": {
    "sessionId": "sess_abc123",
    "userAgent": "Mozilla/5.0..."
  },
  "approvalStatus": null,
  "approvalMetadata": null,
  "orgRetentionDays": 90,
  "createdAt": "2026-04-24T10:30:00Z"
}

Field Definitions

FieldTypeDescription
idUUIDImmutable log ID (can be referenced externally)
orgIdUUIDOrganization ID
actorIdUUIDUser who made the change
actionStringWhat happened (member_role_assigned, etc.)
resourceTypeStringType of resource changed (role, team, member)
resourceIdUUIDID of resource that changed
changesObjectBefore/after state comparison
ipAddressStringIP address of requester (for security audit)
sessionContextObjectSession details for compliance
approvalStatusStringApproval workflow status (future)
approvalMetadataObjectApproval details (future)
orgRetentionDaysIntegerRetention policy in effect at log creation
createdAtTimestampWhen the change occurred

Retention Policy

Default Retention

Organizations retain audit logs for a default period (e.g., 90 days). After this period, logs are automatically deleted. The response from the audit API includes the retention period:
{
  "logs": [...],
  "retentionDays": 90
}

Cleanup Process

A scheduled job (cron, Lambda, etc.) calls the cleanup endpoint periodically:
curl -X POST "https://api.example.com/api/v1/organizations/org_xyz/audit/cleanup" \
  -H "Authorization: Bearer <service_token>" \
  -H "Content-Type: application/json" \
  -d '{"dry_run": false}'
Response:
{
  "deleted": 150,
  "retainedFrom": "2026-01-25T00:00:00Z"
}

Dry Run

Test cleanup without deleting:
curl -X POST "https://api.example.com/api/v1/organizations/org_xyz/audit/cleanup" \
  -H "Authorization: Bearer <service_token>" \
  -H "Content-Type: application/json" \
  -d '{"dry_run": true}'
Returns how many logs would be deleted without actually deleting them.

Common Use Cases

Compliance Audit

“Show me all role changes made in Q1 2026”:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?start_date=2026-01-01&end_date=2026-03-31&resource_type=role" \
  -H "Authorization: Bearer <token>"
Then export to CSV or PDF for compliance teams.

Security Investigation

“Did someone add themselves as an admin without authorization?”:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?resource_type=member&resource_id=member_suspicious&pageSize=100" \
  -H "Authorization: Bearer <token>"
Review the log history to see all role changes for that member.

Debugging Permission Issues

“Why does Alice not have content:publish permission?”:
# 1. Check current permissions by querying member details or testing can()
# 2. Get role assignment history
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?resource_id=member_alice" \
  -H "Authorization: Bearer <token>"
# 3. Review when roles were added/removed
# 4. Check which teams she's in and their role assignments
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?resource_type=team" \
  -H "Authorization: Bearer <token>"

Admin Activity Review

“What did the new admin do in their first week?”:
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?actor_id=user_new_admin&start_date=2026-04-15&end_date=2026-04-22" \
  -H "Authorization: Bearer <token>"

Best Practices

Regular Audits

Schedule weekly or monthly reviews of audit logs to catch suspicious activity early.

Retention Strategy

  • Short retention (30 days): For compliance-sensitive data, delete quickly
  • Standard retention (90 days): Default for most organizations
  • Long retention (1 year): For highly regulated industries

Immutability Guarantee

Audit logs are guaranteed immutable. They cannot be:
  • Modified or edited
  • Deleted except by retention policy
  • Hidden from queries
This makes them trustworthy for compliance purposes.

IP Address Logging

Logs capture the requester’s IP address for security investigations:
{
  "ipAddress": "192.168.1.100",
  ...
}
Use this to detect unauthorized access patterns or geographic anomalies.

API Pagination

Audit logs support pagination to handle large result sets efficiently:
# Get 20 logs per page (default)
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?page=1" \
  -H "Authorization: Bearer <token>"

# Get 100 logs per page (max)
curl "https://api.example.com/api/v1/organizations/org_xyz/audit?page=1&pageSize=100" \
  -H "Authorization: Bearer <token>"
Response includes:
{
  "logs": [...],
  "total": 1250,
  "page": 1,
  "pageSize": 20
}
Use total to calculate how many pages exist: Math.ceil(total / pageSize).

Error Handling

Insufficient Permissions

{
  "error": "Insufficient permissions to access audit logs"
}
Only members of the organization can view audit logs.

Invalid Filter

{
  "error": "Invalid date range: start_date must be before end_date"
}
Ensure dates are in ISO 8601 format and logically ordered.

Organization Not Found

{
  "error": "Organization not found"
}
Verify the organization ID is correct.