Search code examples
androidoauth-2.0google-oauthaccess-token

Cross Client google oauth2.0 for android app with a backend server for offline access


I am developing an android app that fetches data from user's youtube account and needs to do so in offline mode also. For this i am supposed to implement google's oauth2.0 crossclient authentication (https://developers.google.com/+/mobile/android/sign-in#server-side_access_for_your_app) mechanism. I am able to fetch the IdToken but for the one time exchange token (https://developers.google.com/accounts/docs/CrossClientAuth) it returns null. Please help me out in this problem. Thanks in advance... Here is my code

package com.example.sampleapp;

import java.util.Arrays;
import java.util.List;

import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.AccountPicker;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.accounts.AccountManager;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

final private String CLIENT_ID = "12345----.apps.googleusercontent.com";
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
private String mEmail;
//private static final String SCOPE =
  //      "oauth2:https://www.googleapis.com/auth/userinfo.profile";

final private List<String> SCOPES = Arrays.asList(new String[]{
          "https://www.googleapis.com/auth/plus.login",
          "https://www.googleapis.com/auth/youtube"});

 private EditText mExchangeCodeEditText;
  private EditText mIdTokenEditText;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

     mExchangeCodeEditText = (EditText) findViewById(R.id.editTextExchangeCode);
        mIdTokenEditText = (EditText) findViewById(R.id.editTextIdToken);

Button b1=(Button) findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener(){

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

//      static final int REQUEST_CODE_PICK_ACCOUNT = 1000;

        String[] accountTypes = new String[]{"com.google"};
        Intent intent = AccountPicker.newChooseAccountIntent(null, null,
                accountTypes, false, null, null, null, null);
        startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);          
    }
});



}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override   public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
        // Receiving a result from the AccountPicker
        if (resultCode == RESULT_OK) {
            mEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            // With the account name acquired, go get the auth token
      //      getUsername();
            Log.v("MY_UNAME",mEmail);
            new RetrieveJwtAsyncTask().execute();
            new RetrieveExchangeCodeAsyncTask().execute();
        } else if (resultCode == RESULT_CANCELED) {
            // The account picker dialog closed without selecting an account.
            // Notify users that they must pick an account to proceed.
            Toast.makeText(this, R.string.pick_account, Toast.LENGTH_SHORT).show();
        }
    }
    // Later, more code will go here to handle the result from some exceptions...
}


 public class RetrieveJwtAsyncTask
 extends AsyncTask<Void, Boolean, String> {

   @Override
  protected String doInBackground(Void... params) {
  String scope = "audience:server:client_id:" + CLIENT_ID;
  try {
   return GoogleAuthUtil.getToken(
       MainActivity.this, mEmail, scope);
  } catch (Exception e) {
   e.printStackTrace(); // TODO: handle the exception
  }
  return null;
 }

  @Override
  protected void onPostExecute(String idToken) {
  // exchange encrypted idToken with server-side to identify the user
   mIdTokenEditText.setText(idToken);
  Log.v("Second One","  "+ idToken);

  }
 }

 public class RetrieveExchangeCodeAsyncTask
 extends AsyncTask<Void, Boolean, String> {



 @Override
 protected String doInBackground(Void... params) {
 String scope = String.format("oauth2:server:client_id:%s:api_scope:%s",
     CLIENT_ID, TextUtils.join(" ", SCOPES));
 try {
   return GoogleAuthUtil.getToken(
       MainActivity.this, mEmail, scope);

 } catch (Exception e) {
   e.printStackTrace(); // TODO: handle the exception
  }
 return null;
 }

 @Override
 protected void onPostExecute(String code) {
 // exchange code with server-side to retrieve an additional
 // access token on the server-side.
 Log.v("first One","1"+ code);
 mExchangeCodeEditText.setText(code);
  }
 }

} 

class RetrieveJwtAsyncTask runs fine but class RetrieveExchangeCodeAsyncTask returns null instead of one-time access code reffered to as "code" in the above snippet.


Solution

  • I had not registered my app properly in the developer console. After fixing it my problem was solved and the above code worked.