invalid_grant with override on thirdparty
# support-questions
m
invalid_grant with override on thirdparty
Any ideas on why I'm getting a 400 ``{ error: 'invalid_grant', error_description: 'Bad Request' }`` when trying to use the
signInUpPOST
?
r
Hey @Marques this usually means some config error in how you have initialised the third party provider. Can you show me the init function call on the backend?
m
I’m currently out so will have to send later, but kinda confused as it’s the same code you send me a while ago for another project and did work but now with a new project can’t seem to get it working :/
r
huh.. some setting issue most likely.
m
Copy code
ThirdParty.init({
          signInAndUpFeature: {
            providers: [
              ThirdParty.Google({
                clientId:
                  'SOMECLIENTID',
                clientSecret: 'SOMECLIENTSECRET',
                authorisationRedirect: {
                  params: {
                    redirect_uri:
                      'http://localhost/auth/callback/social/google',
                  },
                },
              }),
            ],
          },
          override: {
            apis: (oI) => {
              return {
                ...oI,
                signInUpPOST: async function (input) {
                  if (oI.signInUpPOST === undefined) {
                    throw Error('Should never come here');
                  }
                  try {
                    await oI.signInUpPOST(input);
                  } catch (err) {
                    console.log(err);
                  }
                  let resp = await oI.signInUpPOST(input);
                  if (resp.status === 'OK') {
                    if (resp.createdNewUser) {
                      let googleAccessToken =
                        resp.authCodeResponse['access_token'];
                      let user = resp.user;
                      let session = resp.session;

                      const hexPerm = pm.createPermissionAttribute(
                        Permissions.CREATE_LINK,
                        Permissions.EDIT_LINK,
                      );

                      const newUser = await this.prisma.user.create({
                        data: {
                          uid: 'TEST',
                          email: user.email.toLowerCase(),
                          username: user.email.toLowerCase(),
                          permissions: hexPerm,
                        },
                      });

                      // TODO: store info about the user in your own db

                      // TODO: You can modify the access token payload like this:
                      await session.updateAccessTokenPayload({
                        perms: newUser.permissions,
                      });
                    }
                  }
                  return resp;
                },
              };
            },
          },
        }),
r
Are you sure
http://localhost/auth/callback/social/google
is correct?
m
I think I'm sure,
r
can i see the API body of the /signinup post?
m
Copy code
await http.post('/auth/signinup', {
            redirectURI: 'http://localhost/auth/callback/social/google',
            thirdPartyId: 'google',
            code: `${code}`
        });
unless I've put the wrong url in 🤷‍♂️
r
yea please check google's dashboard as well
m
and this is for my button to get the URL to signin with google :
Copy code
await http.get('/auth/authorisationurl?thirdPartyId=google').then((res) => {
            if(res.data.status === 'OK') {
                goto(res.data.url);
                // console.log(res.data);
        }
        });
r
ah right. You need to append
redirect_uri=...
to the res.data.url before calling the goto function
m
so the uri would be the url of once they've signed in?
r
m
it already get's appended
I press my button, it takes to the google login page, once I've logged in... it takes me to =>
http://localhost/auth/callback/social/google?code=randomcode
which then I run this code :
Copy code
await http.post('/auth/signinup', {
            redirectURI: 'http://localhost/auth/callback/social/google',
            thirdPartyId: 'google',
            code: `${code}`
        });
but then it throws the 400
r
Can you show me the url that it sends the user to (the google url)
m
``https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=859215877709-i74loietpf7nkmvgcsvle63uqtrv8akp.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%2Fauth%2Fcallback%2Fsocial%2Fgoogle&flowName=GeneralOAuthFlow``
r
this seems fine
Can you remove the
Copy code
authorisationRedirect: {
                  params: {
                    redirect_uri:
                      'http://localhost/auth/callback/social/google',
                  },
                },
Part and try again?
m
so now it's missing the redirect_uri I'll add that
r
yea. try that
i mean it shouldn't make a diff. but let's see
m
nupe still same issue
r
hmm
m
I just don't get why it doesn't work now, I mean I kinda do as it's a brand new project and just ported over to this, but almost the same stuff
r
OH wait
you are doing:
Copy code
}
                  try {
                    await oI.signInUpPOST(input);
                  } catch (err) {
                    console.log(err);
                  }
                  let resp = await oI.signInUpPOST(input);
you are calling
oI.signInUpPOST
twice
m
oh I put that in the catch an error, it still does the same
r
no i mean you are calling oI.signInUpPOST(input); twice - remove one of them
m
I've just removed and still 400
r
Can you print out the result of
oI.signInUpPOST(input)
?
m
no
just throws a 400 error lul
r
Double check client id and secret?
m
I'll post here , idc if get's out rn
r
hmm
can you remove your override entirely and try again?
m
still 400
r
google doesn't send a good description for why it's sending 400.. kind of annoying
m
yeah it can be literally anything lul
so many causes
r
this error usually means a wrong redirect_uri, or wrong client id / secret
m
but not in my case I guess
data it's trying to send to /signinup
r
can you send me a valid code via text?
instead of an image
m
``4/0AX4XfWiZdtdWF9zFP44m_JbDm_OhAa1ACIP-Bdes5oUw81j4_wd5NYx_l5v3wIQxVyOPxA``
r
client id? text form
and client secret text form
m
``859215877709-i74loietpf7nkmvgcsvle63uqtrv8akp.apps.googleusercontent.com``
``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``
r
lol.. literally no other info
all i can say is to check the client IDs, client secret and redirect_uri being used
maybe add a port to localhost
cause normally it's always http://localhost:8080/...
or some other port
m
nupe same issue
r
this is very very strange
m
even changed on google
r
@nkshah2 can help here
n
Hey @Marques , mind generating another code?
m
just did
``859215877709-fsot93q47jsm721b0m3utrskftd3tadu.apps.googleusercontent.com``
``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``
`` 10 June 2022 at 11:12:44 GMT+1``
n
I meant send another one of these
m
``4/0AX4XfWhFl1oDIZu1wRntU-cmlsVsmD_zZfiAGvNzQVpVzqBtaf901bsKwvl7yzM7FwWmzw``
n
@Marques Sorry but this will be trial and error, could you generate another one?
m
sure
``4/0AX4XfWisRQbDSRW2zJ0V3ZrYyOVgKXDNNqQgH3QMlAlRx2PVPoZ2xLt82iimk2ZyTlG1yg``
n
Hey, this might be easier to debug on call
Can we schedule one in about an hour?
m
um, I'm not currently home until the evening.
maybe tomorrow? or monday
n
Alright that works, one thing I would double check in the meantime is that the redirect uri you have configured matches exactly what is being sent (for the url where you log in with google and when calling the signinup API)
Google usually responds with that if theres an issue with the redirect_uri or with the code
m
yeah they are both the same
n
Lets get on call tomorrow or Monday, let me know what time works for you
m
most prob monday at 1PM (GMT) if possible
I've just tried with github auth as well am I getting error 400
n
Same error?
m
so I presume I've setup supertokens incorrectly
I'll take a look over again on the weekend
n
So theres a couple things you could try: - Use http://localhost:8080 instead and see if Github login still fails - Enable debug logs (you can refer to the troubleshooting guide in the docs) and post the output here
Also Monday 1pm GMT sounds good
Shouldnt the callback url on Google be http://localhost:3000/auth/callback/social/google then? Since thats the domain for your website
m
no, it's because I forgot to change in my env file to be localhost:8080
it didn't change anything tho
n
Alright, can you enable logs on the frontend as well? (Also the config for SuperTokens.init on the frontend would help too)
m
so I presume I just do enableDebug on the init
oops
wrong one
Copy code
SuperTokens.init({apiDomain: 'http://localhost:3000', apiBasePath: '/auth', enableDebugLogs: true});
        if(await SuperTokens.doesSessionExist()) {
            // TODO: get information about the user
            await fetchUserData();
        }else {
            await SuperTokens.signOut();
            // TODO: set user store to be empty.
            user.set({});
        }
n
Yeah that should be enough for logs
m
no logs are outputting :/
n
What SDK and version are you using?
m
unsure tbh : ``"supertokens-website": "^12.0.0"``
n
Strange, the logs should appear in your browser
m
ah, they do now
was in the wrong tab
n
Ah
Is API domain supposed to be localhost:3000?
Right nevermind
m
yeh, the api is on port 3000 and 8080 is frontend
n
And currently whats the redirect uri configured on Github? (You can DM me the screenshot of the OAuth app if its easier)
m
oh I set it all back to google. I was testing to see if it was just google messing up
If you want, I can dm you my backend project?
n
Ok, whats the redirect for Google currently then?
On the Google dashboard I mean. Not the one you send to SuperTokens
Copy code
ThirdParty.Google({
                clientId:
                  'SOMECLIENTID',
                clientSecret: 'SOMECLIENTSECRET',
                authorisationRedirect: {
                  params: {
                    redirect_uri:
                      'http://localhost/auth/callback/social/google',
                  },
                },
              }),
And youve changed this to use localhost:8080 as well I assume?
m
rp told me to remove the authorsationRedirect
Copy code
const googleSubmit = async () => {
    const googleUrl = await http.get('/auth/authorisationurl?thirdPartyId=google');

    const data = googleUrl.data;
    // console.log(data);
    goto(`${data.url}&redirect_uri=http://localhost:8080/auth/callback/social/google`);
  };
it's within my frontend now
n
Ah alright, can you try the flow out once and send the value of
googleUrl
?
Value of
const data = googleUrl.data;
I mean
m
this I presume
n
Can you send the full url in the data object?
m
this ? : ``https://accounts.google.com/o/oauth2/v2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=859215877709-fsot93q47jsm721b0m3utrskftd3tadu.apps.googleusercontent.com``
it doesn't have redirect_uri because it get's added on the ``goto``
n
When calling goto, you use URL encode the redirect_uri
Should look like this http%3A%2F%2Flocalhost%3A8080%2Fauth%2Fcallback%2Fsocial%2Fgoogle
goto(
${data.url}&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fauth%2Fcallback%2Fsocial%2Fgoogle
);
m
shouldn't make a difference because it still redirects me to the right url
but I just changed it and still no difference
n
Same error?
m
yup
n
Alright, now when you log in with google and it redirects you back to your app, can you post the full URL of where it redirects you
m
``http://localhost:8080/auth/callback/social/google?code=4%2F0AX4XfWi0eacwk6FCxK0Q_qPnm2Gf9FQJPaKko-Luy3bIiH3n3USxhzZQ1vww5qqZlNItiQ&scope=email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&prompt=consent``
n
Alright im gonna create a sample app and try it out with the basic setup in the docs and then we can compare notes from there, is it possible for you to send me your frontend + backend app? (You dont need to include credentials, ill create my own)
PS: If you are sending them to me, please DM them
m
👍
n
@Marques So I looked at your project, inside
frontend/src/routes/auth/callback/social/google.svelte
- You are not checking whether the code is running on the server side or not. This means that it tries to read the
code
from the URL on the server first and calls the
/auth/signinup
API from the server itself. When I changed the code to:
Copy code
if (typeof window !== "undefined") {
    ...
    // Read code
    // Call sign in up API here
    ...
}
The flow worked with Google
m
That’s strange I’ve never had to do this with my previous project
n
So normally it wouldnt matter, but because the API is already called on the server side the one on the frontend always fails
m
So where would I put the code snippet? Sorry
n
So you can replace the contents of the file with
Copy code
<script lang="ts">
import { goto } from '$app/navigation';

    import { page } from '$app/stores';
    import { http } from '../../../../util/http';

    
    if (typeof window !== "undefined") {

    const code = $page.url.searchParams.get('code');

    console.log("OG CODE", code)
    if (typeof window !== "undefined") {
        console.log("WI CODE", (new URL(window.location)).searchParams.get("code"))
    }

    (async () => {
        await http.post('/auth/signinup', {
            redirectURI: 'http://localhost:8080/auth/callback/social/google',
            thirdPartyId: 'google',
            code: `${code}`
        });
    })().catch((err) => {
        // console.error(err);
    });
    }
</script>
You can clean up the logs
Ah discord moved the formatting around a bit as well
m
hmm, maybe I'm still doing it wrong then because I'm still getting an error
maybe my backend is not correctly setup 🤷‍♂️
n
Are you getting the same error?
m
yeh
400
n
Ive DMed you a google client you can try
m
The level of dedication and support that you guys provide for an open source project amazes me! Thank you again so much for the support @nkshah2 @rp
n
Happy to help 🙂
n
@nkshah2 marques told me about the issues you were investigating earlier. I got it all working now for him on svelte and thought you might be interested in a few notes: - He needed to add the
authorisationRedirect: { redirect_uri }
object to the ThirdParty recipe - For some reason, pre-encoding the URL in the body when sending the request to verify the callback, would cause an error too - He didn't have the
rid
header set so in order of flow, the changes would be: login.svelte
const googleUrl = await http.get('/auth/authorisationurl?thirdPartyId=google');
supertokens.service.ts
Copy code
ts
ThirdParty.Google({
    clientId: 'ID',
    clientSecret: 'SECRET',
    authorisationRedirect: {
        params: {
            redirect_uri: 'http://localhost:8080/auth/callback/social/google'
        }
    }
}),
login.svelte
goto(googleUrl.data.url) // redirect straight to url provided from our API
google.svelte
Copy code
ts
<script lang="ts">
    import { browser } from '$app/env';
    import { page } from '$app/stores';
    import { http } from '../../../../util/http';

    if (browser) {
        const code = $page.url.searchParams.get('code');
        http.post(`/auth/signinup`, {
            redirectURI: 'http://localhost:8080/auth/callback/social/google',
            thirdPartyId: 'google',
            code
        }, {
            headers: {
                rid: 'thirdparty'
            }
        });
    }
</script>
I'm pretty sure you picked up the above points though, and fixed those things. He didn't share with me the changes you sent to him so I'm not sure how much progress you guys made, but here's some notes on svelte/frontend as he mentioned you guys might put out a svelte template: - redaxios works fine, it's a nice wrapper for the native fetch calls in the browser, so the ST SDK has no issue intercepting those calls. I would imagine other wrappers would also work as long as they don't manipulate the native fetch APIs - in svelte you can (my approach is to) initialise supertokens in a module tag in the layout, and put it in an
if (browser)
block so it doesn't try and run it server side. This way, ST will always be ready before any fetch calls are made, and its very easy to plug global user state into your web app this way
Copy code
// __layout.svelte
// The combination of a load function, within a module script, within a layout component, means that this function will be the very first thing to run when the user navigates to any page on the website, and it will be run once only
<script context="module" lang="ts">
    import SuperTokens from 'supertokens-website';
    import { browser } from '$app/env';
    import type { LoadEvent } from '@sveltejs/kit';

  export async function load({}: LoadEvent) {
    if (browser) {
        SuperTokens.init({
            apiDomain: 'http://localhost:3000', 
            apiBasePath: '/auth', 
            enableDebugLogs: true, 
            autoAddCredentials: true
        });
  
        console.log("----------- SUPERTOKENS INITIALISED ---------------")

        if (SuperTokens.doesSessionExist()) {
            // Session cookies exist, try refreshing tokens?
        } else {
          // redirect to login?
        }
    }
    return {};
  }
</script><main><slot /></main>
hope that was at least mildly insightful :)
n
Thanks @Naf, yep that’s more or less what I came to as well except I wasn’t too familiar with svelte so the syntax was slightly different. I didn’t look into redaxios too much so I switched to axios to see if that fixed it but I’m glad that works as well
r
thanks @Naf this is very helpful. We might end up writing a guide on supertokens + svelte integration and this helps!
12 Views