Query on Authenticating Multi-Field TOTP in Browser-Based Authentication

65 views
Skip to first unread message

Ashish

unread,
Dec 17, 2025, 4:31:50 AM12/17/25
to ZAP User Group
Hi Team 
Hi ZAP Team,
I'm implementing Browser-Based Authentication using the Automation Framework and need help configuring 2-Step Authentication with TOTP. The challenge: my application uses six separate single-digit input fields for the TOTP code instead of a single input.
Authentication Flow
Step 1: User enters Username + Password → clicks Submit
Step 2: Modal appears requesting 6-digit TOTP code
The Constraint: The UI uses six distinct <input> elements (one per digit), not a single field

Here is more details: https://groups.google.com/g/zaproxy-develop/c/PckIktjzxHA/m/dpSV7cw4CQAJ

Thanks 

Ashish

unread,
Dec 17, 2025, 11:39:45 PM12/17/25
to ZAP User Group
Hi Simon
Can you please help here.

Simon Bennetts

unread,
Dec 18, 2025, 12:05:52 PM12/18/25
to ZAP User Group
Hiya,

Pro tip - I have a separate mail folder for all ZAP User Group questions.
I leave them unread until I answer them, and I always do that in reverse order.
If you post asking for an update then that actually delays when I will reply as the email thread looks more recent :D

Also, be patient, we all have a lot to do so might not get to your question for a few days.

To answer your question, no, this is not currently supported by Browser Based Authentication.
However this would be a good enhancement.
Can you share the DOM for the 6 elements used for the TOTP code?

If anyone else has examples then please share them here too, so that we can cover as many real world examples as possible.

Cheers,

Simon

Ashish

unread,
Dec 19, 2025, 2:44:21 AM12/19/25
to ZAP User Group
Thanks
Here is my page structure:
 <div class="flex flex-col"><p class="text-xs leading-3 font-medium text-gray-900 flex items-center">Enter Code <span class="text-primary-red font-semibold mx-0.5">*</span></p><form class="flex flex-col gap-4"><div style="display: flex; align-items: center;"><input autocomplete="off" aria-label="Please enter OTP character 1" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"><span class="w-5"></span><input autocomplete="off" aria-label="Please enter OTP character 2" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"><span class="w-5"></span><input autocomplete="off" aria-label="Please enter OTP character 3" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"><span class="w-5"></span><input autocomplete="off" aria-label="Please enter OTP character 4" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"><span class="w-5"></span><input autocomplete="off" aria-label="Please enter OTP character 5" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"><span class="w-5"></span><input autocomplete="off" aria-label="Please enter OTP character 6" class="select-none rounded-sm !w-[46px] !h-[46px] 3xl:!w-16 border border-solid border-[#0000003B] text-[#78909C] text-2xl leading-[1.33] font-normal outline-none" type="number" inputmode="numeric" value="" style="width: 1em; text-align: center;"></div><div class="text-red-500"><div class="flex items-center text-xs"><span class="pr-1"></span></div></div><div class="flex flex-col justify-between gap-[18.8px]"><button class="MuiButtonBase-root MuiButton-root MuiButton-Primary MuiButton-sizeMedium MuiButton-SizeMedium Mui-disabled MuiButton-root MuiButton-Primary MuiButton-sizeMedium MuiButton-SizeMedium h-9 w-full relative rounded-sm px-4 py-[6px] css-10ihhpu" tabindex="-1" type="submit" disabled="" aria-label=""><p class="text-white font-medium text-sm">Authenticate</p></button><button class="MuiButtonBase-root MuiButton-root MuiButton-outline MuiButton-outlinePrimary MuiButton-sizeMedium MuiButton-outlineSizeMedium MuiButton-root MuiButton-outline MuiButton-outlinePrimary MuiButton-sizeMedium MuiButton-outlineSizeMedium h-9 text-[13px] leading-[18px] rounded-sm px-4 py-[6px] flex flex-row border-none justify-center items-center font-medium gap-1.5 cursor-pointer uppercase css-4hfqlu" tabindex="0" type="button" aria-label="">Cancel<span class="MuiTouchRipple-root css-w0pj6f"></span></button></div></form></div>



I used the following steps in the automation YAML:
steps:
- description: Fill Email
type: USERNAME
xpath: '//*[@id="root"]/div/div/div/div/div[2]/div/div[2]/div/form/div[1]/div/input'
timeout: 1000
- description: Fill password
type: PASSWORD
xpath: '//*[@id="root"]/div/div/div/div/div[2]/div/div[2]/div/form/div[2]/div/input'
timeout: 1000
- description: TOTP Next
type: CLICK
xpath: '//*[@id="root"]/div/div/div/div/div[2]/div/div[2]/div/form/button/p'
timeout: 1000
- type: WAIT
duration: 5000
- description: "Enter Full TOTP Code"
type: TOTP_FIELD
xpath: '//*[@id="root"]/div/div/div/div/div[2]/div/div[2]/div[2]/form/div[1]/input[1]'
timeout: 2000
- description: Log In
type: RETURN
xpath: '//*[@id="root"]/div/div/div/div/div[2]/div/div[2]/div[2]/form/div[3]/button[1]'
timeout: 2000

Authentication Summary Report
1.  ,"summaryItems": [
{
"description": "Authentication failed",
"passed": false,
"key": "auth.summary.auth"
},
{
"description": "Username field not identified",
"passed": false,
"key": "auth.summary.username"
},
{
"description": "Password field not identified",
"passed": false,
"key": "auth.summary.password"
},
{
"description": "Session Handling identified",
"passed": true,
"key": "auth.summary.session"
},
{
"description": "Verification URL identified",
"passed": true,
"key": "auth.summary.verif"
}
]
,"failureReasons": [
{
"key": "auth.failure.no_successful_logins",
"description": "No successful logins."
},
{
"key": "auth.failure.logged_in",
"description": "No indication found of being logged in."
}
]

ZAP was able to log in to the application, and this was validated using a screenshot, so the above steps are working correctly.

FYI: The TOTP field is auto-complete.

However, the authentication summary report still shows a failure.

Questions
  1. What is reason for the authentication summary report shows a failure even though the login is successful?

  2. Sometimes the login API takes longer than the configured delay. Could this cause authentication to fail ?

     how can this scenario be handled to avoid false authentication failures?

thc202

unread,
Dec 19, 2025, 3:42:15 AM12/19/25
to zaprox...@googlegroups.com
Hi.

1. The report is not just about being able to authenticate successfully
but also knowing that the user is still authenticated, the latter failed
"No indication found of being logged in."
Either the verification URL is not good at all or it's missing required
session related state (e.g. custom headers). What exactly needs to be
checked, by comparing the verification request with the application
request. (You can load the auth report into ZAP and analyze the
requests, assuming you have the auth diags enabled)

2. Based on the information provided that does not seem to be the
problem, if that's an actual problem you can raise the delay.


It's not a false authentication failure, per reply in point 1.

Best regards.

Ashish

unread,
Dec 22, 2025, 6:46:56 AM12/22/25
to ZAP User Group

Hi I have verified, Screen shot steps shows successful login but unable to identify session management & verification url.
>>>>>
<<<
HTTP/1.1 200 OK
content-type: application/x-protobuffer
>>>>>
content-type: application/x-www-form-urlencoded

=sanitizedtoken0&
<<<
HTTP/1.1 200 OK
content-type: application/binary
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html
>>>>>
content-type: application/x-protobuf
<<<
HTTP/1.1 200 OK
content-type: application/x-protobuffer
>>>>>
content-type: application/x-www-form-urlencoded
authorization: sanitizedtoken1143

app=sanitizedtoken2&device=sanitizedtoken1144&sender=sanitizedtoken4&
<<<
HTTP/1.1 301 Moved Permanently
content-type: text/plain; charset=UTF-8

>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/plain
>>>>>
content-type: application/x-www-form-urlencoded
authorization: sanitizedtoken1143

X-scope=sanitizedtoken5&X-subtype=sanitizedtoken6&app=sanitizedtoken7&appid=sanitizedtoken1146&device=sanitizedtoken1144&gmsv=sanitizedtoken9&scope=sanitizedtoken5&sender=sanitizedtoken10&ttl=sanitizedtoken11&
<<<
HTTP/1.1 200 OK
content-type: text/plain; charset=UTF-8
>>>>>
content-type: application/x-protobuf
<<<
HTTP/1.1 200 OK
content-type: application/x-protobuf
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8

>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
content-type: application/json

{"username":"a...@example.com","password":"abc4ssw0rd"}
<<<
HTTP/1.1 200 OK
content-type: application/json

{"mfa_uuid":"sanitizedtoken1147"}
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/plain
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
content-type: application/json

{"mfa_uuid":"sanitizedtoken1147","token":"sanitizedtoken1148"}
<<<
HTTP/1.1 200 OK
content-type: application/json

{"token":"sanitizedtoken1149"}
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
content-type: application/json
authorization: Bearer sanitizedtoken1149

<<Failed to parse JSON>>
<<<
HTTP/1.1 200 OK
content-type: application/json

[{"name":"sanitizedtoken21","download_setting":"sanitizedtoken22"},{"name":"sanitizedtoken23","download_setting":"sanitizedtoken24"},{"name":"sanitizedtoken25","download_setting":"sanitizedtoken26"}]
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
content-type: text/plain
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
<<<
HTTP/1.1 200 OK
>>>>>
content-type: application/json
authorization: Bearer sanitizedtoken1149

<<Failed to parse JSON>>
<<<
HTTP/1.1 200 OK
content-type: application/json

{"count":0,"next":null,"previous":null,"results":[]}

>>>>>
content-type: application/json
authorization: Bearer sanitizedtoken1149

<<Failed to parse JSON>>
<<<
HTTP/1.1 200 OK
content-type: application/json

[{"name":"sanitizedtoken21","download_setting":"sanitizedtoken22"},{"id":11,"name":"sanitizedtoken23","download_setting":"sanitizedtoken24"},{"id":19,"name":"sanitizedtoken25","download_setting":"sanitizedtoken26"}]
>>>>>
content-type: application/json
authorization: Bearer sanitizedtoken1149

<<Failed to parse JSON>>
<<<
HTTP/1.1 200 OK
content-type: application/json

{"email":"a...@example.com","first_name":"sanitizedtoken19","last_name":"sanitizedtoken20","mfa":true} Screenshot from 2025-12-22 17-14-02.png

thc202

unread,
Dec 22, 2025, 9:52:17 AM12/22/25
to zaprox...@googlegroups.com
Hi,

It's really your responsibility to know which domains are needed by your
application and include them in context.

Try with whatever domain matches example7 in the shared diagnostics.

Best regards.
Reply all
Reply to author
Forward
0 new messages