public function fetchToken($client_email, $key_file, $delegate_email = null) {
    $header = array(
      "alg" => self::header_alg,
      "typ" => self::header_typ,
    );

    $claimset = array(
      "iss" => $client_email,
      "scope" => self::scope_url,
      "aud" => self::request_url,
      "exp" => time() + (60 * 60),
      "iat" => time(),
    );

    if(!empty($delegate_email)) {
      $claimset["sub"] = $delegate_email;
    }

    $data = $this->base64URLEncode(json_encode($header)) . '.' . $this->base64URLEncode(json_encode($claimset));

    if (!file_exists($key_file)) {
      if ( !file_exists(__DIR__ . DIRECTORY_SEPARATOR . $key_file) ) {
        throw new Exception('GAPI: Failed load key file "' . $key_file . '". File could not be found.');
      } else {
        $key_file = __DIR__ . DIRECTORY_SEPARATOR . $key_file;
      }
    }

    $key_data = file_get_contents($key_file);
    
    if (empty($key_data)) {
      throw new Exception('GAPI: Failed load key file "' . $key_file . '". File could not be opened or is empty.');
    }

    openssl_pkcs12_read($key_data, $certs, 'notasecret');

    if (!isset($certs['pkey'])) {
      throw new Exception('GAPI: Failed load key file "' . $key_file . '". Unable to load pkcs12 check if correct p12 format.');
    }

    openssl_sign($data, $signature, openssl_pkey_get_private($certs['pkey']), "sha256");

    $post_variables = array(
      'grant_type' => self::grant_type,
      'assertion' => $data . '.' . $this->base64URLEncode($signature),
    );

    $url = new gapiRequest(self::request_url);
    $response = $url->post(null, $post_variables);
    $auth_token = json_decode($response['body'], true);

    if (substr($response['code'], 0, 1) != '2' || !is_array($auth_token) || empty($auth_token['access_token'])) {
      throw new Exception('GAPI: Failed to authenticate user. Error: "' . strip_tags($response['body']) . '"');
    }

    $this->auth_token = $auth_token['access_token'];

    return $this->auth_token;
  }