Hi Dear SuperTokens Community members, I'm trying ...
# support-questions-legacy
m
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
hey @manikantasannidhi
@sattvikc can help here
m
how to reach out to him?
r
he will message here in a bit
m
ok thanks a lot for the quick response
and also for such an amazing Open Source Solution 🙂
s
hey @manikantasannidhi , are you using auth-react SDK or web-js SDK ?
m
Hi @sattvikc, i'm using auth react SDK
s
cool, have you already implemented frontend part of one tap login ?
m
yeah
s
one moment
m
ok
s
I will share some code snippet soon
m
sure, thank you
s
what's your backend language ?
m
Django (Python)
s
okay
m
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
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
Hi @sattvikc , no problem at all, thanks for the help. let's try that
s
or your own implementation ?
m
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
sure, meanwhile we can go through the backend
m
sure
s
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
Copy code
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
yeah till now understood the logic, understanding the code...
s
you will need to pass this override in your thirdparty.init
Copy code
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
just came to know that We are using the direct cdn
From account.google.com/gsi/client
s
sure
you would need to use callback version of it
you would need to do 2 things on the frontend
m
what's that?
s
in the thirdparty.init, we would need a preAPIHook which adds the oneTap boolean to the body:
Copy code
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
ok, what's the another thing?
s
the other thing is the login callback
m
on backend?
s
no no, on the frontend
one tap login needs a callback function
m
oh ok
s
Copy code
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
yeah got it
we will try this solution
s
if you wish, I have also written a google-tap react component, which can be used
m
oh really, that would be a great help
s
you could use it like this:
Copy code
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
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
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
Hi @sattvikc, I'm using thirdpartyemailpassword recipe
and in the thirdpartyemailpassword we don't have sign_in_and_up_feature right
s
hey, that's fine. you just use thirdpartyemailpassword in place of thirdparty. logic remains the same
m
ok
small doubt here
we don't have sign_in_and_up_feature in init method of thirdpartyemailpassword right
s
right
you pass the providers list directly
I suppose you have passed the providers already
m
yeah
but no need of overriding the apis?
s
you just need to do the override
m
ok
s
you need to do the override, the class and the function will be different, but the logic would be same
m
as we don't have sign_in_and_up_feature in thirdpartyemailpassword, which one to override?
sign_up_feature?
s
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
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
the method name would be different
one sec
change it to
thirdparty_sign_in_up
m
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
hey @manikantasannidhi please try and see our SDK reference / types suggested by your IDE to try and solve this 🙂
m
@rp_st 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 🙂
10 Views