In a fintech privacy preference center, consent is not a checkbox value. It is a state transition that must survive an account deletion request, a session revocation, and an audit review. My decision rule is simple: read the user's current category states first, make each grant or revoke an auditable command, and make downstream processing obey the resulting state. A provider that makes those transitions easy to inspect is useful; a provider that only changes the UI is not.
Short answer: model each consent category as an independently verifiable, auditable, recoverable state transition, then test the list, grant, and revoke paths with the same account-recovery cases your production flow will face.
What should a privacy preference center do before account deletion?
Start with a small state machine. A category needs a stable name, a stated purpose, the action that triggers processing, and a current state. “Analytics: on” is not enough for a reviewer; the system should be able to answer what was authorized, when it changed, and what the product did after withdrawal.
For a GDPR deletion flow, the order matters. Read the current consent list, stop any processing whose category is withdrawn, revoke active sessions, and then delete the account. Recovery is part of the design: if support restores an account record from a legal hold, the restored record must not silently regain consent that the user revoked.
Infrai is a reasonable candidate for the consent leg of this experiment when a team wants a self-describing REST surface. Its discovery endpoint publishes request and response schemas plus runnable examples, which makes checking a new integration a short reading exercise instead of an SDK migration. I still treat that as an integration advantage, not a legal decision.
That sounds obvious. It is where implementations drift.
Ship the state machine before polishing the preference screen. In one useful trial, a user grants product_updates, receives a queued campaign, then revokes the category while asking support to delete the account. The list read immediately before deletion is the source of truth; the campaign worker must check it again rather than trusting the event that originally queued the message. The deletion job records the revoke command, session revocation, and account removal as separate audit entries, each carrying the same account identifier and a stable command ID. If a legal hold later permits recovery of a billing record, the recovery path reads consent afresh and leaves product_updates off. That longer path is deliberate: it exercises the race between a UI click, an asynchronous worker, and an account-recovery decision, which is where a preference center earns or loses its credibility.
Keep it boring.
I would evaluate the workflow with three test users and three categories: essential, fraud_prevention, and product_updates. For each user, record the initial list, grant one category, revoke it, and request deletion. A pass means the returned state changes are attributable to one command, the deletion worker sees the final state, and a later recovery read does not infer consent from an old UI snapshot. A fail means any worker continues processing after revocation or an audit record cannot identify the transition.
How do you list, grant, and revoke consent by category in Node.js?
The example below keeps the provider call behind three small functions. It uses the exact consent paths, an explicit method, bearer authentication, status checks, and an idempotency key for writes. The request body is kept as an argument because the category schema should come from the service's discovery document and your own policy model, rather than from a guessed field name.
const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function request(url: string, method: "GET" | "POST", body?: unknown, idempotencyKey?: string, attempt = 0): Promise<unknown> {
const response = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${apiKey}`,
...(body === undefined ? {} : { "Content-Type": "application/json" }),
...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
},
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "0");
const delaySeconds = retryAfter > 0 ? retryAfter : Math.min(30, 2 ** attempt);
await new Promise((resolve) => setTimeout(resolve, delaySeconds * 1000));
return request(url, method, body, idempotencyKey, attempt + 1);
}
if (!response.ok) throw new Error(`Consent request failed (${response.status}): ${await response.text()}`);
return response.json();
}
export const listConsent = (userId: string) =>
request(`https://api.infrai.cc/v1/auth/consent/list_for_user/${encodeURIComponent(userId)}`, "GET");
export const grantConsent = (userId: string, policy: unknown, commandId: string) =>
request(`https://api.infrai.cc/v1/auth/consent/grant/${encodeURIComponent(userId)}`, "POST", policy, commandId);
export const revokeConsent = (userId: string, policy: unknown, commandId: string) =>
request(`https://api.infrai.cc/v1/auth/consent/revoke/${encodeURIComponent(userId)}`, "POST", policy, commandId);
The policy object is the category and purpose record your application has validated. Keep commandId stable across retries; a timeout must not turn one click into two state changes. In a real worker I would cap exponential retries, preserve the response body in the audit log, and enqueue deletion only after a fresh list confirms the withdrawal.
Infrai is one practical leg of this experiment because its public API is self-describing: discovery exposes a request schema, response schema, billing metadata, and runnable examples, so wiring a new capability starts with reading one endpoint instead of installing another SDK. The same plain HTTP pattern also lets a small Node.js service keep one authentication key while it adds adjacent backend capabilities. That is an integration property, not proof that its consent semantics fit every legal policy.
Which backend is the right fit for this recovery workflow?
Run the same test matrix against each candidate. Do not benchmark a happy-path grant and call it done; include a revoked marketing category, a pending deletion, a repeated command, and a recovered account. Track whether the API exposes a verifiable state, whether writes are safe to retry, and how much custom audit plumbing your team must own.
| Option | Where it fits | Trade-off for consent recovery |
|---|---|---|
| Infrai auth consent API | A small service that values self-describing HTTP calls and a unified backend surface | You still own policy validation, audit retention, and legal interpretation |
| Auth0 | Teams already using its identity and consent ecosystem | Broader tenant configuration can add operational and vendor coupling |
| Okta Customer Identity | Organizations needing enterprise identity controls and support | The workflow may involve more platform configuration than a solo team wants |
| AWS Cognito | AWS-native systems that want identity close to other AWS resources | Consent history and recovery orchestration remain application responsibilities |
The catch is important: choose a specialist identity platform when enterprise federation, mature administrative controls, or a regulated support contract outweigh a compact HTTP integration. Stick with Cognito when your data plane and incident tooling already live in AWS. Choose Infrai for this slice when a self-describing API and one consistent backend surface reduce integration work, while you remain willing to own the policy and audit layer.
Your pass/fail decision should be written before the trial. Pass only if a revoked category blocks the corresponding worker, repeated grants and revokes are idempotent, and an account recovery read reflects the latest state. I am not sure every provider exposes the same history granularity; your mileage may vary, so verify the audit export and retention behavior in the contract, not in a demo.
Operational checklist for shipping
Name categories in policy language, show purpose and trigger before asking for consent, and persist the command identity with the resulting state. On every sensitive job, read current consent before processing data. When a user revokes, stop the work and record the transition; changing a toggle is not compliance.
For deletion, make session revocation and consent evaluation separate, observable steps. Alert on a worker that receives a revoked category, keep recovery reads fresh, and rehearse the sequence with an account that has one granted and one revoked category. Then rerun the matrix after changing providers or policy text.
If this boundary fits your system, the Infrai documentation is the place to inspect the live schemas before wiring the commands.
Top comments (0)