Urgent.News

What's breaking now, across thousands of outlets.

Tech

Node.js Email Verification Needs Atomic Tokens

Email verification looks like a small feature: create a token, send a message, and accept the token when the user clicks it. In a real Node.js service, the difficult part is not generating the token. It is deciding what happens when the user clicks twice, the link expires during a retry, or two API workers process the same request at nearly the same time. The reliable design is to treat…

Email verification in Node.js applications is a simple process: generate a token, send an email, and confirm the user's identity by clicking the link. However, the real challenge lies in handling potential issues when users click the link multiple times, the link expires during retries, or multiple API workers attempt to process the same request simultaneously.

The recommended solution is to treat verification as a state transition, backed by a single atomic database operation. The email serves only as a delivery mechanism, while PostgreSQL remains the authoritative source for determining a token's validity and consumption status.

A common mistake in naive implementations is the following sequence:

1. Read the verification row.

2. Verify that `used_at` is empty and `expires_at` is in the future.

3. Mark the row as used.

4. Activate the user.

Two concurrent requests can complete step 2 before either request reaches step 3, resulting in the same token being accepted twice. This can lead to duplicate welcome messages, repeated audit events, or an account activation even when it should have failed. Similar ambiguity can arise from email delivery, where temporary or disposable email addresses may cause delayed messages or duplicates.

To mitigate these issues, it is advised to store a cryptographic digest of the token instead of the raw value in the database. This approach ensures that even if a database snapshot is exposed, the attacker will not have usable verification links.

The recommended database schema includes a table called `email_verification_tokens` with columns for the token digest, user ID, expiry time, and consumption time. A partial index is created to optimize common lookups for tokens that can still be consumed. A cleanup job can be used to remove old rows, but this process should never decide the validity of a current request.

When consuming the token, a conditional UPDATE statement is used to check the digest, expiry, and unused state while acquiring a row lock. Only one successful request should be able to update a row, ensuring that the token is accepted only once. If the activation fails, the entire transaction should be rolled back to prevent the user from receiving a "try again" response while their only token is already consumed.

The Node.js code should treat an empty result from the query as a normal rejection, rather than a database error. This way, internal failures can be logged with a safe reason, while the public response remains broad and consistent.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Keeping obfuscated names stable across releases with Nebula''s seed map

Ship an obfuscated .NET build and you get a mapping: MyApp.Billing.Invoice.Recalculate became n.a.b , and you tuck away the map so you can decode the crash reports that will arrive.

  • Nebula.NET seed map preserves obfuscated names across releases
  • Unchanged members retain original names for easier crash report decoding
  • Seed map improves crash symbolication and CI integration

Designing a license gate: where to check, what to cache, and when to fail closed

Adding Keyright to a .NET app looks like one line: client.Validate() returns a LicenseInfo , you check IsValid , done. That line is the easy part, and it is not where licensing goes wrong.

  • One object performs SDK validation to prevent scattered Validate() calls.
  • LicenseSnapshot record is immutable to prevent unauthorized licensing state modifications.
  • When validation fails, the gate defaults to free edition to avoid ambiguous paid status.

SoundSafari: ten seconds of recording, one minute of listening

Built for the DEV Week 1 “Touch Grass” challenge . What I Built SoundSafari is a small outdoor listening exercise. You record ten seconds of your surroundings, get a tentative sound category, and use…

  • SoundSafari app encourages users to record 10 seconds of ambient sound
  • Users listen for 1 minute to outdoors after recording and write reflection
  • App uses Audio Spectrogram Transformer for local audio classification

Your Low-Code Platform Is a Credential Store Whether You Planned It or Not.

I was on a call with a customer's IT lead four months after their system went live. He was calm, which was the strange part.

  • Low-code platforms treat credentials as regular data.
  • Permissions, export paths, and audit trails inherit from data model.
  • Cloning applications spreads credentials to multiple environments.

More from Saturday 10 October →