Hi, we are trying to implement manual account linking, the account linking itself works but then whe...
i
Hi, we are trying to implement manual account linking, the account linking itself works but then when we return the response there is an exception says
This should never happen: session and user mismatch
the scenario is we have a primary passwordless user and now we want to connect a social media login account (FB in this case). any directions? I assume it is somehow related to the fact we do the linking in
thirdPartySignInUpPOST
and return the response from
originalImplementation.thirdPartySignInUpPOST
code looks something like that
r
can i have the full error stack please?
i
sure: err:{ type:Error message:This should never happen: session and user mismatch stack:Error: This should never happen: session and user mismatch at Object.getBackwardsCompatibleUserInfo (/app/node_modules/supertokens-node/lib/build/utils.js:208:19) at Object.signInUpAPI [as default] (/app/node_modules/supertokens-node/lib/build/recipe/thirdparty/api/signinup.js:79:62) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Recipe.handleAPIRequest (/app/node_modules/supertokens-node/lib/build/recipe/thirdparty/recipe.js:73:24) at async Recipe.handleAPIRequest (/app/node_modules/supertokens-node/lib/build/recipe/thirdpartypasswordless/recipe.js:64:24) at async SuperTokens.middleware (/app/node_modules/supertokens-node/lib/build/supertokens.js:181:38) at async AuthMiddleware.supertokensMiddleware (/app/node_modules/supertokens-node/lib/build/framework/express/framework.js:136:28) at async /app/node_modules/@nestjs/core/router/router-proxy.js:9:17 }
r
and which version of the node SDK?
i
"supertokens-node": "^16.3.4"
can upgrade to 16.5 if there is a fix there
r
right, so the issue is that the
session
object you get with getSession points to the currently logged in user's session. When you call
thirdPartySignInUpPOST
, it creates a new session (overwriting the existing one), and also creates a new user that has a new user ID. So when you call
linkAccounts
with the (older) session's user ID and then response from
thirdPartySignInUpPOST
, you see the mismatch error
i
ok, so how to solve it in the case we want to let the user to connect their social media ?
r
it's a little bit long cause you have to replicate the logic for
thirdPartySignInUpPOST
in the API, but it is one way to get it to work.
i
so basically the only way to solve it is to create our own API in the BE that will do what thirdPartySignInUpPOST is doing?
r
basically, in this API, if a session exists, just do what the API i link to does.
you don't need to create your own API. Just in the override, don't call the
originalImplementation.thirdPartySignInUpPOST
, and instead do what i linked
i
ok will go over it
thanks
@khaledfromvee_63013
r
let me quickly see if there is a simpler way as well.
i
I guess if there is a way to override the session in the response to be the original session it will work, no?
r
yea, basically. That can be done by passing in an appropriate userContext when calling
originalImplementation.thirdPartySignInUpPOST
to signify that a session already exists, and then in the createNewSession override, just return the existing session if that userContext has it
i'll try it out
i
thanks, looking forward
r
so something like this should work
i
btw, I see in our code that we do attach to the userContext the session we get from getSession we do
input.userContext.session = session;
where session is the response of:
Copy code
const session = await Session.getSession(
                  input.options.req,
                  input.options.res,
                );
and we send the input to:
Copy code
const response =
                  await originalImplementation.thirdPartySignInUpPOST(input);
r
Im using ThirdParty, but similar should work for thirdpartyemailpassword
i
will it work with thirdPartySignInUpPOST? cause we do this in the original code I share a bit different but this is what we do
r
yea
i
so we do that in the original code but it doesn't work
we have there already:
Copy code
input.userContext.session = session;
r
im not sure why your code doesn't work. Maybe try and remove the customisations related to this and add them back one by one to see where things go wrong?
i
ohh I see we also have a function override for:
Copy code
thirdPartySignInUp: async (input) => {
        const response = await originalImplementation.thirdPartySignInUp(input);
        if (response.status === 'OK') {
          const userInfo =
            (this.configService.get<string>('NODE_ENV') === 'development' &&
              JSON.stringify(response.user)) ||
            response.user.id;
          if (response.createdNewRecipeUser) {
            // TODO: some post sign up logic
            this.logger.log(
              `successful thirdparty function sign-up ${userInfo}`,
            );
            await this.newUserCallback(response.user);
          } else {
            // TODO: some post sign in logic
            this.logger.log(`successful thirdparty sign-in ${userInfo}`);
          }
        } else {
          this.logger.error(
            `failed thirdparty sign-in/up Status:${response.status}`,
          );
        }
        return response;
      },
r
yea, so the API first calls this function, and then the createNewSession function
i
I don't think we even need this, this function is not doing anything relevant although it doesn't modify the input or response
I will just remove it and see if it help
I will also add the log of the response just in case for debugging
like magic
thanks for the help
it works for use now but it seems like a data we add to the response object is not being return to the client, any reason you can think of why?
r
what data do you want to add?
i
we add the third party response, mainly we need the oauth token
r
you need the oauth tokens on the frontend?
i
we do something like that:
Copy code
(response.user.thirdParty as any) = {
                        ...response.user.thirdParty,
                        accessToken,
                      }
and it is even being logged in the last log before we return the response
yea we do some additional work with it
r
right, that's cause this modification is not a part of our API spec
i
it used to work in the previous SDK
will take a look
r
yea, in this version of the SDK it's changed cause well.. it's an internal implementation detail
i
so in our case we need to override the
thirdPartySignInUp
api, right?
r
yea
i
so if I will do something like that:
Copy code
thirdPartySignInUp: async (input) => {
        const response = await originalImplementation.thirdPartySignInUp(input);

        this.logger.log({
          msg: 'response from internal implementation',
          response,
        });


        return response;
      },
will it call first the internal implementation and in the response object will I get everything we have added to the response in the internal implementation?
r
you should.
i
in the example you've shared it says to use input.options.res
but it doesn't exists according to typescript
r
cause thats in the API override
i
nvm - got lost with all overrides 🙂
found the right place
r
sg
3 Views