Skip to main content
Matcher implements comprehensive security controls to protect financial reconciliation data. This guide covers authentication, authorization, tenant isolation, encryption, and compliance features.

Overview


Matcher’s security architecture is built on several layers. Every API request passes through multiple security checkpoints before reaching your data.
1
First, TLS encrypts the connection.
2
Then authentication verifies who you are:
  • Tenant isolation ensures you only see your own data.
  • RBAC checks whether you’re allowed to perform the action.
3
Finally, the system logs everything for audit purposes.

Layer protection

LayerProtection
TransportTLS 1.2+ encryption
AuthenticationJWT tokens via lib-auth
Tenant IsolationSchema-per-tenant PostgreSQL
AuthorizationRole-based access control
AuditImmutable append-only logs
StorageEncryption at rest

Authentication


Matcher uses the shared lib-auth library for authentication, supporting OAuth 2.0 and JWT-based access control.

Supported authentication methods

MethodUse Case
OAuth 2.0 + JWTUser authentication via IdP
Client CredentialsService-to-service auth
API KeysProgrammatic access

JWT token structure

{
  "sub": "user_123",
  "tenant_id": "tenant_001",
  "roles": [
    "reconciliation_admin"
  ],
  "permissions": [
    "ingestion:import:create",
    "matching:job:run",
    "exception:item:resolve"
  ],
  "iat": 1705749600,
  "exp": 1705753200,
  "iss": "https://auth.example.com"
}

Required headers

All API requests must include authentication:
curl -X GET "https://api.matcher.example.com/v1/contexts" \
 -H "Authorization: Bearer $JWT_TOKEN" \
 -H "X-Request-ID: req_abc123"

Token validation

Matcher validates tokens on every request:
  1. Signature verification: Validates JWT signature against public key
  2. Expiration check: Rejects expired tokens
  3. Issuer validation: Confirms token from trusted issuer
  4. Tenant extraction: Extracts tenant_id for schema isolation

Service-to-service authentication

For backend services integrating with Matcher:
# Request token
curl -X POST "https://auth.example.com/oauth/token" \
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d "grant_type=client_credentials" \
 -d "client_id=matcher-service" \
 -d "client_secret=$CLIENT_SECRET" \
 -d "scope=matcher:read matcher:write"

Response

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "matcher:read matcher:write"
}

Authorization (rbac)


Role-based access control protects all API endpoints. Permissions are granular and follow the pattern domain:resource:action.

Permission structure

<bounded_context>:<resource>:<action>
Examples:
  • ingestion:import:create - Create imports
  • matching:job:run - Execute matching jobs
  • exception:item:resolve - Resolve exceptions

Complete permission list

Ingestion

PermissionDescription
ingestion:import:createUpload transaction files
ingestion:import:readView import status
ingestion:import:cancelCancel in-progress imports
ingestion:source:createCreate data sources
ingestion:source:readView source configuration
ingestion:source:updateModify source settings
ingestion:source:deleteRemove data sources

Matching

PermissionDescription
matching:job:runExecute matching jobs
matching:job:readView job status
matching:job:cancelCancel running jobs
matching:match:readView match results
matching:match:confirmConfirm proposed matches
matching:match:rejectReject proposed matches
matching:rule:createCreate match rules
matching:rule:updateModify match rules
matching:rule:deleteDelete match rules

Exception

PermissionDescription
exception:item:readView exceptions
exception:item:resolveResolve exceptions
exception:item:assignAssign exceptions
exception:item:escalateEscalate exceptions
exception:routing:manageConfigure routing rules

Governance

PermissionDescription
governance:report:readView reports
governance:report:createGenerate reports
governance:report:exportExport report data
governance:audit:readView audit logs
governance:context:createCreate contexts
governance:context:updateModify contexts
governance:context:deleteDelete contexts

Administration

PermissionDescription
admin:user:manageManage user access
admin:role:manageManage roles
admin:tenant:configureConfigure tenant settings
admin:system:monitorView system health

Built-in roles

RolePermissionsUse Case
reconciliation_viewerRead-only access to matches and exceptionsAuditors
reconciliation_analystView + resolve exceptionsFinance team
reconciliation_adminFull access except system adminTeam leads
system_adminAll permissionsIT administrators

Custom roles

Create custom roles combining specific permissions:
cURL
curl -X POST "https://api.matcher.example.com/v1/admin/roles" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "exception_specialist",
   "description": "Can only work on exceptions",
   "permissions": [
     "exception:item:read",
     "exception:item:resolve",
     "exception:item:assign",
     "governance:report:read"
   ]
 }'

Response

{
  "id": "role_exc_001",
  "name": "exception_specialist",
  "description": "Can only work on exceptions",
  "permissions": [
    "exception:item:read",
    "exception:item:resolve",
    "exception:item:assign",
    "governance:report:read"
  ],
  "created_at": "2024-01-15T10:00:00Z"
}

Assign roles to users

curl -X POST "https://api.matcher.example.com/v1/admin/users/user_123/roles" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "roles": [
     "exception_specialist"
   ],
   "context_restrictions": [
     "ctx_abc123",
     "ctx_def456"
   ]
 }'

Tenant isolation


Matcher uses schema-per-tenant isolation in PostgreSQL, providing strong data separation between tenants.

How it works

When a request arrives, Matcher extracts the tenant ID from the JWT token (never from query parameters or headers you control). It then sets the database connection to use that tenant’s schema, so every query runs in complete isolation.
Even if a bug existed in the application layer, the database enforces separation.
Implementation details
  1. Tenant ID from JWT only: Never accepted from request parameters
  2. Automatic schema selection: Applied via auth.ApplyTenantSchema()
  3. Query isolation: All queries scoped to tenant schema
  4. No cross-tenant access: Database enforces isolation

Database schema structure

Database: matcher_db
├── tenant_001 (schema)
│ ├── transactions
│ ├── matches
│ ├── exceptions
│ ├── audit_logs
│ └── ...
├── tenant_002 (schema)
│ ├── transactions
│ ├── matches
│ ├── exceptions
│ ├── audit_logs
│ └── ...
└── shared (schema)
 ├── field_map_templates
 ├── rule_templates
 └── system_config

Isolation guarantees

GuaranteeImplementation
Data isolationSeparate PostgreSQL schemas
Query scopingsearch_path set per connection
No tenant spoofingTenant from JWT only
Audit separationPer-tenant audit tables

Verify tenant isolation

# This returns only data for the tenant in the JWT
curl -X GET "https://api.matcher.example.com/v1/contexts" \
 -H "Authorization: Bearer $TOKEN"

Audit trail


All actions are recorded in an immutable, append-only audit log for compliance and forensics.

Audited events

CategoryEvents
AuthenticationLogin, logout, token refresh, failed attempts
Data AccessView matches, view exceptions, export data
Data ModificationCreate match, resolve exception, update rules
ConfigurationCreate context, modify source, change settings
AdministrationUser management, role changes, permission grants

Audit log structure

{
  "id": "audit_001",
  "timestamp": "2024-01-20T10:30:00Z",
  "tenant_id": "tenant_001",
  "user_id": "user_123",
  "user_email": "[email protected]",
  "action": "exception:item:resolve",
  "resource_type": "exception",
  "resource_id": "exc_001",
  "details": {
    "resolution_type": "FORCE_MATCH",
    "matched_transaction": "txn_456",
    "notes": "Verified with bank statement"
  },
  "ip_address": "192.168.1.100",
  "user_agent": "Mozilla/5.0...",
  "request_id": "req_abc123",
  "outcome": "SUCCESS"
}

Query audit logs

cURL
curl -X GET "https://api.matcher.example.com/v1/governance/audit" \
 -H "Authorization: Bearer $TOKEN" \
 -G \
 -d "date_from=2024-01-01" \
 -d "date_to=2024-01-31" \
 -d "user_id=user_123" \
 -d "action=exception:item:resolve"

Response

{
  "audit_logs": [
    {
      "id": "audit_001",
      "timestamp": "2024-01-20T10:30:00Z",
      "user_id": "user_123",
      "action": "exception:item:resolve",
      "resource_id": "exc_001",
      "outcome": "SUCCESS"
    }
  ],
  "pagination": {
    "total": 45,
    "page": 1,
    "per_page": 20
  }
}

Audit log retention

EnvironmentRetentionArchive
Production7 yearsCold storage after 1 year
Staging90 daysNo archive
Development30 daysNo archive

Export audit logs

For compliance reporting:
curl -X POST "https://api.matcher.example.com/v1/governance/audit/export" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "date_from": "2024-01-01",
   "date_to": "2024-01-31",
   "format": "CSV",
   "include_details": true
 }'

Data encryption


Encryption in transit

All data transmitted to and from Matcher is encrypted using TLS.
RequirementConfiguration
ProtocolTLS 1.2 or higher
Cipher suitesStrong ciphers only
CertificateValid CA-signed certificate
HSTSEnabled with 1-year max-age

Encryption at rest

Data TypeEncryption Method
DatabasePostgreSQL TDE (Transparent Data Encryption)
File storageAES-256 encryption
BackupsEncrypted before storage
SecretsVault with envelope encryption

Sensitive field encryption

Specific sensitive fields are encrypted at the application level:
{
  "settings": {
    "encryption": {
      "encrypt_fields": [
        "counterparty_account",
        "reference",
        "external_id"
      ],
      "key_id": "key_prod_001"
    }
  }
}

Key management

PracticeImplementation
Key rotationAutomatic 90-day rotation
Key storageHashiCorp Vault or AWS KMS
Access controlPrinciple of least privilege
AuditAll key access logged

SOX compliance


Matcher maintains records for SOX (Sarbanes-Oxley) audit requirements.

SOX control features

ControlMatcher Feature
Segregation of dutiesRBAC with granular permissions
Change managementAudit trail for all configuration changes
Access controlJWT authentication with role enforcement
Audit trailImmutable logs with 7-year retention
Data integrityTransaction checksums and validation

SOX compliance report

Generate compliance-ready reports:
curl -X POST "https://api.matcher.example.com/v1/governance/reports/sox" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "period": {
     "from": "2024-01-01",
     "to": "2024-03-31"
   },
   "include_sections": [
     "access_reviews",
     "configuration_changes",
     "exception_resolutions",
     "segregation_analysis"
   ]
 }'

Response

{
  "report_id": "sox_q1_2024",
  "period": {
    "from": "2024-01-01",
    "to": "2024-03-31"
  },
  "sections": {
    "access_reviews": {
      "total_users": 25,
      "role_changes": 8,
      "permission_grants": 12,
      "permission_revocations": 5
    },
    "configuration_changes": {
      "context_changes": 3,
      "rule_changes": 15,
      "source_changes": 7
    },
    "exception_resolutions": {
      "total_resolved": 450,
      "by_resolution_type": {
        "FORCE_MATCH": 280,
        "ADJUSTMENT": 120,
        "WRITE_OFF": 50
      },
      "approval_compliance": 100.0
    },
    "segregation_analysis": {
      "violations_detected": 0,
      "users_with_conflicting_roles": 0
    }
  }
}

Four-eyes principle

Enforce dual approval for sensitive actions:
{
  "settings": {
    "governance": {
      "require_approval": {
        "exception_write_off": true,
        "high_value_match": true,
        "threshold_amount": 100000.0
      },
      "approver_role": "reconciliation_admin"
    }
  }
}

API security


Rate limiting

Protect against abuse with rate limits:
Endpoint TypeLimit
Read operations1000/minute
Write operations100/minute
Report generation10/minute
File uploads20/minute

Rate limit headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1705753200

Ip allowlisting

Restrict API access to known IP ranges:
{
  "settings": {
    "security": {
      "ip_allowlist": [
        "10.0.0.0/8",
        "192.168.1.0/24",
        "203.0.113.50"
      ],
      "enforce_allowlist": true
    }
  }
}

Request signing

For high-security environments, enable request signing:
# Generate signature
TIMESTAMP=$(date +%s)
SIGNATURE=$(echo -n "$TIMESTAMP$REQUEST_BODY" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)

curl -X POST "https://api.matcher.example.com/v1/matches" \
 -H "Authorization: Bearer $TOKEN" \
 -H "X-Timestamp: $TIMESTAMP" \
 -H "X-Signature: $SIGNATURE" \
 -d "$REQUEST_BODY"

Security monitoring


Security events

Monitor security-relevant events:
curl -X GET "https://api.matcher.example.com/v1/admin/security/events" \
 -H "Authorization: Bearer $TOKEN" \
 -G \
 -d "severity=HIGH" \
 -d "date_from=2024-01-20"

Response

{
  "events": [
    {
      "id": "sec_001",
      "timestamp": "2024-01-20T14:30:00Z",
      "type": "AUTHENTICATION_FAILURE",
      "severity": "HIGH",
      "details": {
        "user_id": "user_456",
        "ip_address": "192.168.1.200",
        "failure_reason": "invalid_token",
        "attempt_count": 5
      }
    }
  ]
}

Security alerts

Configure alerts for security events:
{
  "settings": {
    "alerts": {
      "security": {
        "failed_auth_threshold": 5,
        "unusual_access_pattern": true,
        "permission_escalation": true,
        "notification_channels": [
          "[email protected]",
          "slack:#security"
        ]
      }
    }
  }
}

Best practices


Grant users only the permissions they need. Start with minimal access and add permissions as needed.
Implement automatic rotation for API keys and service credentials. Use short-lived tokens where possible.
Keep audit logs enabled and review them regularly. Set up alerts for suspicious activity.
Restrict API access to known IP ranges, especially for production environments.
Require MFA for user accounts. Use certificate-based auth for service accounts when possible.
Conduct periodic access reviews. Remove access promptly when users change roles or leave.
Enable field-level encryption for sensitive transaction data beyond database encryption.
Set up real-time monitoring and alerting for security events. Investigate anomalies promptly.

Next steps