WebSocket API
The IDToken Auth Server uses WebSocket to deliver real-time authentication session updates to the browser. This is how the browser knows when the user has confirmed (or rejected) the OTP on their mobile app.
Connection
Section titled “Connection”Endpoint
Section titled “Endpoint”GET /ws/session/{sessionId}?token={wsToken}| Parameter | Source | Description |
|---|---|---|
sessionId | POST /auth/initiate response | The active session identifier |
wsToken | POST /auth/initiate response | HMAC-SHA256 authentication token |
Authentication
Section titled “Authentication”The wsToken is verified using constant-time HMAC-SHA256 comparison, preventing timing attacks on the WebSocket authentication.
Connection Rules
Section titled “Connection Rules”- One connection per session — if a new WebSocket connects for the same session, the previous connection is closed with code
4009 - Session must exist — the
sessionIdmust be present in Redis - Auto-cleanup — connection is automatically closed when the session expires or is resolved
Events
Section titled “Events”All events are JSON messages sent from the server to the client.
otp_ready
Section titled “otp_ready”Sent immediately after the session is initiated. Contains the OTP for display to the user.
{ "type": "otp_ready", "autoPassword": "4829**", "expiresAt": "2025-01-15T10:01:00Z"}The autoPassword may be partially masked depending on the server configuration.
approved
Section titled “approved”Sent when the mobile app successfully verifies the OTP and signature.
{ "type": "approved", "jwt": "eyJhbGciOiJFUzI1NiIs...", "hash": "hmac-response-verification", "random": "a1b2c3d4e5f67890", "expiresAt": "2025-01-15T11:00:00Z"}| Field | Description |
|---|---|
jwt | The signed JWT containing identity claims |
hash | Response verification HMAC for anti-forgery |
random | Random nonce from initiation (for hash verification) |
expiresAt | JWT expiration time |
rejected
Section titled “rejected”Sent when verification fails.
{ "type": "rejected", "reason": "Invalid signature"}| Reason | Description |
|---|---|
Invalid signature | ECDSA signature verification failed |
Invalid OTP | OTP mismatch (outside tolerance window) |
Too many attempts | Brute-force limit exceeded (3 attempts) |
Close Codes
Section titled “Close Codes”| Code | Meaning |
|---|---|
1000 | Normal closure (session resolved) |
4001 | Invalid wsToken |
4004 | Session not found |
4009 | Replaced by newer connection |
Browser Client Example
Section titled “Browser Client Example”function connectSession(sessionId, wsToken) { const ws = new WebSocket( `wss://auth.idtoken.example.com/ws/session/${sessionId}?token=${wsToken}` );
ws.onmessage = (event) => { const data = JSON.parse(event.data);
switch (data.type) { case 'otp_ready': displayOTP(data.autoPassword); break;
case 'approved': handleSuccess(data.jwt, data.hash, data.random); ws.close(); break;
case 'rejected': handleRejection(data.reason); ws.close(); break; } };
ws.onclose = (event) => { if (event.code === 4009) { console.log('Connection replaced by another tab'); } };
return ws;}