Hey folks - we're debugging an issue we saw over t...
# support-questions-legacy
n
Hey folks - we're debugging an issue we saw over the weekend with a user attempting to login, were hoping for some expertise or finger pointing on places to look. Details in the thread:
Here's what we've identified thus far: 1. /auth/session/refresh fails with a 401 on login page (probably expected) 2. User attempts to login, we do a migration from our previous auth system (can provide details on how this is done if needed, but mostly straightforward and we've found that the migration works as we expect). 3. On the frontend, we see the result of a successful http call to /signin, BUT it seems
emailPasswordSignIn
throws an error. Unfortuately we do not have adequate logging here to know what the details of the error was, but we do know err.isSuperTokensGeneralError was false. 4. Within ThirdPartyEmailPassword.getRedirectionURL, context.action === 'SUCCESS', as we redirect to the OTP screen on this condition. 5. We then see /user/email/verify retrying indefinitely, and entering the OTP code and hitting submit has no effect. 6. Eventually we see a bunch of errors printed to the console:
Copy code
Encountered an error while refreshing validator st-ev[object Response]
    Uncaught (in promise): Error: No session exists
A couple of immediate questions that would be really helpful for us: 1. Broadly, any ideas here on where we should be looking to debug this further? We've taken a look at all the backend HTTP calls and a bunch of fe SDK code. Its obvious theres an error being throw here - https://github.com/supertokens/supertokens-website/blob/e7c136fbbb6a659e8cd2942486fcb9266064ad46/lib/ts/recipeImplementation.ts#L82 -, but without context its hard to tell what's going on in our case. 2. What does the SDK do in the background in between the /signin call, and firing of getRedirectionURL? It seems the error (which assumingly is triggering the indefinite reties) occurred somewhere in here.
r
I think it might be most helpful to understand why this is happening - "We then see /user/email/verify retrying indefinitely".
what is the API input / output in this case? Specifically, request and response headers and the http status code. Which SDKs of ours are you using, and which versions? Finally, are you using our pre built UI or custom UI?
n
Agree on that, For API input / output: Request Headers:
Copy code
{
  "content-type": "application/json",
  "fdi-version": "1.15",
  "rid": "emailverification"
}
Response Headers:
Copy code
{
  "content-length": "33",
  "content-type": "application/json; charset=utf-8",
  "front-token": "<redacting, but present>"
}
Response Body:
Copy code
{
  "status": "OK",
  "isVerified": true
}
Status: 200 As far as SDK - "supertokens-auth-react": "^0.26.4", We are using mostly a custom UI.
r
The request must contain the session cookies as well correct?
And also, what happens after this api is called? Does it get called again - and is that what you meant by retrying indefinitely?
n
I don't see the cookie sent along in the headers here (that could just be the tool we use to debug FE requests not specifying the inclusion of the header) Yeah, here's a screenshot for example:
r
So cookies must be getting sent cause otherwise the api would return a 401.
Since you are using custom ui for emailverification, what’s the condition on which you call this api?
Also, can you send the value of sAccessToken from the cookie storage? (You can dm this to me)
And also the value of sFrontToken from the cookie storage
n
Could be wrong here - hold me honest, heres our overrides - I don't think we call this API (GET)- only the POST:
Copy code
disableDefaultUI: false,
        override: {
          components: {
            EmailVerificationSendVerifyEmail_Override: (props) => {
              return <EmailVerify {...props} />
            },
            EmailVerificationVerifyEmailLinkClicked_Override: ({ DefaultComponent, ...props }) => {
              return <EmailVerifyClicked {...props} />
            },
          },
        },
We don't have the value of the access token, but sending you the front token that comes back from that API
r
Our frontend SDK calls this api when the session claim indicates that the last time the status of email verification was checked more than 5 mins ago. The fact that it’s being called again and again, means that for some reason, the front-token stored on the frontend is not being updated when this API responds.
Can you send the value of front-token across API calls? Also, the front-token is present in the response headers, but can you also fetch its value from cookie storage?
Another reason this could be happening is that
<EmailVerify />
component might be constantly remounting.
If that component remounts, it implies that our email verification component (which embeds your
<EmailVerify />
component), is also remounting and that component calls the email verify GET API. So any reasons that might be causing remounts?
z
FYI -- we just replicated this error by setting our local system clock to the future
looking now to see if that's our code or supertokens SDK code
r
In the link above, if
if (tokenInfo.ate < Date.now()) {
is true, it would mean that you would see calls to the refresh API as well.
Regardless, if the frontend's clock is in the future compared to the backend's clock, that would cause issues like this where our frontend SDK would try to call the email verification get API indefinitely (assuming that the frontend is at least 5 mins ahead of the backend)
n
Yeah, we're finding that through trial and error
z
Yep, just tested 2, 5, 6, and 60 minutes in the future. More than 5 is when it breaks.
r
yea. Makes sense now
z
This is an edge case a real user hit, so I think it's an actual bug
r
This can be solved by overriding the global claim validators in session.init on the frontend to change the
maxAgeInSeconds
to a larger number than 5 mins. I'll share some code shortly.
z
What are the implications of a larger maxAgeInSeconds? Are there industry best practices here for doing any kind of calculation on the user's machine to figure out how accurate it is and calibrating? Or anyway to make it so we're immune to user clock skew?
r
> What are the implications of a larger maxAgeInSeconds? That if a user's email is marked as verified and then you change it to unverified in offline mode, then the frontend's existing sessions won't know about it until
maxAgeInSeconds
time has passed. > Are there industry best practices here for doing any kind of calculation on the user's machine to figure out how accurate it is and calibrating? Or anyway to make it so we're immune to user clock skew? Will get back on this.
There are ways to measure this skew and take it into account though. We will add this to our roadmap.
but for now, you could just increase the
maxAgeInSeconds
to make it 10 mins instead of 5 mins. Making this an even more rare edge case. That is until we can implement the skew check logic.
Try this on the frontend's session.init in the recipeList in supertokens.init:
Copy code
ts
import EmailVerification from "supertokens-auth-react/recipe/emailverification";
import Session from "supertokens-auth-react/recipe/session";

Session.init({
    override: {
        functions: (oI) => {
            return {
                ...oI,
                getGlobalClaimValidators: function (input) {

                    // we remove the default claim validator which has maxAgeInSeconds as 5 mins
                    input.claimValidatorsAddedByOtherRecipes = input.claimValidatorsAddedByOtherRecipes.filter(c => c.id !== EmailVerification.EmailVerificationClaim.id);

                    // then we re add it with 10 as the max age in secs
                    input.claimValidatorsAddedByOtherRecipes = [...input.claimValidatorsAddedByOtherRecipes, (EmailVerification.EmailVerificationClaim.validators as any).isVerified(10, 600)]

                    return input.claimValidatorsAddedByOtherRecipes;
                }
            }
        }
    }
})
In
.isVerified(10, 600)
, the
10
represents the minimum number of seconds to wait for before querying the is email verification API if the email is NOT verified, whereas
600
is the min number of seconds to wait for if the email is verified. The default values in our SDKs are
(10, 300)
.
z
Thanks! We'll give this a shot
n
This worked - thank you!
r
Great!
3 Views