title: How to manage API permissions? javascript
body: <p>I've written some client-side app and tried to test it. How it turned out only I can use it. Anyone else will get such error. </p>
  
  <pre><code>{
   "error": {
    "errors": [
     {
      "domain": "global",
      "reason": "forbidden",
      "message": "Forbidden"
     }
    ],
    "code": 403,
    "message": "Forbidden"
   }
  }
  </code></pre>
  
  <p>What does it mean? How to solve this?
  There is my code. There i'm getting Email, name, surname and user photo. I want to get the number of youtube channel subscribers and work with youtube later. For example I want to rate some videos directly from the site.</p>
  
  <pre><code>function resultFindUserByEmail()
  {
    if (ajaxRet['isUserFinded'])
    {
      cf_JSON.clear();
      cf_JSON.addItem(    'email',email     );
      var jsonstr = cf_JSON.make();
      ajax_post('doyoutubelogin','loginres','index.php',jsonstr,c_dologin);
    }else{
  
      gapi.client.init({
        discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/people/v1/rest"],
        clientId: OAUTH2_CLIENT_ID,
        scope: OAUTH2_SCOPES
      }).then(function () {       
        var request = gapi.client.people.people.get({
        'resourceName': 'people/me'
      }).then(function(response) {
  
          var parsedResponse = JSON.parse(response.body).names;
          surname = parsedResponse[0].familyName;
          name = parsedResponse[0].givenName;
  
          photo = JSON.parse(response.body).photos[0].url; 
          addYoutubeUser();       
        });                  
      });
    }
  }
  function addYoutubeUser() {
      cf_JSON.clear();
      cf_JSON.addItem(        'Email',email              );
      cf_JSON.addItem(    'Firstname',name               );
      cf_JSON.addItem(     'Lastname',surname            );
      cf_JSON.addItem(        'Image',photo              );
      var jsonstr = cf_JSON.make();
      ajax_post('addyoutubeuser','loginres','index.php',jsonstr,c_dologin);
  }
  
  var API_KEY = '&lt;Key removed for posting&gt;'; 
  var API_KEY1='&lt;Key removed for posting&gt;';
  var OAUTH2_CLIENT_ID = '&lt;Key removed for posting&gt;';
  var OAUTH2_CLIENT_ID1 = '&lt;Key removed for posting&gt;';
  var OAUTH2_SCOPES = 'https://www.googleapis.com/auth/youtube.force-ssl';
  var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];
  
    var GoogleAuth;
    function handleClientLoad() {
      // Load the API's client and auth2 modules.
      // Call the initClient function after the modules load.
      gapi.load('client:auth2', initClient);
    }
  
    function initClient() {
      // Retrieve the discovery document for version 3 of YouTube Data API.
      // In practice, your app can retrieve one or more discovery documents.
      var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest';
  
      // Initialize the gapi.client object, which app uses to make API requests.
      // Get API key and client ID from API Console.
      // 'scope' field specifies space-delimited list of access scopes.  
      gapi.client.init({
          'apiKey': API_KEY,
          'discoveryDocs': [discoveryUrl,"https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
          'clientId': OAUTH2_CLIENT_ID,
          'scope': OAUTH2_SCOPES
      }).then(function () {      
        GoogleAuth = gapi.auth2.getAuthInstance();
        //GoogleAuth.grant(OAUTH2_SCOPES);
  
        // Listen for sign-in state changes.
        GoogleAuth.isSignedIn.listen(updateSigninStatus);
  
        // Handle initial sign-in state. (Determine if user is already signed in.)
        var user = GoogleAuth.currentUser.get();
        setSigninStatus();
  
        // Call handleAuthClick function when user clicks on
        //      "Sign In/Authorize" button.
        $('#sign-in-or-out-button').click(function() {
          handleAuthClick();
        }); 
        $('#revoke-access-button').click(function() {
          revokeAccess();      
        }); 
      });
    }
  
    function handleAuthClick() {
      if (GoogleAuth.isSignedIn.get()) {
        // User is authorized and has clicked 'Sign out' button.
        GoogleAuth.signOut();
      } else {
        // User is not signed in. Start Google auth flow.
        GoogleAuth.signIn();
      }
    }
  
    function revokeAccess() {
      GoogleAuth.disconnect();
    }
  
    function setSigninStatus(isSignedIn) {
      var user = GoogleAuth.currentUser.get();
  
      var isAuthorized = user.hasGrantedScopes(OAUTH2_SCOPES);
      if (isAuthorized) {
        $('#sign-in-or-out-button').html('Sign out');
        $('#revoke-access-button').css('display', 'inline-block');
        $('#auth-status').html('You are currently signed in and have granted ' +
            'access to this app.');
  
            //// get gmail Email
        gapi.client.init({
          'apiKey': API_KEY,
          'discoveryDocs': ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
          'clientId': OAUTH2_CLIENT_ID,
          'scope': OAUTH2_SCOPES
        }).then(function () {    
          var request = gapi.client.gmail.users.getProfile({
          'userId': 'me'
        }).then(function(response) {
  
            email = JSON.parse(response.body).emailAddress;
  
            cf_JSON.clear();
            cf_JSON.addItem(    'email',email     );
            var jsonstr = cf_JSON.make();
            tryFindUserByEmail(jsonstr);                  
          });                  
        });
  
        // try to find email
  
  
      } else {
        $('#sign-in-or-out-button').html('Вход через Youtube');
        $('#revoke-access-button').css('display', 'none');
        $('#auth-status').html('You have not authorized this app or you are ' +
            'signed out.');
      }
    }
  
    function updateSigninStatus(isSignedIn) {
      setSigninStatus();
    }
  </code></pre>