title: Android In-app Purchase V3 Error: Authentication is required
body: <p>I am implementing <code>Google In-app Purchase V3</code> and followed all steps stated over <a href="https://help.gamesalad.com/hc/en-us/articles/203536123-7-6-In-App-Purchases-IAP-for-Google-Play" rel="noreferrer">here</a> as well in official documentation <a href="http://developer.android.com/google/play/billing/api.html" rel="noreferrer">here</a>. I have uploaded my app in Google Playstore for <code>Alpha Testing</code> and I have downloaded that from playstore URL into my real device but it giving me error</p>
  <blockquote>
  <p>Error</p>
  <p>Authentication is required. You need to sign into your Google Account.</p>
  </blockquote>
  <p><img src="https://i.stack.imgur.com/njWmf.jpg" alt="enter image description here" /></p>
  <p>My code for In-app purchase is here:</p>
  <pre><code>public class BuyPointsFragment extends Fragment
  //In app Billing variable start
  
      // Debug tag, for logging
          static final String TAG = &quot;com.myApp&quot;;
  
          // Does the user have the premium upgrade?
          boolean mIsPremium = false;
  
          // Does the user have an active subscription to the infinite gas plan?
          boolean mSubscribedToInfiniteGas = false;
  
          // SKUs for our products: the premium upgrade (non-consumable) and gas
          // (consumable)
          static final String SKU_PREMIUM = &quot;premium&quot;;
          static final String SKU_GAS = &quot;gas&quot;;
  
          // SKU for our subscription (infinite gas)
          static final String SKU_INFINITE_GAS = &quot;infinite_gas&quot;;
  
          // (arbitrary) request code for the purchase flow
          static final int RC_REQUEST = 10001;
  
          // Graphics for the gas gauge
          static int[] TANK_RES_IDS = {};
  
          // How many units (1/4 tank is our unit) fill in the tank.
          static final int TANK_MAX = 4;
  
          // Current amount of gas in tank, in units
          int mTank;
  
          // The helper object
          IabHelper mHelper;
          
      
  
      //In app billing variable end
  
  
  
  @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
              Bundle savedInstanceState) {
      //inapp  load game data
              loadData();
              
              String base64EncodedPublicKey = &quot;Base64Key from publisher account&quot;;
  
              // Some sanity checks to see if the developer (that's you!) really
              // followed the
              // instructions to run this sample (don't put these checks on your app!)
              if (base64EncodedPublicKey.contains(&quot;CONSTRUCT_YOUR&quot;)) {
                  throw new RuntimeException(
                          &quot;Please put your app's public key in MainActivity.java. See README.&quot;);
              }
              if (getActivity().getPackageName().startsWith(&quot;com.myApp.activity&quot;)) {
                  throw new RuntimeException(
                          &quot;Please change the sample's package name! See README.&quot;);
              }
  
              // Create the helper, passing it our context and the public key to
              // verify signatures with
              Log.d(TAG, &quot;Creating IAB helper.&quot;);
              mHelper = new IabHelper(getActivity(), base64EncodedPublicKey);
  
              // enable debug logging (for a production application, you should set
              // this to false).
              mHelper.enableDebugLogging(true);
  
              // Start setup. This is asynchronous and the specified listener
              // will be called once setup completes.
              Log.d(TAG, &quot;Starting setup.&quot;);
              mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
                  public void onIabSetupFinished(IabResult result) {
                      Log.d(TAG, &quot;Setup finished.&quot;);
  
                      if (!result.isSuccess()) {
                          // Oh noes, there was a problem.
                          complain(getString(R.string.problem_setting_inapp_billing) + result);
                          return;
                      }
  
                      // Have we been disposed of in the meantime? If so, quit.
                      if (mHelper == null)
                          return;
  
                      // IAB is fully set up. Now, let's get an inventory of stuff we
                      // own.
                      Log.d(TAG, &quot;Setup successful. Querying inventory.&quot;);
                      mHelper.queryInventoryAsync(mGotInventoryListener);
                      
                      
                      
                  }
              });
  
              //In app billing code end here
      }
  </code></pre>
  <p>//In app billing methods start here</p>
  <pre><code>public void inappCall(){
      
      setWaitScreen(true);
      Log.d(TAG, &quot;Launching purchase flow for gas.&quot;);
  
      /*
       * TODO: for security, generate your payload here for verification. See
       * the comments on verifyDeveloperPayload() for more info. Since this is
       * a SAMPLE, we just use an empty string, but on a production app you
       * should carefully generate this.
       */
      String payload = &quot;&quot;;
  
      mHelper.launchPurchaseFlow(getActivity(), SKU_GAS, RC_REQUEST,
              mPurchaseFinishedListener, payload);
  }
  
      // updates UI to reflect model
          public void updateUi() {
              // update the car color to reflect premium status or lack thereof
              // ((ImageView)findViewById(R.id.free_or_premium)).setImageResource(mIsPremium
              // ? R.drawable.premium : R.drawable.free);
  
              // &quot;Upgrade&quot; button is only visible if the user is not premium
              // findViewById(R.id.upgrade_button).setVisibility(mIsPremium ?
              // View.GONE : View.VISIBLE);
  
              // &quot;Get infinite gas&quot; button is only visible if the user is not
              // subscribed yet
              // (R.id.infinite_gas_button).setVisibility(mSubscribedToInfiniteGas ?
              // View.GONE : View.VISIBLE);
  
              // update gas gauge to reflect tank status
              if (mSubscribedToInfiniteGas) {
                  // ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(R.drawable.gas_inf);
              } else {
                  int index = mTank &gt;= TANK_RES_IDS.length ? TANK_RES_IDS.length - 1
                          : mTank;
                  // ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(TANK_RES_IDS[index]);
              }
          }
  
          // Enables or disables the &quot;please wait&quot; screen.
          void setWaitScreen(boolean set) {
              // findViewById(R.id.screen_main).setVisibility(set ? View.GONE :
              // View.VISIBLE);
              // findViewById(R.id.screen_wait).setVisibility(set ? View.VISIBLE :
              // View.GONE);
          }
  
          void complain(String message) {
              Log.e(TAG, &quot;**** TrivialDrive Error: &quot; + message);
              alert(&quot;Error: &quot; + message);
          }
  
          void alert(String message) {
              AlertDialog.Builder bld = new AlertDialog.Builder(getActivity());
              bld.setMessage(message);
              bld.setNeutralButton(&quot;OK&quot;, null);
              Log.d(TAG, &quot;Showing alert dialog: &quot; + message);
              bld.create().show();
          }
  
          void saveData() {
  
              /*
               * WARNING: on a real application, we recommend you save data in a
               * secure way to prevent tampering. For simplicity in this sample, we
               * simply store the data using a SharedPreferences.
               */
  
              SharedPreferences.Editor spe = getActivity().getPreferences(getActivity().MODE_PRIVATE).edit();
              spe.putInt(&quot;tank&quot;, mTank);
              spe.commit();
              Log.d(TAG, &quot;Saved data: tank = &quot; + String.valueOf(mTank));
          }
  
          void loadData() {
              SharedPreferences sp = getActivity().getPreferences(getActivity().MODE_PRIVATE);
              mTank = sp.getInt(&quot;tank&quot;, 2);
              Log.d(TAG, &quot;Loaded data: tank = &quot; + String.valueOf(mTank));
          }
      
          // We're being destroyed. It's important to dispose of the helper here!
          @Override
          public void onDestroy() {
              super.onDestroy();
  
              // very important:
              Log.d(TAG, &quot;Destroying helper.&quot;);
              if (mHelper != null) {
                  mHelper.dispose();
                  mHelper = null;
              }
          }
          
          // Listener that's called when we finish querying the items and
          // subscriptions we own
          IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
              public void onQueryInventoryFinished(IabResult result,
                      Inventory inventory) {
                  Log.d(TAG, &quot;Query inventory finished.&quot;);
  
                  // Have we been disposed of in the meantime? If so, quit.
                  if (mHelper == null)
                      return;
  
                  // Is it a failure?
                  if (result.isFailure()) {
                      complain(getString(R.string.failed_to_query_inventory) + result);
                      return;
                  }
  
                  Log.d(TAG, &quot;Query inventory was successful.&quot;);
  
                  /*
                   * Check for items we own. Notice that for each purchase, we check
                   * the developer payload to see if it's correct! See
                   * verifyDeveloperPayload().
                   */
  
                  // Do we have the premium upgrade?
                  Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
                  mIsPremium = (premiumPurchase != null &amp;&amp; verifyDeveloperPayload(premiumPurchase));
                  Log.d(TAG, &quot;User is &quot; + (mIsPremium ? &quot;PREMIUM&quot; : &quot;NOT PREMIUM&quot;));
  
                  // Do we have the infinite gas plan?
                  Purchase infiniteGasPurchase = inventory
                          .getPurchase(SKU_INFINITE_GAS);
                  mSubscribedToInfiniteGas = (infiniteGasPurchase != null &amp;&amp; verifyDeveloperPayload(infiniteGasPurchase));
                  Log.d(TAG, &quot;User &quot;
                          + (mSubscribedToInfiniteGas ? &quot;HAS&quot; : &quot;DOES NOT HAVE&quot;)
                          + &quot; infinite gas subscription.&quot;);
                  if (mSubscribedToInfiniteGas)
                      mTank = TANK_MAX;
  
                  // Check for gas delivery -- if we own gas, we should fill up the
                  // tank immediately
                  Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
                  if (gasPurchase != null &amp;&amp; verifyDeveloperPayload(gasPurchase)) {
                      Log.d(TAG, &quot;We have gas. Consuming it.&quot;);
                      mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
                              mConsumeFinishedListener);
                      return;
                  }
  
                  updateUi();
                  setWaitScreen(false);
                  Log.d(TAG, &quot;Initial inventory query finished; enabling main UI.&quot;);
              }
          };
          
          /** Verifies the developer payload of a purchase. */
          boolean verifyDeveloperPayload(Purchase p) {
              String payload = p.getDeveloperPayload();
  
              /*
               * TODO: verify that the developer payload of the purchase is correct.
               * It will be the same one that you sent when initiating the purchase.
               * 
               * WARNING: Locally generating a random string when starting a purchase
               * and verifying it here might seem like a good approach, but this will
               * fail in the case where the user purchases an item on one device and
               * then uses your app on a different device, because on the other device
               * you will not have access to the random string you originally
               * generated.
               * 
               * So a good developer payload has these characteristics:
               * 
               * 1. If two different users purchase an item, the payload is different
               * between them, so that one user's purchase can't be replayed to
               * another user.
               * 
               * 2. The payload must be such that you can verify it even when the app
               * wasn't the one who initiated the purchase flow (so that items
               * purchased by the user on one device work on other devices owned by
               * the user).
               * 
               * Using your own server to store and verify developer payloads across
               * app installations is recommended.
               */
  
              return true;
          }
          
          // Callback for when a purchase is finished
          IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
              public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
                  Log.d(TAG, &quot;Purchase finished: &quot; + result + &quot;, purchase: &quot;
                          + purchase);
  
                  // if we were disposed of in the meantime, quit.
                  if (mHelper == null)
                      return;
  
                  if (result.isFailure()) {
                      complain(getString(R.string.error_purchase) + result);
                      setWaitScreen(false);
                      return;
                  }
                  if (!verifyDeveloperPayload(purchase)) {
                      complain(getString(R.string.error_purchase_authenitcity_failed));
                      setWaitScreen(false);
                      return;
                  }
  
                  Log.d(TAG, &quot;Purchase successful.&quot;);
  
                  if (purchase.getSku().equals(SKU_GAS)) {
                      // bought 1/4 tank of gas. So consume it.
                      Log.d(TAG, &quot;Purchase is gas. Starting gas consumption.&quot;);
                      mHelper.consumeAsync(purchase, mConsumeFinishedListener);
                  } else if (purchase.getSku().equals(SKU_PREMIUM)) {
                      // bought the premium upgrade!
                      Log.d(TAG, &quot;Purchase is premium upgrade. Congratulating user.&quot;);
                      alert(getString(R.string.thank_you_updgraing_premium));
                      mIsPremium = true;
                      updateUi();
                      setWaitScreen(false);
                  } else if (purchase.getSku().equals(SKU_INFINITE_GAS)) {
                      // bought the infinite gas subscription
                      Log.d(TAG, &quot;Infinite gas subscription purchased.&quot;);
                      alert(&quot;Thank you for subscribing to infinite gas!&quot;);
                      mSubscribedToInfiniteGas = true;
                      mTank = TANK_MAX;
                      updateUi();
                      setWaitScreen(false);
                  }
              }
          };
  
          // Called when consumption is complete
          IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
              public void onConsumeFinished(Purchase purchase, IabResult result) {
                  Log.d(TAG, &quot;Consumption finished. Purchase: &quot; + purchase
                          + &quot;, result: &quot; + result);
  
                  // if we were disposed of in the meantime, quit.
                  if (mHelper == null)
                      return;
  
                  // We know this is the &quot;gas&quot; sku because it's the only one we
                  // consume,
                  // so we don't check which sku was consumed. If you have more than
                  // one
                  // sku, you probably should check...
                  if (result.isSuccess()) {
                      // successfully consumed, so we apply the effects of the item in
                      // our
                      // game world's logic, which in our case means filling the gas
                      // tank a bit
                      Log.d(TAG, &quot;Consumption successful. Provisioning.&quot;);
                      mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
                      saveData();
                      alert(&quot;You filled 1/4 tank. Your tank is now &quot;
                              + String.valueOf(mTank) + &quot;/4 full!&quot;);
                  } else {
                      complain(&quot;Error while consuming: &quot; + result);
                  }
                  updateUi();
                  setWaitScreen(false);
                  Log.d(TAG, &quot;End consumption flow.&quot;);
              }
          };
          
          @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data) {
              Log.d(TAG, &quot;onActivityResult(&quot; + requestCode + &quot;,&quot; + resultCode + &quot;,&quot;
                      + data);
              if (mHelper == null)
                  return;
  
              // Pass on the activity result to the helper for handling
              if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
                  // not handled, so handle it ourselves (here's where you'd
                  // perform any handling of activity results not related to in-app
                  // billing...
                  super.onActivityResult(requestCode, resultCode, data);
              } else {
                  Log.d(TAG, &quot;onActivityResult handled by IABUtil.&quot;);
              }
          }
          
          
  
      
      //In app billing method end here
  </code></pre>
  <p>My products are <code>Managed products</code> in developer account <code>In-app Products</code></p>
  <p><img src="https://i.stack.imgur.com/0zRgq.jpg" alt="enter image description here" /></p>
  <p><strong>EDIT:</strong></p>
  <p>When I use <code>android.test.purchased</code> as a <code>SKU</code> then it works fine and as I change my <code>sku</code> with my <code>product_id</code> then it giving me <code>Error Authentication is required. You need to sign into your Google Account.</code></p>