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:
idToken
on the phoneidToken
to the serveridToken
to get refresh token on the server (this is where things fall apart)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!
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.