Skip to content

Data Privacy & GDPR

Gatewyse provides two admin operations for handling data-subject requests under the GDPR: a data export (right of access) and an erasure (right to be forgotten). Both are RBAC-gated and bounded by the caller’s own scope: a deployment administrator can act on any user, an organization administrator only on users in their organization, a department administrator only on their department. An out-of-scope target returns 404 Not Found and the refusal is written to the audit trail.

Data Export (Article 15)

Retrieve a complete, secret-free bundle of a single user’s data as a downloadable JSON file.

GET /api/admin/users/:id/data-export
  • Permission: requires the users:read permission.
  • Scope: bounded by assertWithinScope. The target must be a user the caller may administer, or the request returns 404 Not Found — the same response as a genuinely missing user, so the endpoint cannot be used to discover who exists outside your scope.
  • Response: application/json served as a file attachment (Content-Disposition: attachment; filename="data-export-<id>.json"), pretty-printed.

The bundle assembles the user’s data across collections:

FieldContents
exportedAtISO-8601 timestamp of when the bundle was generated.
subjectThe userId and tenantId the export covers (the deployment identifier).
profileThe user record, with all secrets stripped (passwordHash, mfaSecret, recoveryCodes, passwordHistory are excluded).
apiKeysThe user’s API keys, with the stored key hash (keyHash) removed.
usageRecordsThe user’s usage records.
requestLogsA capped, most-recent sample of the user’s request logs (see below).

Request-log sampling

To keep the export synchronous and bounded, request logs are capped at a sample of the 5000 most recent entries. The requestLogs object reports both the true size and whether the sample was truncated:

"requestLogs": {
"totalCount": 41230,
"sampleLimit": 5000,
"truncated": true,
"records": [ /* up to 5000 most-recent request logs */ ]
}

The export is read-only — it never modifies the user or their data. It is secret-free by construction: password hashes, MFA secrets, recovery codes, password history, and API-key hashes are all excluded.

Erasure / Right to be Forgotten (Article 17)

Anonymize a user’s personal data in place and scrub the personal content captured in their request logs.

POST /api/admin/users/:id/erase
Content-Type: application/json
{ "confirm": true }
  • Permission: requires the users:delete permission.
  • Scope: bounded by assertWithinScope — the target must be a user the caller may administer.
  • Confirmation: the body must include { "confirm": true }. Any other body is rejected with a validation error (Erasure requires { "confirm": true }). This is a destructive operation with no automatic undo.

What erasure does

The user record is anonymized, not deleted, so foreign-key references from other collections stay valid:

  • Email is replaced with erased-<userId>@deleted.invalid (the user id keeps the anonymized address unique under the email index).
  • Name is cleared.
  • Status is set to deactivated.
  • Auth secrets are wiped: password hash, MFA secret, recovery codes, password history, and any SSO linkage (externalId, ssoProviderId) are removed; MFA is turned off.
  • Request/response bodies captured in the user’s request logs are unset (scrubbed). The response reports how many log documents were scrubbed.

What erasure preserves

The append-only audit chain is left intact. Audit entries are tamper-evident integrity records that reference the (now anonymized) user id — they are not a store of the erased personal data, so removing them would break the audit chain’s verifiability without improving privacy.

Response

{
"data": {
"message": "User data erased",
"userAnonymized": true,
"requestLogsScrubbed": 128
}
}