https://supertokens.com/ logo
google one tap
m

ManikantaSannidhi

04/24/2023, 10:37 AM
Hi Dear SuperTokens Community members, I'm trying to add Google One Tap provider in third-party authentication providers but not as a button in the /auth page, but after the user chooses an email from One Tap pop-up and after that we get response in which we will be having 'credential' field if it is decoded we get the user email using which we have to continue the remaining flow of creating a session for user and managing the user data automatically using the existing supertokens APIs/have to write a new API using Core Driver Interface(CDI) APIs. Can anyone please help me in this. Thanks In Advance 🙂
r

rp

04/24/2023, 10:44 AM
hey @ManikantaSannidhi
@sattvikc can help here
m

ManikantaSannidhi

04/24/2023, 10:45 AM
how to reach out to him?
r

rp

04/24/2023, 10:45 AM
he will message here in a bit
m

ManikantaSannidhi

04/24/2023, 10:45 AM
ok thanks a lot for the quick response
and also for such an amazing Open Source Solution 🙂
s

sattvikc

04/24/2023, 11:07 AM
hey @ManikantaSannidhi , are you using auth-react SDK or web-js SDK ?
m

ManikantaSannidhi

04/24/2023, 11:08 AM
Hi @sattvikc, i'm using auth react SDK
s

sattvikc

04/24/2023, 11:09 AM
cool, have you already implemented frontend part of one tap login ?
m

ManikantaSannidhi

04/24/2023, 11:09 AM
yeah
s

sattvikc

04/24/2023, 11:10 AM
one moment
m

ManikantaSannidhi

04/24/2023, 11:10 AM
ok
s

sattvikc

04/24/2023, 11:14 AM
I will share some code snippet soon
m

ManikantaSannidhi

04/24/2023, 11:14 AM
sure, thank you
s

sattvikc

04/24/2023, 11:15 AM
what's your backend language ?
m

ManikantaSannidhi

04/24/2023, 11:15 AM
Django (Python)
s

sattvikc

04/24/2023, 11:15 AM
okay
m

ManikantaSannidhi

04/24/2023, 11:17 AM
hope you understood the problem correctly that we need to implement the authentication flow after user has been authenticated with one tap we extract the email from "credential" which is a JWT encoded response field from here we need to handle the user data(if user exists need to create session other wise session along with new user) and also session data
s

sattvikc

04/24/2023, 11:20 AM
right, so supertokens SDK handles creation of new user already as needed
hi @ManikantaSannidhi, sorry for the delay. I now have kind of working code, which I can run you through
are you using
react-google-one-tap-login github
on the frontend ?
m

ManikantaSannidhi

04/24/2023, 1:08 PM
Hi @sattvikc , no problem at all, thanks for the help. let's try that
s

sattvikc

04/24/2023, 1:08 PM
or your own implementation ?
m

ManikantaSannidhi

04/24/2023, 1:09 PM
sorry pls give me few mins, actually some other guy is working on front-end part of One Tap, i messaged him
once i come to know will ping here
s

sattvikc

04/24/2023, 1:10 PM
sure, meanwhile we can go through the backend
m

ManikantaSannidhi

04/24/2023, 1:10 PM
sure
s

sattvikc

04/24/2023, 1:11 PM
the summary is this, on the frontend, while handling one tap login, we pass an additional body param
oneTap
set to true along with the credential returned by google on the code param
so we override the sign_in_up_post API on the thirdparty recipe to check for this flag and handle it appropriately
python
class GoogleOneTap(thirdparty.Google):
    async def get_profile_info(self, auth_code_response, user_context):
        return UserInfo(
            auth_code_response['sub'], 
            UserInfoEmail(auth_code_response['email'], auth_code_response['email_verified'].lower() == 'true')
        )

def thirdparty_api_override(original_implementation):
    osign_in_up_post = original_implementation.sign_in_up_post

    async def custom_sign_in_up_post(provider, code, redirect_uri, client_id, auth_code_response, api_options, user_context):
        request = user_context["_default"]["request"]
        request_body = json.loads(request.request.body)
        if not request_body.get('oneTap'):
            return await osign_in_up_post(provider, code, redirect_uri, client_id, auth_code_response, api_options, user_context)

        resp = requests.get('https://oauth2.googleapis.com/tokeninfo', {'id_token': request_body.get('code')}).json()
        return await osign_in_up_post(GoogleOneTap("", ""), None, None, None, resp, api_options, user_context)


    original_implementation.sign_in_up_post = custom_sign_in_up_post
    return original_implementation
Essentially in the override, if oneTap is not part of the request body, we just do the original sign in up, otherwise, we get the tokeninfo from the google using an API provided by them and pass that as auth_code_response to a custom GoogleOneTap provider
is it clear so far ?
m

ManikantaSannidhi

04/24/2023, 1:15 PM
yeah till now understood the logic, understanding the code...
s

sattvikc

04/24/2023, 1:17 PM
you will need to pass this override in your thirdparty.init
python
    thirdparty.init(
        sign_in_and_up_feature=thirdparty.SignInAndUpFeature(providers=[
            # We have provided you with development keys which you can use for testing.
            # IMPORTANT: Please replace them with your own OAuth keys for production use.
            Google(
                client_id='1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com',
                client_secret='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'
            ),
        ]),
        override=InputOverrideConfig(
            apis=thirdparty_api_override
        )
    ),
@ManikantaSannidhi you can probably tag your frontend person here so that it will be easy to integrate
m

ManikantaSannidhi

04/24/2023, 1:30 PM
just came to know that We are using the direct cdn
From account.google.com/gsi/client
s

sattvikc

04/24/2023, 1:30 PM
sure
you would need to use callback version of it
you would need to do 2 things on the frontend
m

ManikantaSannidhi

04/24/2023, 1:32 PM
what's that?
s

sattvikc

04/24/2023, 1:32 PM
in the thirdparty.init, we would need a preAPIHook which adds the oneTap boolean to the body:
ts
        ThirdParty.init({
            signInAndUpFeature: {
                providers: [Github.init(), Google.init(), Apple.init()],
            },
            preAPIHook: async (context) => {
                if (context.userContext.oneTap) {
                    const body = JSON.parse(context.requestInit.body as string)
                    body.oneTap = true;
                    context.requestInit.body = JSON.stringify(body);
                }

                return context;
            }
        }),
m

ManikantaSannidhi

04/24/2023, 1:33 PM
ok, what's the another thing?
s

sattvikc

04/24/2023, 1:34 PM
the other thing is the login callback
m

ManikantaSannidhi

04/24/2023, 1:34 PM
on backend?
s

sattvikc

04/24/2023, 1:34 PM
no no, on the frontend
one tap login needs a callback function
m

ManikantaSannidhi

04/24/2023, 1:35 PM
oh ok
s

sattvikc

04/24/2023, 1:35 PM
ts
    const doLogin = async (data: any) => {
        function insertUrlParam(key: string, value: string) {
            let searchParams = new URLSearchParams(window.location.search);
            searchParams.set(key, value);
            let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams.toString();
            window.history.pushState({path: newurl}, '', newurl);
        }

        if (data.credential) {
            await ThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ providerId: "google", authorisationURL: window.location.toString() })
            const stateInfo = await ThirdParty.getStateAndOtherInfoFromStorage();
            if (data.credential && stateInfo !== undefined) {
                insertUrlParam("code", data.credential);
                insertUrlParam("state", stateInfo.stateForAuthProvider);

                ThirdParty.signInAndUp({userContext: {oneTap: true}});
            }
        }
    }
doLogin is the callback function
m

ManikantaSannidhi

04/24/2023, 1:36 PM
yeah got it
we will try this solution
s

sattvikc

04/24/2023, 1:37 PM
if you wish, I have also written a google-tap react component, which can be used
m

ManikantaSannidhi

04/24/2023, 1:38 PM
oh really, that would be a great help
s

sattvikc

04/24/2023, 1:40 PM
you could use it like this:
ts
import ThirdParty from 'supertokens-auth-react/recipe/thirdparty'
import GoogleOneTapLogin from './google-one-tap';

export default function SomeRoute() {
    const doLogin = async (data: any) => {
        function insertUrlParam(key: string, value: string) {
            let searchParams = new URLSearchParams(window.location.search);
            searchParams.set(key, value);
            let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams.toString();
            window.history.pushState({path: newurl}, '', newurl);
        }

        if (data.credential) {
            await ThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ providerId: "google", authorisationURL: window.location.toString() })
            const stateInfo = await ThirdParty.getStateAndOtherInfoFromStorage();
            if (data.credential && stateInfo !== undefined) {
                insertUrlParam("code", data.credential);
                insertUrlParam("state", stateInfo.stateForAuthProvider);

                ThirdParty.signInAndUp({userContext: {oneTap: true}});
            }
        }
    }

    return (
        <div className="fill" id="home-container">
            <GoogleOneTapLogin onSuccess={doLogin} googleAccountConfigs={{ client_id: "your-google-client-id-here" }} />
            <p>Use one tap login to continue</p>
        </div>
    )
}
feel free to ping here if stuck in any of the steps
m

ManikantaSannidhi

04/24/2023, 1:42 PM
Sure, Thanks a lot @sattvikc for the kindful help, you've rescued me, I've been trying to solve this problem for 3 days, though I couldn't get a perfect working solution
s

sattvikc

04/24/2023, 1:45 PM
we are working on an improved interface to account for use cases like these, but that is still few weeks away. This work around should just work fine.
m

ManikantaSannidhi

04/25/2023, 10:45 AM
Hi @sattvikc, I'm using thirdpartyemailpassword recipe
and in the thirdpartyemailpassword we don't have sign_in_and_up_feature right
s

sattvikc

04/25/2023, 10:46 AM
hey, that's fine. you just use thirdpartyemailpassword in place of thirdparty. logic remains the same
m

ManikantaSannidhi

04/25/2023, 10:46 AM
ok
small doubt here
we don't have sign_in_and_up_feature in init method of thirdpartyemailpassword right
s

sattvikc

04/25/2023, 10:47 AM
right
you pass the providers list directly
I suppose you have passed the providers already
m

ManikantaSannidhi

04/25/2023, 10:47 AM
yeah
but no need of overriding the apis?
s

sattvikc

04/25/2023, 10:48 AM
you just need to do the override
m

ManikantaSannidhi

04/25/2023, 10:48 AM
ok
s

sattvikc

04/25/2023, 10:48 AM
you need to do the override, the class and the function will be different, but the logic would be same
m

ManikantaSannidhi

04/25/2023, 10:49 AM
as we don't have sign_in_and_up_feature in thirdpartyemailpassword, which one to override?
sign_up_feature?
s

sattvikc

04/25/2023, 10:50 AM
this part. it's not related to the sign_up_feature

https://cdn.discordapp.com/attachments/1100007631952826418/1100373363081367582/image.png

it should be part of the thirdpartyemailpassword.init
m

ManikantaSannidhi

04/25/2023, 10:51 AM
yeah, ok
File "/home/manikantas/Desktop/Django_Projects/supertokens_trail_project/supertokens_trail_project/__init__.py", line 16, in thirdparty_api_override osign_in_up_post = original_implementation.sign_in_up_post AttributeError: 'APIImplementation' object has no attribute 'sign_in_up_post'
ended up with this error
s

sattvikc

04/25/2023, 11:48 AM
the method name would be different
one sec
change it to
thirdparty_sign_in_up
m

ManikantaSannidhi

04/26/2023, 7:26 AM
HI @sattvikc , sorry I'm still getting the same error
File "/home/manikantas/Desktop/Django_Projects/supertokens_trail_project/supertokens_trail_project/__init__.py", line 16, in thirdparty_api_override osign_in_up_post = original_implementation.thirdparty_sign_in_up AttributeError: 'APIImplementation' object has no attribute 'thirdparty_sign_in_up'
r

rp

04/26/2023, 7:27 AM
hey @ManikantaSannidhi please try and see our SDK reference / types suggested by your IDE to try and solve this 🙂
m

ManikantaSannidhi

04/26/2023, 7:56 AM
@rp thanks a lot, finally I found the type from the SDK reference, sorry actually I've not explored much of the documentation SDK reference part, now i am able to understand things better
@sattvikc thanks for the help 🙂