How do I call a Google API or retrieve the Google credentials?
-
@jacob-0 have you taken a look at Google's calender scopes? https://developers.google.com/identity/protocols/oauth2/scopes#calendar
You will need to add the appropriate scope in the scopes section of the Identity Provider configuration.
-
@mark-robustelli Thanks for the reply! I already spent 6 months getting that approval so we're good to go on scope, I just need to figure out the flow of getting the token.
In my current flow without FusionAuth as Sign In With Google, I store the credential on our DB and do the token refreshing ourselves. It works great.
Without the refresh token, I imagine we are going to request the token each time and FusionAuth does the refreshing of the token on our behalf?
My remaining question: how do I get the token, and how do I ensure it will not be a blank string as above.
-
@mark-robustelli BTW I did add the appropriate scopes there:
https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid
-
@jacob-0 Ok, can you tell me a little more about how you '...ask the user to connect their calendar manually'?
It sounds like you are getting the token directly from Google and then are looking to store that in connection with the FusionAuth user? Do I have that right?
-
@mark-robustelli Here's how I am doing it with the Sign in with Google flow:
Sign in with Google button on the home page has a generated url . That function looks like this for me:
function generateGoogleOAuth2LoginUrl() { const { google } = require("googleapis"); const redirectUrl = `${process.env.FRONT_ROOT}/sign-up/login-redirect`; const oauth2Client = new google.auth.OAuth2( process.env.GOOGLE_OAUTH_CLIENT_ID, process.env.GOOGLE_OAUTH_SECRET, redirectUrl ); let scopes = [ "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid", ]; return oauth2Client.generateAuthUrl({ access_type: "offline", scope: scopes, }); }
From there when the user logs in we are placed at
/sign-up/login-redirect
I use the typescript fusionauth client to log in with google
async function loginWithGoogle(code) { return client.identityProviderLogin({ data: { code, redirect_uri: `${process.env.FRONT_ROOT}/sign-up/login-redirect`, }, applicationId: process.env.FUSION_AUTH_APP_ID, identityProviderId: process.env.GOOGLE_IDENTITY_PROVIDER_ID, }); }
This works and from there I create my own internal user linked to FusionAuth
From there I call to get the token from the link api
async function getLinkedAccounts(userId) { const { response } = await client.retrieveUserLinksByUserId( process.env.GOOGLE_IDENTITY_PROVIDER_ID, userId ); return response; }
This works and gives me the user I am looking for however the
token
field is blank. Everything else is populated. I would call Google myself but only one of us can have the token.One assumption I am making is that FusionAuth is handling the token refresh on my behalf.
The other way is with Username and Password authentication and I do all the Google calling myself, and I keep the credentials stored on my database.
-
@jacob-0 do you have Google set up as and IdP in FusionAuth? https://fusionauth.io/docs/apis/identity-providers/google. Would this flow work for you if the right scopes are provided?
-
@mark-robustelli I do have it set up as an idp.
I am using openId because I could not get Google working from the API. I am not using the hosted login. I have built my own.
I use the identity provider API route to complete the sign in.
I just need the token. And I need to know that fusion is refreshing the tokens on my behalf. -
@mark-robustelli Yes I have it set up. This is the reply I get from fusionauth
{ "identityProviderLinks": [ { "displayName": "jsch...@gmail.com", "identityProviderId": "c43c909e-ada2-4731-b840-9e30e928c2a2", "identityProviderName": "Google OpenID", "identityProviderType": "OpenIDConnect", "identityProviderUserId": "110...3166", "insertInstant": 1701322547795, "lastLoginInstant": 1701636612288, "tenantId": "17470e59-34e8-4833-9c80-080d3abe09b3", "token": "", "userId": "ea855097-9b97-48fc-99ee-b9975a7e7a8b" } ] }
As you can see in this response from the server, the token is blank.
-
@jacob-0 , just wanted to let you know I haven't forgotten about this. I was able to get the scopes to work today through the regular login. I should have some time over the next few days to test the api login.
-
@mark-robustelli I made some headway in finding out when the token is blank!
It seems that the first time that I make a sign in with Google, the token is returned every time.
Any subsequent calls to get identity provider links may or may not return the token. The only way to guarentee it comes back is to completely "forget" the oauth2 link in accounts.google.com, specifically here: https://myaccount.google.com/connections.
My solution is to save the token the first time it comes through in the database. There's one problem with this solution is that I don't have a refresh token for the user, so if this token expires I won't be able to refresh it, but I am only assuming that Fusion will refresh the token and return a new one for me. I have no idea if this is true or not.
Since I can't see the source code of FusionAuth and the docs aren't clear about what kind of token this is, I can't say if this is going to work for sure.
If you can give me more clarity into how this works
-
@jacob-0 Thank you for your patience. With my testing and the last bit of info you posted, I think you have uncovered a bug. I was able to reproduce this in the UI now. Thank you so much for your effort here. I have submitted this as bug in the FusionAuth Issues project here to follow if you are interested.
Until that gets resolved, I think you will need to keep looking for the refresh token update it in an external source if it appears and link it on the user ID until the behavior is changed.
While ideally we would like to keep this info all in FusionAuth, you may be able to set up a webhook that listens for a login and then if there is a value for the refresh token keep that in the user.data, but I have not tested that out.
-
@mark-robustelli Thanks for your response!
I think our paths are getting crossed and I am still confused.Can you answer these questions:
token
that comes back from theretrieveUserLinksByUserId
in the TypeScript SDK or Retrieve A Link(s) in the Link API. Is it supposed to be the access token?- If that is the access token, how does the token get refreshed? Does that happen via FusionAuth?
- I read the OpenID documentation from Google and their API returns
access_token
,refresh_token
, andid_token
keys in JSON, but nothing liketoken
, so somewhere this is getting translated, but how does theid_token
get translated or where is the functionality of the refresh token?
-
@mark-robustelli I see now from here: that it is the refresh token, I see now that I should store the refresh token the first time and initially refresh that token to get an access token. Thank you @dan!
IMHO this one tiny detail is not clear enough, even though it in there. For example, in the Link API it could mention again that the token is a refresh token. Instead it says this:
This is treated as an opaque token as the type varies by identity provider, this value may not be returned by all identity providers. When provided, this token is typically a long lived access or refresh token, but consult individual identity provider documentation for specifics.
That's not true though is it? It's a refresh token when one is available.
While the details may be in the docs, IMHO it isn't extremely clear because OAuth is confusing for people in the first place, and FusionAuth is asking us to perform some but not all parts of the OAuth flow. The answer is spread throughout the docs. In the end if we want to create a custom login page with Google page we need to first:
- Create an OpenID for Identity Provider for Google.
- Create the Sign in Google URL on our own to call the sign in page.
- When the flow comes back to our page we need to exchange the code with the FusionAuth API.
- When that returns to our redirected url, we need to get the link API to get the refresh token in the
token
. - Exchange that refresh token for an access token, and I guess refresh the token on our own?
However, in a flow without FusionAuth we'd get the access token and refresh token together, store both, and use the access token until it is expired, then use the refresh token.
While it is possible to figure this out, it's just not as clear as the rest of the docs. Everything up to this point was well written and clear. This was hard to figure out from my POV.
-
@jacob-0 Thank you all for your help with this issue! Thanks for the fast turnaround and the hard work here! Thanks again everyone!
-
To call a Google API or retrieve Google credentials, you typically need to follow these steps:
Create a Project in the Google Cloud Console:
Go to the Google Cloud Console.
Create a new project or select an existing one.
Enable APIs:In the Cloud Console, navigate to the "APIs & Services" > "Dashboard."
Click on "+ ENABLE APIS AND SERVICES."
Search for the API you want to use (e.g., Google Drive API) and enable it.
Create Credentials:After enabling the API, go to "APIs & Services" > "Credentials."
Click on "Create Credentials."
Choose the type of credentials you need (API key, OAuth client ID, etc.).
Configure OAuth Consent Screen:If you're using OAuth, set up the OAuth consent screen with the required information.
Download or Copy Credentials:Once you've created credentials, download or copy them. For OAuth client IDs, you might download a JSON file that contains your client ID and client secret.
Use Credentials in Your Code:Integrate the credentials into your code. For example, if you're using OAuth, you'll use the client ID and secret to authenticate your application.
Make sure to replace 'credentials.json' with the path to your downloaded JSON file containing the client ID and secret.
Remember to handle your credentials securely and never expose them in publicly accessible code or repositories.
-
coHi there,
To call a Google API or retrieve the Google credentials in FusionAuth, you can follow these steps:
-
Create a Google Cloud Project:
- Go to the Google Cloud Console.
- Create a new project or select an existing one.
- Navigate to the API & Services section and enable the API you need.
-
Set Up OAuth 2.0 Credentials:
- In the API & Services section, go to Credentials.
- Click on "Create Credentials" and select "OAuth 2.0 Client IDs".
- Set up the consent screen and configure the OAuth 2.0 Client ID.
- Note down the Client ID and Client Secret.
-
Configure FusionAuth:
- In FusionAuth, go to "Identity Providers".
- Add a new "OpenID Connect" provider.
- Enter the details from your Google Cloud Project:
- Authorization endpoint:
https://accounts.google.com/o/oauth2/v2/auth
- Token endpoint:
https://oauth2.googleapis.com/token
- User info endpoint:
https://openidconnect.googleapis.com/v1/userinfo
- Client ID and Client Secret from your Google Cloud Project.
- Authorization endpoint:
-
Test the Integration:
- Ensure your FusionAuth instance is properly set up to handle the authentication flow.
- Test logging in with Google to verify everything is working.
For more detailed steps, you might find this FusionAuth documentation useful.
If you need assistance with digital marketing strategies, feel free to visit my digital marketing agency, Digitology, where we specialize in helping businesses grow online.
Best of luck with your integration!
-
-
Hello @ehabmohsen66 The information you provided is very helpful. Thanks for it.
But can you elaborate on the google developer console?
-
I do this all the time and keep meaning to create a post on codingcat.dev for it instead of hitting Jeff's site for it all the time. In the meantime I would suggest checking this out it always works for me
-
Thanks for sharing the information..
-
Thank you for sharing.