0
votes

I have a mobile app and I want to add events on the user's google calendar from my server. I've added the consent flow on iOs and I get an idToken from the response. I can also get an accessToken using getTokens on the client. However I am not able to use these in order to get an appropriate refresh token on the server so I can call the Calendar API at a later stage. For a web app it requires a client secret. The ios client does not have a secret and when I use my web client id and secret I get insufficientPermissions: Insufficient Permission: Request had insufficient authentication scopes. .

To clarify, my steps are:

  1. get consent and idToken on the phone
  2. send idToken to the server
  3. use idToken to get refresh token on the server (this is where things fall apart)
  4. use refresh token to create events on the user's calendar

Here's my ios React Native code:

signInWithGoogle() {
    GoogleSignin.configure({scopes: ['https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.events']});

    GoogleSignin.signIn()
    .then(result => {
      // idToken
      console.log(result);
      GoogleSignin.getTokens()
      .then(tokens => {
        //this gets me an accessToken
        console.log(tokens);
      })
    }).catch(error => {
      console.log('google auth error: ', error);
    });
  }

And my server side code:

secrets = Google::APIClient::ClientSecrets.new({
      "web" => {
        "refresh_token" => ENV['GOOGLE_REFRESH_TOKEN'],
        "client_id" => ENV["GOOGLE_CLIENT_ID"],
        "client_secret" => ENV["GOOGLE_CLIENT_SECRET"]
      }
    })
auth_code = idToken_from_client
auth_client = secrets.to_authorization
auth_client.update!(scope: 'https://www.googleapis.com/auth/calendar.events')
auth_client.code = auth_code
auth_client.fetch_access_token!

I know the server code doesn't make sense because I already have an access token, however I need a refresh token. I will need to create events for the user as long as they use the app and access tokens expire. And this is what they recommended for getting a refresh token in the server side auth docs: https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code

Thanks for your help!

1
Please edit your question and include your code. YOu dont need a refresh token to access the api you need an access toekn. It sounds like you have not asked for the proper scope when authenticating your user. You can use Ruby-on-rails in IOs?DaImTo
@DaImTo I've added code and explained why I need a refresh token, not an access token, so it does not expire and I don't have to repeatedly ask the user for consentTamar
I would still like to know what Ruby-on-rails has to do with your question and why it is tagged as such if you are doing IOs. To my knowledge mobile authorization does not use a refresh token. Also you cant mix React authorization with what ever you are doing on server side the client ides are different the authorization types are diffrentDaImTo
@DaImTo I have a client side where I do the authorization but the information for creating events is on the server side. I am looking for a way to use the token generated from the client side with the google-api-ruby-client gem to obtain a refresh token. Is it not possible?Tamar

1 Answers

0
votes

What I ended up doing is using the auth flow for installed apps opening a system browser window, using the web client id and secret. I use the redirect uri pointing to my server endpoint where I use the google-api-client to obtain a refresh and access token with the provided code.

ReactNative code:

const scope = 'scope=the_google_scope';
const redirect = 'redirect_uri=redirect_for_google_auth'; // Your serverside endpoint
const url = `https://accounts.google.com/o/oauth2/v2/auth?${scope}&prompt=consent&access_type=offline&response_type=code&${redirect}&client_id=${googleClientID}`

Linking.openURL(url);

Rails code:

require "google/api_client/client_secrets.rb"
...
secrets = Google::APIClient::ClientSecrets.new({
      web: {
        client_id: googleClientID, # Same one used on the client
        client_secret: googleClientSecret,
        grant_type: "authorization_code",
        redirect_uri: "redirect_for_google_auth"
      }
    })
auth_client = secrets.to_authorization
auth_client.code = code_retrieved_from_google
auth_result = auth_client.fetch_access_token!

Hopes this helps other people with this scenario.