06.A
Auth · TOTP + JWT
Password → TOTP → tokens issued → silent refresh on 401. The user never sees a re-login.
$auth.demo --start --mfa=totp
>8 stages · play to walk through
step 1 / 8
Client
browser · axios
local state
access_tokenttl 15m
refresh_tokenttl 7d (httpOnly cookie)
totp · 349 360
Auth Service
lambda · /login /verify-totp /refresh
wire log · lane bus
→ POST /login
User Store
dynamodb · users · refresh_jti
users#jun.cao
pw_hash: argon2$...
totp_secret: ●●●●●●●●●●
refresh_jti: —
// the trick: silent refresh interceptor
● client · axios.ts
// axios silent refresh interceptor
api.interceptors.response.use(
r => r,
async (err) => {
const cfg = err.config;
if (err.response?.status === 401 && !cfg._retry) {
cfg._retry = true;
await api.post('/refresh'); // httpOnly cookie sent
return api(cfg); // retry original request
}
throw err;
}
);The access token is short-lived (15 min) and held in JS memory; the refresh token lives 7 days in an httpOnly cookie so it can't be read by JS — only the browser sends it back to /refresh.
When a request returns 401, the axios interceptor catches it, calls /refresh (the cookie rides along automatically), and retries the original call. The user never sees a re-login.
Each refresh rotates the refresh token'sjti on the server — replay attacks invalidate the chain immediately.