DSAR Handler
API reference for the DSARHandler class - automate GDPR data subject access requests.
DSAR Handler
The DSARHandler automates GDPR Data Subject Access Requests (DSAR), including data access, portability, and erasure.
What is DSAR?
Under GDPR, users have the right to:
| Right | DSAR Type | Description |
|---|---|---|
| Access | access | Request a copy of their data |
| Portability | portability | Export data in machine-readable format |
| Erasure | erasure | "Right to be forgotten" |
| Rectification | rectification | Correct inaccurate data |
| Restriction | restriction | Limit data processing |
| Objection | objection | Object to specific processing |
Initialization
import { DSARHandler, createDSARHandler } from '@priv/compliance-sdk';
const dsar = new DSARHandler({
siteId: 'your-site-id',
api: {
endpoint: 'https://api.priv.io/v1',
apiKey: 'your-api-key',
},
requestExpiryDays: 30,
});Configuration
DSARHandlerConfig
interface DSARHandlerConfig {
/** Unique site identifier (required) */
siteId: string;
/** API configuration */
api?: {
endpoint: string;
apiKey: string;
timeout?: number; // Default: 10000ms
};
/** Days until request expires */
requestExpiryDays?: number; // Default: 30
/** Callback when request created */
onRequestCreated?: (request: DSARRequest) => void;
/** Callback when request completed */
onRequestCompleted?: (request: DSARRequest) => void;
/** Custom data collectors for exports */
dataCollectors?: DataCollector[];
}Methods
createRequest(type, email)
Create a new DSAR request.
const request = await dsar.createRequest('access', 'user@example.com');
console.log('Request ID:', request.id);
console.log('Verification Token:', request.verificationToken);
// Send verification email to user
sendVerificationEmail(request.email, request.verificationToken);Parameters:
| Name | Type | Description |
|---|---|---|
type | DSARRequestType | Type of request |
email | string | User's email address |
Returns: Promise<DSARRequest>
Request Types:
type DSARRequestType =
| 'access' // Copy of data
| 'portability' // Export data
| 'erasure' // Delete data
| 'rectification'// Correct data
| 'restriction' // Limit processing
| 'objection'; // Object to processinggetRequest(requestId)
Retrieve a DSAR request by ID.
const request = await dsar.getRequest('dsar-abc123');
if (request) {
console.log('Status:', request.status);
console.log('Type:', request.type);
console.log('Created:', new Date(request.requestedAt));
}Parameters:
| Name | Type | Description |
|---|---|---|
requestId | string | Request identifier |
Returns: Promise<DSARRequest | null>
verifyRequest(requestId, token)
Verify a request using the verification token (sent via email).
// User clicks verification link: /verify-dsar?id=xxx&token=yyy
const isValid = await dsar.verifyRequest(requestId, token);
if (isValid) {
// Proceed to process the request
await dsar.processRequest(requestId);
} else {
console.error('Invalid or expired verification');
}Parameters:
| Name | Type | Description |
|---|---|---|
requestId | string | Request identifier |
token | string | Verification token |
Returns: Promise<boolean>
processRequest(requestId)
Process a verified DSAR request.
try {
const completed = await dsar.processRequest(requestId);
if (completed.type === 'access' || completed.type === 'portability') {
// Data is available
const data = completed.data;
sendDataToUser(completed.email, data);
} else if (completed.type === 'erasure') {
// Data has been deleted
notifyUserOfDeletion(completed.email);
}
} catch (error) {
console.error('Failed to process request:', error);
}Parameters:
| Name | Type | Description |
|---|---|---|
requestId | string | Request identifier |
Returns: Promise<DSARRequest>
Behavior by Type:
| Type | Action |
|---|---|
access | Collects and returns user data |
portability | Collects and returns data in portable format |
erasure | Deletes all user data |
| Others | Marks as completed (manual processing) |
exportData(userIdHash)
Export all data for a specific user.
const data = await dsar.exportData('abc123...');
console.log('Export Date:', new Date(data.exportedAt));
console.log('Consent:', data.consent.current);
console.log('History:', data.consent.history.length, 'events');
console.log('Custom Data:', data.customData);Parameters:
| Name | Type | Description |
|---|---|---|
userIdHash | string | User identifier hash |
Returns: Promise<DSARExportData>
Export Format:
interface DSARExportData {
exportedAt: number;
dataSubject: {
idHash: string;
email?: string;
};
consent: {
current: ConsentPreferences | null;
history: AuditLogEntry[];
};
customData?: Record<string, unknown>;
}deleteData(userIdHash)
Delete all data for a user (erasure request).
await dsar.deleteData('abc123...');
// All user data is now deleted:
// - Consent preferences
// - Audit log entries
// - DSAR requests
// - Custom data (via data collectors)Parameters:
| Name | Type | Description |
|---|---|---|
userIdHash | string | User identifier hash |
Returns: Promise<void>
downloadExport(data, filename?)
Trigger a download of exported data.
const data = await dsar.exportData(userHash);
// Download as JSON file
dsar.downloadExport(data, 'my-data-export.json');Parameters:
| Name | Type | Description |
|---|---|---|
data | DSARExportData | Exported data |
filename | string | Optional filename |
Returns: void
registerDataCollector(collector)
Register a custom data collector for exports.
dsar.registerDataCollector({
name: 'orders',
collect: async (userIdHash) => {
// Fetch user's orders from your database
const orders = await db.orders.findByUser(userIdHash);
return { orders };
},
});
dsar.registerDataCollector({
name: 'preferences',
collect: async (userIdHash) => {
return {
theme: localStorage.getItem('theme'),
language: localStorage.getItem('language'),
};
},
});Parameters:
| Name | Type | Description |
|---|---|---|
collector | DataCollector | Custom collector |
DataCollector Interface:
interface DataCollector {
name: string;
collect: (userIdHash: string) => Promise<Record<string, unknown>>;
}getPendingRequests()
Get all pending DSAR requests.
const pending = dsar.getPendingRequests();
pending.forEach((req) => {
console.log(`${req.id}: ${req.type} - ${req.status}`);
});Returns: ReadonlyArray<DSARRequest>
DSAR Request Object
interface DSARRequest {
/** Unique request ID */
id: string;
/** Request type */
type: DSARRequestType;
/** Current status */
status: DSARStatus;
/** User identifier hash */
userIdHash: string;
/** User's email */
email: string;
/** Request creation timestamp */
requestedAt: number;
/** Completion timestamp */
completedAt?: number;
/** Request expiration timestamp */
expiresAt: number;
/** Verification token */
verificationToken?: string;
/** Exported data (for access/portability) */
data?: DSARExportData;
}
type DSARStatus =
| 'pending' // Awaiting verification
| 'processing' // Being processed
| 'completed' // Fulfilled
| 'rejected' // Rejected
| 'expired'; // ExpiredFull Example: DSAR Flow
1. User Submits Request
// Frontend form submission
async function handleDSARSubmit(type: DSARRequestType, email: string) {
const request = await dsar.createRequest(type, email);
// Send verification email
await sendEmail({
to: email,
subject: 'Verify Your Data Request',
body: `Click to verify: ${baseUrl}/verify?id=${request.id}&token=${request.verificationToken}`,
});
return { success: true, requestId: request.id };
}2. User Verifies Email
// Verification page handler
async function handleVerification(requestId: string, token: string) {
const isValid = await dsar.verifyRequest(requestId, token);
if (!isValid) {
throw new Error('Invalid or expired verification link');
}
// Auto-process or queue for manual review
const request = await dsar.getRequest(requestId);
if (request?.type === 'access' || request?.type === 'portability') {
// Auto-process data export
const completed = await dsar.processRequest(requestId);
return { status: 'completed', data: completed.data };
} else {
// Queue for manual review
return { status: 'pending_review' };
}
}3. Deliver Data
// For access/portability requests
async function deliverData(requestId: string) {
const request = await dsar.getRequest(requestId);
if (request?.status === 'completed' && request.data) {
// Option 1: Direct download
dsar.downloadExport(request.data);
// Option 2: Email the data
await sendEmail({
to: request.email,
subject: 'Your Data Export',
attachments: [{
filename: 'data-export.json',
content: JSON.stringify(request.data, null, 2),
}],
});
}
}4. Handle Erasure
// For erasure requests
async function handleErasure(requestId: string) {
const request = await dsar.getRequest(requestId);
if (request?.type === 'erasure') {
// Process deletion
await dsar.processRequest(requestId);
// Notify user
await sendEmail({
to: request.email,
subject: 'Your Data Has Been Deleted',
body: 'Your personal data has been removed from our systems.',
});
}
}GDPR Compliance Notes
- 30-Day Deadline: GDPR requires responding within 30 days
- Verification: Always verify the requester's identity
- Audit Trail: All DSAR actions are logged automatically
- Data Portability: Export in machine-readable format (JSON)
- Third Parties: Remember to notify data processors
Next Steps
- Audit Log - Track all DSAR events
- Script Embed - Easy integration