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:readpermission. - Scope: bounded by
assertWithinScope. The target must be a user the caller may administer, or the request returns404 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/jsonserved as a file attachment (Content-Disposition: attachment; filename="data-export-<id>.json"), pretty-printed.
The bundle assembles the user’s data across collections:
| Field | Contents |
|---|---|
exportedAt | ISO-8601 timestamp of when the bundle was generated. |
subject | The userId and tenantId the export covers (the deployment identifier). |
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: 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 }}