hey, i'm having a bit of an annoying 'bug', the th...
# support-questions-legacy
b
hey, i'm having a bit of an annoying 'bug', the thirdparty.google login flow works, but then without changes it starts failing with "bad request" "invalid_grant". When I restart the docker containers it starts working again. Any idea?
r
that happens if the frontend is making multiple requests to the backend with the same authorisation code. Are you using a custom UI?
b
hmm yes and no. I have a nextjs Layout wrapper and disabled shadow dom
Copy code
const SuperTokensComponentNoSSR = dynamic(new Promise((res) => res(SuperTokens.getRoutingComponent)) as any, {
  ssr: false
});

const AuthPage: NextPageWithLayout = () => {
  useEffect(() => {
    if (SuperTokens.canHandleRoute() === false) {
      redirectToAuth();
    }
  }, []);
  //@ts-ignore;
  return <SuperTokensComponentNoSSR />;
};

AuthPage.getLayout = function getLayout(page) {
  return (
    <Container>
      <img src="/navawalogo.svg" alt="Natuurbegraafplaatsen van waarde" />
      <article>{page}</article>
    </Container>
  );
};
r
what does the network tab look like when google redirects you back?
b
since it works currently, this is from memory, but it does a googleauth call that times out
r
hmmm. if you are causing an unmount / mount of the
<SuperTokensComponentNoSSR />
component when google redirects you back, that will call the signinup API twice, and the second call will fail.
So maybe something to do with that?
b
i'll have a look at that, but it wouldnt explain the fact that it works until it doesnt 🙂 i have a dump of the supertokens error in the nextjs logs if it helps
i also have a check in override signInUp that checks if a user is allowed.
Copy code
//code to check user
if (user !== null) {
  return await     originalImplementation.signInUp(input);
}
r
sure
b
r
hmm
in the above error message, are you calling
await     originalImplementation.signInUp(input);
even if a user is not allowed to sign up? Can I see the whole override implementation?
b
Copy code
import ThirdPartyNode from "supertokens-node/recipe/thirdparty";
import SessionNode from "supertokens-node/recipe/session";
import { appInfo } from "./appInfo";
import { TypeInput } from "supertokens-node/types";
import { getUserByThirdPartyUserID, getUserByEmail } from "lib/db/query";

export const backendConfig = (): TypeInput => {
  return {
    framework: "express",
    supertokens: {
      // try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core.
      connectionURI: process.env.AUTH_SERVER || ""
      // apiKey: "IF YOU HAVE AN API KEY FOR THE CORE, ADD IT HERE",
    },
    appInfo,
    recipeList: [
      ThirdPartyNode.init({
        signInAndUpFeature: {
          providers: [
            // We have provided you with development keys which you can use for testsing.
            // IMPORTANT: Please replace them with your own OAuth keys for production use.
            ThirdPartyNode.Google({
              clientId: process.env.GOOGLE_ID || "",
              clientSecret: process.env.GOOGLE_SECRET || ""
            })
          ]
        },
        override: {
          functions: (originalImplementation) => {
            return {
              ...originalImplementation,
              signInUp: async (input) => {
                console.log("Check if should signup", input.email.id);
                let user = await getUserByEmail(input.email.id);

                if (user !== null) {
                  return await originalImplementation.signInUp(input);
                }
                throw new Error("Not allowed to signup");
              }
            };
          },
          apis: (originalImplementation) => {
            return {
              ...originalImplementation
              //              signInUpPOST: undefined
            };
          }
        }
      }),
      SessionNode.init({
        jwt: {
          enable: true
        },
        override: {
          functions: function (originalImplementation) {
            return {
              ...originalImplementation,
              createNewSession: async function (input) {
                let user = await getUserByThirdPartyUserID(input.userId);
                if (!user || !user.is_active) {
                  throw new Error("User not found");
                }

                input.accessTokenPayload = {
                  ...input.accessTokenPayload,
                  "https://hasura.io/jwt/claims": {
                    "x-hasura-user-id": input.userId,
                    "x-hasura-default-role": user.is_admin ? "admin" : "user",
                    "x-hasura-allowed-roles": user.is_admin ? ["admin", "user"] : ["user"]
                  }
                };

                return originalImplementation.createNewSession(input);
              }
            };
          }
        }
      })
    ]
  };
};
r
this seems about fine.
would be good to be able to replicate it.
b
definitely! but google is very sparse with their error messages
restarting the containers helping suggests it has to me some regenerated key or some timing issue?
r
have you connected the core to a db? or using in memory version of it?
b
postgres
r
i see. the core is pretty much stateless, so restarting it should not make a difference
so it's weird that that fixes the issue
b
once it fails again (hopefully it doesnt) i'll dive in deeper. weirdly I cant find any logs in the google console. thanks for your quick response and brain power!
r
hmm. ok fair! thanks
b
hey, the issue showed itself again, after a few weeks (sure how many) logins started to fail again. Could it have to do with out of date tokens / refresh tokens not working? Like I said a restart of the docker container running nextjs helps the problem. I dont know what parameters this restart would reset to make it work again
r
Restart doesn’t really reset anything, unless you clear the db
b
we found a way to trigger the failure. click google login button browser back button click google login button browser back button ... after the 5th time it fails with the invalid grant message, and it breaks for all users
r
hmmm. Interesting
b
nope, works flawlessly.
r
hmmm
b
the weird thing is we manage to have a bug that messes it up for all users (and a restart still fixes it)
Copy code
ThirdPartyNode.init({
        signInAndUpFeature: {
          providers: [
            // We have provided you with development keys which you can use for testsing.
            // IMPORTANT: Please replace them with your own OAuth keys for production use.
            ThirdPartyNode.Google({
              clientId: process.env.GOOGLE_ID || "",
              clientSecret: process.env.GOOGLE_SECRET || ""
            })
          ]
        },
        override: {
          functions: (originalImplementation) => {
            return {
              ...originalImplementation,
              signInUp: async (input) => {
                console.log("Check if should signup", input.email.id);
                let user = await getUserByEmail(input.email.id);

                if (user !== null) {
                  return await originalImplementation.signInUp(input);
                }
                throw new Error("Not allowed to signup");
              }
            };
          },
          apis: (originalImplementation) => {
            return {
              ...originalImplementation
              //              signInUpPOST: undefined
            };
          }
        }
      }),
is the throw new error incorrect? a non existing user login also seems to mess things up
r
Where do you get
getUserByEmail
function from?
b
its an async function that queries postgres directly
r
I see.
b
we have our own "users" table to store which people are allowed on the site
r
throwing an error should just cause the frontend to get a 500 error (depending on if you have a generic app wide error handler and what that does)
I don't see any obvious problem with this - are you open to getting on a call?
b
the frontend seems to hang indefinitely when trying to signup with an email adres thats not in our "users" table
r
so you mean you see the scroller UI forever?
b
yes
r
what does the API reply in this case?
500 status code?
b
hmm scratch that it works fine now with a "something went wrong" message
a call would be amazing support but I dont want to waste your time to much, not sure where to start I could fork the repo into a public one temporarily
r
yea i mean i just need a way to replicate it myself. So that we can figure whats wrong
since i can't replicate it our demo app
b
im beginning to think its most probably something on our end, either in our next code with PWA or the way I handle the hasura things
r
maybe
b
something messes up the tokens for all users
r
yeaaa.. very odd
b
can only be some form of serverside caching right?
r
i have really no idea.. lots of possibilities. Until i can debug it myself, hard to say
b
i understand. Thanks for your time again! my colleague is the one able to reproduce and he'll be back shortly. We will dig deeper. I'll let you know when we solve it (if 😅 )
r
sounds good!
b
super embarrassing, we found the reason for the failing. we forgot to release the postgres connections from the pool we we're totally red herring'd by the invalid grant error apparently thrown by a user constantly logging in with the wrong email address in the background. The timeout on the db was seemingly infinite so we didnt notice. Thank you so much for taking the time (and sorry for wasting it)
r
ahh! I see. Makes sense :)) Always happy to help
2 Views