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 strictly tenant-scoped — an administrator can only export or erase users within their own tenant.
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:readpermission. - Scope: tenant-scoped. The user must belong to the caller’s tenant, or the request returns
404 Not Found. - Response:
application/jsonserved as a file attachment (Content-Disposition: attachment; filename="data-export-<id>.json"), pretty-printed.
The bundle assembles the user’s data across collections within the tenant:
| Field | Contents |
|---|---|
exportedAt | ISO-8601 timestamp of when the bundle was generated. |
subject | The userId and tenantId the export covers. |
profile | The user record, with all secrets stripped (passwordHash, mfaSecret, recoveryCodes, passwordHistory are excluded). |
apiKeys | The user’s API keys, with the stored key hash (keyHash) removed. |
usageRecords | The user’s usage records. |
requestLogs | A 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/eraseContent-Type: application/json
{ "confirm": true }- Permission: requires the
users:deletepermission. - Scope: tenant-scoped — the user must belong to the caller’s tenant.
- 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 tenant’s 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 }}