Dual-Token Auth and the Friction of 2FA Flows

Security & UX · May 14, 2026 · 5 min read

Security and user experience are often in direct conflict. Here is how dual-token rotation and temporary handshakes keep admin logins airtight.

Implementing Two-Factor Authentication (2FA) is easy on paper: verify password, verify 6-digit TOTP code, issue JWT.

The difficulty lies in what happens between step 1 and step 2.

When a user submits their email and password correctly, what token do you give them? If you issue a full access token before they enter their 6-digit 2FA code, 2FA is completely useless because a compromised password already yields valid authorization.

If you don't issue any token, how does the frontend prove it passed password verification when it submits the TOTP code to /api/auth/verify-2fa?


The Temporary Handshake Token

We solved this state transition using a short-lived Handshake Token:

1. POST /api/auth/login (Email + Password)
   └── Backend verifies credentials. If 2FA enabled:
       └── Returns: { requires2FA: true, tempToken: "handshake_xyz..." }
           (Valid for exactly 5 minutes, scoped ONLY to /verify-2fa)

2. POST /api/auth/verify-2fa (Bearer: tempToken, Code: "849201")
   └── Backend validates TOTP code & expires tempToken.
       └── Sets HttpOnly Refresh Token cookie & returns Access Token.

The temporary handshake token carries zero authorization permissions: it cannot fetch catalog items, it cannot mutate settings, and it expires after 300 seconds.


The Takeaway

Security is about defining strict, unambiguous intermediate states.

By making the transition between password verification and TOTP confirmation a temporary, single-purpose handshake, you eliminate session leaks while keeping the login flow smooth.

— Abu Bakar Hasan

If this resonated, let's talk. Get in touch →