Email OTP code submission through proxy, "You've reached the maximum number of attempts. Please try to login again"


We’ve implemented a passwordless login service that asks the user for an OTP code. We receive this OTP code & email through AWS Lambda, and that function acts as a proxy to send a request to our auth0 endpoint, with the following data:

        data: {
          grant_type: '',
          otp: payload.emailCode,
          realm: 'email',
          audience: ...,
          scope: ...,
          client_id: ...,
          client_secret: ...,

Keep in mind that we have a truly passwordless implementation, where the OTP code is the sole way that users can verify their emails in our app.

This works well when the code provided is correct. When the code provided is incorrect, the response is a 403 with the following data:

  data: {
    error: 'invalid_grant',
    error_description: 'Wrong email or verification code.'

which is expected. However, when the code is wrong more than twice, then we start receiving a 403 with the following data instead:

  data: {
    error: 'invalid_grant',
    error_description: "You've reached the maximum number of attempts. Please try to login again."

Which struck me initially as a rate-limit message but from inspecting the headers, it is not a rate-limit issue:

    'x-ratelimit-limit': '30',
    'x-ratelimit-remaining': '29',

So it seems to be a protection for limiting the number of requests that a client is able to make for a given email, before they are locked out. Only after I refresh my page, am I able to make the two attempts with the OTP code, and then again, I keep receiving the ‘You’ve reached the maximum number of attempts’ message.

My questions are the following:

  1. Where can I find more documentation about the ‘You’ve reached the max # of attempts’ error_description? A google search didn’t provide me with much
  2. How can I increase the number of attempts from 2 bad attempts, as this is too limited
  3. Why does refreshing the page seem to cause this ‘reseting’ behaviour, although no information about the client is part of the payload to auth0? Does this potentially have to do with our lambda proxying implementation?