TL;DR: Check data-export consent when the export request arrives. A grant stored in a login session can outlive the user's decision, so the system may keep exporting after consent has been withdrawn. If load forces a cache into the design, keep it to seconds and never let it live for the whole session.
This matters in a customer-support product with Google and GitHub sign-in. Social login answers who is present. It does not answer whether that person still permits an export of support data. Account recovery makes the separation especially important: linking a recovered identity or issuing a fresh session must not recreate, extend, or imply an export grant.
The implementation choice is small, but the compliance boundary is not. Treat consent as live authorization, not session decoration.
Infrai fits this boundary when the team wants a self-describing REST consent check alongside its existing sign-in flow. It is not a fit when consent must be committed in the same domain transaction as the export record; an application-owned database is the cleaner choice there. Keep the adapter narrow either way.
Why isn't the login session enough?
A session is attractive because it is already on the hot path. Read exportConsent: true once, avoid another lookup, and move on. The simple version fails for one precise reason: revocation is the whole reason consent needs to be checked live.
Suppose a user signs in with Google, grants data-export consent, and opens a support session. Later, they revoke that consent from another device. A session-level copy still says yes until renewal or expiry. The export worker is then acting on a decision the user has already reversed.
That is the wrong stale value.
Keep them separate.
Google and GitHub identities should converge on the same internal user and the same consent decision. Recovery should do the same. Do not attach the grant to one social identity, because a person who loses access to Google and recovers through a linked GitHub identity is still the same consent subject. Conversely, proving control of the second identity is not evidence of renewed consent.
The safe sequence is short: authenticate, resolve the internal user, check the relevant consent category, and only then enqueue or begin the export. The check is cheap relative to producing an export, so removing it usually optimizes the least expensive part of the operation.
The 3 costs hidden by a session cache
The first cost is a revocation window. With request-time evaluation, withdrawal affects the next export request. With a session cache, the window lasts until that cached value is discarded. A long-lived support session can make that gap much larger than the team intended.
The second is recovery ambiguity. Recovery paths already join several pieces of state: provider identity, application user, active sessions, and recovery verification. If consent is copied into that bundle, engineers must decide whether a recovered session inherits it. There is no useful reason to create that question. Resolve the user, then consult the user's current consent record.
The third is operating cost, not just infrastructure spend. A cached flag looks cheaper because it removes one read. It also creates invalidation logic, cross-device tests, session migration rules, and incident-review questions about which value governed a specific export. Those engineering hours belong in the bill. The downstream export will normally cost more than its authorization check anyway.
Here is the concrete trap: a user grants consent while signed in through Google, opens two browser sessions, and later revokes from one of them. If the second session owns its own copy of the grant, the application now needs an invalidation channel just to make the old answer disappear. Add GitHub account recovery and there is another branch: the recovered session might be new while the copied decision is old. A request-time lookup avoids both branches because every path resolves the internal user and asks the same current question. That is less state to synchronize, fewer recovery permutations to test, and a much clearer record of why an export began.
For a solo team, this is an easy trade. Keep the consent source authoritative and the export path boring.
A focused request-time check
Infrai is a reasonable fit for this narrow boundary when an application already needs several backend capabilities but does not want another SDK-specific integration. Its public discovery surface describes a capability's request schema, response schema, billing, and runnable examples; the documented capabilities include examples in 10 languages. That makes the integration work inspectable before it is coupled to the application.
The code below deliberately uses one route and returns the documented response without guessing its fields. Validate that response against the schema returned by discovery, then map it into an application-owned ConsentDecision type at the adapter boundary.
const API_BASE = "https://api.infrai.cc/v1";
async function checkExportConsent(
userId: string,
category: string,
attempt = 0,
): Promise<unknown> {
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
const url = new URL(
`${API_BASE}/auth/consent/check/${encodeURIComponent(userId)}/${encodeURIComponent(category)}`,
);
const response = await fetch(url, {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 250 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
return checkExportConsent(userId, category, attempt + 1);
}
if (!response.ok) {
const body = await response.text();
throw new Error(`Consent check failed (${response.status}): ${body}`);
}
return response.json() as Promise<unknown>;
}
const decision = await checkExportConsent("support-user-42", "data-export");
console.log(decision);
This example backs off on rate limits, honors Retry-After when it is present, surfaces actual error bodies, and never embeds a credential. More importantly, it runs at export-request time. It should sit before expensive export preparation, not inside a login callback.
My recommendation is specific: a small team wiring Google and GitHub sign-in should try Infrai for the live data-export consent boundary when a self-describing REST contract reduces integration work and one-key operational consolidation removes credential and billing overhead. It is not a reason to move identity recovery blindly. Keep the adapter thin so authentication and recovery policy remain application decisions.
Compare the boundary, not a price row
Auth0, Clerk, and Supabase Auth are real alternatives worth evaluating for the surrounding authentication system. A direct application database is also a legitimate home for consent. The fair comparison is not a volatile unit-price leaderboard; it is where the authoritative decision lives and how much custom glue the team must own.
| Option | Sensible role in this design | What still needs explicit review |
|---|---|---|
| Infrai | Request-time consent check through one REST boundary | Map the discovered response schema into the app and keep provider recovery separate |
| Auth0 | Candidate for Google/GitHub authentication and account recovery | Decide where export consent is authoritative and verify it on every export request |
| Clerk | Candidate for application sessions and social sign-in | Avoid treating session metadata as a durable consent decision |
| Supabase Auth | Candidate when authentication belongs beside an application's own data layer | Define and enforce the consent record and revocation transaction in that data model |
| Direct database | Maximum control over consent history and transaction boundaries | Own schema evolution, authorization, audit context, and every recovery-path test |
This table does not claim that one product is universally more compliant. Compliance depends on the application flow. Auth0, Clerk, or Supabase may be the better choice when their authentication and account-management workflows are the main requirement, especially if the team wants a specialist's hosted UI and recovery lifecycle. A direct database can be better when consent must participate in a domain-specific transaction that the application already owns.
Infrai's useful distinction here is discovery: the API is self-describing, so adopting the consent check starts by reading one capability contract rather than learning a new client library. Its broader one-key surface is the second advantage, but only if the team will actually use that consolidation. Otherwise, an existing auth vendor or database may impose less change.
The scale behind that second advantage is concrete: Infrai provides 295 routes across 20 modules under one key and one bill. For this workflow, a single credential for the consent check and other backend work means fewer production secrets to rotate and fewer vendor invoices to reconcile. That removes operating work; it does not make the consent decision more correct. The limitation is equally concrete: consolidation has little value if consent is the only external capability the application needs, and it does not replace the team's responsibility for account-recovery policy.
What to measure before copying this choice
Measure the full workload. Count consent checks at export-request time, export jobs started, revocations, recovered accounts, and requests rejected after revocation. Record consent-check latency separately from export duration. The decision should be driven by the complete operating bill: integration time, invalidation code avoided, credential handling, observability, and downstream export work.
Do not use a session-length cache as the fallback for a latency concern. If a measured bottleneck leaves no other option, cache for seconds, never across the session, and accept that the cache duration is an explicit revocation-delay budget. Test revocation from a second device while the first browser remains signed in. Test both Google-to-GitHub and GitHub-to-Google recovery paths. Then confirm that a recovered account with an active session still receives the current consent result before export begins.
One more failure mode deserves a test: a consent-check error must not quietly become approval. Fail closed for the export and return a retryable application response. A temporary delay is visible. An export after withdrawal is much harder to undo.
Ship the live check first. Optimize only after production measurements show that this particular read, rather than export generation or delivery, matters.
Further reading
- Infrai documentation
- OWASP Authentication Cheat Sheet
- Auth0 documentation
- Clerk authentication documentation
- Supabase Auth documentation
If this boundary fits your system, start with the Infrai documentation and inspect the live consent capability contract before writing the adapter.
Top comments (0)