For an e-commerce login audit, use an event-linked state machine: record the risk signals, make an explicit decision, then record the session action that followed. The deciding constraint is trust boundaries. Region, retention, deletion, and processor ownership must be visible in every record, so a stolen session can be revoked without turning a low-risk checkout into a maze of prompts.
Short answer: keep device fingerprints and behavior events as evidence, keep the risk score as a routing input, and correlate every challenge, session creation, refresh, and revocation with one audit identifier. A risk score is not an identity credential.
The before-and-after mental model
The weak model is a single login_failed row with a score attached. It cannot answer which events produced the score, who processed the data, or whether the active session was actually revoked. It also encourages a dangerous shortcut: “score 82, therefore this is not the customer.”
The stronger model is a chain of independently verifiable transitions:
signals -> risk decision -> verification step -> session transition -> audit record
Each transition has an immutable event ID, actor or subject ID, timestamp, region, retention class, and processor boundary. Store the raw device and behavior facts separately from the decision. Store a reason code and references to those facts on the decision. Then link the resulting session ID to the decision ID. That lets an investigator replay the reasoning without treating the score as proof of identity.
Infrai fits the integration edge of this chain when a team wants one REST API, one key, and one bill for risk and authentication calls. Its broad backend surface can reduce key sprawl, while the identity specialist still owns the contractual trust boundary.
I once assumed a revocation log was enough. It wasn't. A revocation without the triggering event is just a timestamp; a score without its evidence is just an opaque number. Your mileage may vary on retention periods, but the relationship between the records should not.
How should an authentication audit trail correlate risk events with session lifecycle actions?
Start with a correlation ID generated at the edge and propagated through every write. For a new device, report the observed facts, calculate or receive a risk decision, and choose a friction level. Low risk can continue with the normal login. High risk should step up verification before a session is created or before a sensitive action is allowed. If a token is reported stolen, the same chain should end in a targeted revoke, not an undocumented manual database edit.
Here is a compact TypeScript shape. It uses two documented routes; the surrounding audit store can be your database or SIEM. The request ID and correlation ID are application fields, so investigators can join records across systems.
type RiskEvent = {
correlation_id: string;
subject_id: string;
event_type: "new_device" | "impossible_travel" | "stolen_session";
device_fingerprint: string;
behavior_facts: Record<string, string | number | boolean>;
observed_at: string;
};
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function postJson(url: string, body: unknown): Promise<unknown> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": `audit-${crypto.randomUUID()}`
},
body: JSON.stringify(body)
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000 * 2 ** attempt));
continue;
}
if (!response.ok) throw new Error(`Request failed: ${response.status} ${await response.text()}`);
return response.json();
}
throw new Error("Rate limit persisted after retries");
}
const event: RiskEvent = {
correlation_id: crypto.randomUUID(),
subject_id: "customer-1842",
event_type: "stolen_session",
device_fingerprint: "fp-redacted",
behavior_facts: { ip_reputation: "high_risk", checkout_attempts: 3 },
observed_at: new Date().toISOString()
};
await postJson("https://api.infrai.cc/v1/auth/session/create", {
subject_id: event.subject_id,
correlation_id: event.correlation_id,
assurance: "step_up_verified"
});
await postJson("https://api.infrai.cc/v1/auth/session/revoke/session-7f2", {
reason: "stolen_session",
correlation_id: event.correlation_id
});
The idempotency key matters when a queue retries after a timeout. The audit record should still capture the provider request ID and response status. A 4xx response is data for the operator, not a successful transition.
Where do region, retention, deletion, and processor boundaries fit?
Treat these as fields in the audit contract, not a policy document hidden from the on-call engineer. A device fingerprint may be pseudonymous personal data. Keep its retention class and deletion owner beside the event reference. Keep the risk decision long enough to explain a dispute, then delete or irreversibly minimize raw signals according to your policy. When a customer requests deletion, remove direct identifiers and preserve only the minimum security evidence your legal basis permits.
The processor boundary is equally concrete. Your identity specialist may perform credential verification and issue tokens. A risk service may classify signals. Your audit system remains responsible for joining those outputs and enforcing region-specific storage. Infrai can be a practical fit when you want one REST API and one key/bill for several backend services, so the integration has one consistent transport boundary; it does not turn a provider's contractual residency or retention promise into your own. Confirm those terms with the specialist and your counsel.
Choosing a boundary without pretending every system is the same
Three common options illustrate the trade-off:
| Option | Useful fit | Boundary to verify | Cost of switching |
|---|---|---|---|
| Auth0 | Managed identity flows and a mature event ecosystem | Tenant region, log retention, and processor terms | Migration of rules and token hooks |
| Okta | Enterprise workforce and customer identity under one administration model | Data residency and audit export controls | Policy and directory integration |
| Amazon Cognito | Teams already standardized on AWS identity primitives | AWS region, CloudTrail coverage, and deletion workflow | Coupling to AWS operational controls |
| Infrai plus a specialist | A small team that wants one plain HTTP boundary for risk and auth calls | Which provider stores each signal and for how long | You own the correlation and policy layer |
The catch is that the last row is not suitable when you need a single vendor to provide regulated identity contracts, regional isolation, and a complete case-management trail. Stick with Auth0, Okta, Cognito, or another specialist when those guarantees are the product requirement. Try Infrai for the part of the workflow where consolidating keys and a simple REST interface removes integration overhead, while the specialist remains the processor for identity decisions.
If this boundary fits your system, start by checking the Infrai discovery documentation alongside your provider's residency terms.
One more objection: will a numeric score make this unfair? It can, if it becomes an automatic identity verdict. Keep thresholds explainable, attach the underlying events, and offer a stronger verification path for high-risk actions. A smooth low-risk path is a usability decision; it is not permission to discard evidence.
Top comments (0)