Ad

Get Google Refresh Token From Existing User Auth Code

I'm trying to get the Google Refresh token, the thing is that i haven't seen my current scenario anywhere, what i'm trying to accomplish is get the refresh token from a user auth token already generated by a google sign in from a native android app, basically i request every google permission i need on the app, and the the auth code from the sign in, with that auth code i send it to my Firebase functions backend, there i try to get the refresh token but i always get invalid_grant from google, so i don't know where could i be messing up

I saw that requesting oauth offline may solve the problem, but i'm sign in in the android app, so i cannot make a sign in request offline from the backend, i need the sign in and authentication to be only on the android app and i need this to make Google assistant requests over the backend and for this, the only thing missing is the refresh token

I have my google oauth2 key from google cloud console and the client initialized

var OAuth2 = google.auth.OAuth2;

var _client_id = require('./config/secrets/omni.json').installed.client_id; 
var _client_secret = require('./config/secrets/omni.json').installed.client_secret;
var redirect = require('./config/secrets/omni.json').installed.redirect_uris[1];

return new OAuth2(
        _client_id,
        _client_secret,
        redirect
        );

And finally try to get the token:

function getRefreshToken(authCode, idFBUser) {
    return new Promise((resolve, reject) => {
        getOAuthClient().getToken(authCode, function(err, token) {
            if (!err) {
                console.log(`Get Token success, token: ${token}`);
                getOAuthClient().setCredentials(token);
                saveRefreshFirebase(idFBUser, token)
                resolve(token);
            } else {
                console.log("Get Token error", err);
                reject(err);
            }
        });
    });
}

the error i'm getting exactly is this one: { error: 'invalid_grant', error_description: 'Bad Request' }

The method i use in the android app to request the auth code is this one:

Creating the GoogleSignIn instance

val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.default_web_client_id))
            .requestEmail()
            .requestId()
            .requestIdToken(getClientId())
            .requestServerAuthCode(getClientId())
            .requestScopes(ASSISTANT_SCOPE)
            .build()

googleSignInClient = GoogleSignIn.getClient(this, gso)

Calling the Sign in Intent:

val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RESULT_GOOGLE_SIGNIN)

Handle the Sign in Result:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                RESULT_GOOGLE_SIGNIN -> {
                    val task = GoogleSignIn.getSignedInAccountFromIntent(data)
                    try {
                        task.result?.let {  account ->
                            val id = account.id
                            val idToken = account.idToken
                            val authCode = account.serverAuthCode
                            Log.d("GoogleSignIn", "ID: $id")
                            Log.d("GoogleSignIn", "ID Token: $idToken")
                            Log.d("GoogleSignIn", "Auth code: $authCode")
                            btnLogin.text = "Sign Out"
                            loggedIn = true
                        } ?: Log.e("GoogleSignIn", "Exception: ${task.exception}")
                    } catch (e: Exception) {
                        Log.e("GoogleSignIn", "Catch Exception: $e")
                    }
                }
            }
        }
    }

and the authCode is the one i used to try to get the Refresh Token in the backend

Ad

Answer

You need to call

            .requestServerAuthCode(getClientId(),true)

instead of

            .requestServerAuthCode(getClientId())

If you want to get a refresh token. The javascript code you posted works with refresh tokens.

This is the easiest way to authenticate your app because all other kinds of token will expire. Refresh tokens dont expire. The Google Sign in library gives you an access code which you are already using to obtain a refresh token. You need to save this refresh token and send it to Google in order to obtain access tokens. The access token can then finally be used to make API requests.

By the way, that is actually what 'offline access' refers to. Took me a while to figure this out as well.

Ad
source: stackoverflow.com
Ad