diff --git a/js/plugins/tokenbrowser/plugin.js b/js/plugins/tokenbrowser/plugin.js
new file mode 100644
index 0000000..8d93163
--- /dev/null
+++ b/js/plugins/tokenbrowser/plugin.js
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Drupal Entity embed plugin.
+ */
+
+(function ($, Drupal, CKEDITOR) {
+
+  "use strict";
+
+  CKEDITOR.plugins.add('tokenbrowser', {
+
+    // The plugin initialization logic goes inside this method.
+    beforeInit: function (editor) {
+
+      // Generic command
+      editor.addCommand('edittokenbrowser', {
+        modes: { wysiwyg : 1 },
+        canUndo: true,
+        exec: function (editor, data) {
+          data = data || {};
+
+          // we have no current existingValues
+          var existingValues = {};
+
+          // set all options for the model
+          var dialogOptions = {
+            dialogClass: 'token-browser-dialog',
+            autoResize: false,
+            modal: false,
+            draggable: true,
+          };
+          var dialogSettings = drupalSettings.dialog;
+
+          // we have no current saveCallback
+          var saveCallback = function (values) {};
+
+          // Open token browser dialog.
+          Drupal.ckeditor.openDialog(editor, data.link, existingValues, saveCallback, dialogOptions);
+
+        }
+      });
+
+      // Register the toolbar buttons.
+      if (editor.ui.addButton) {
+        for (var key in editor.config.TokenBrowser_buttons) {
+          var button = editor.config.TokenBrowser_buttons[key];
+          editor.ui.addButton(button.id, {
+            label: button.label,
+            data: button,
+            click: function(editor) {
+              editor.execCommand('edittokenbrowser', this.data);
+            },
+            icon: button.image
+          });
+        }
+      }
+    }
+  });
+
+})(jQuery, Drupal, CKEDITOR);
diff --git a/js/plugins/tokenbrowser/tokenbrowser.png b/js/plugins/tokenbrowser/tokenbrowser.png
new file mode 100644
index 0000000..7fb5acf
Binary files /dev/null and b/js/plugins/tokenbrowser/tokenbrowser.png differ
diff --git a/src/Plugin/CKEditorPlugin/TokenBrowser.php b/src/Plugin/CKEditorPlugin/TokenBrowser.php
new file mode 100644
index 0000000..41876bb
--- /dev/null
+++ b/src/Plugin/CKEditorPlugin/TokenBrowser.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Drupal\token_filter\Plugin\CKEditorPlugin;
+
+use Drupal\Component\Serialization\Json;
+use Drupal\Component\Utility\DiffArray;
+use Drupal\Core\Url;
+use Drupal\ckeditor\CKEditorPluginBase;
+use Drupal\editor\Entity\Editor;
+
+
+/**
+ * Defines the "tokenbrowser" plugin.
+ *
+ * NOTE: The plugin ID ('id' key) corresponds to the CKEditor plugin name.
+ * It is the first argument of the CKEDITOR.plugins.add() function in the
+ * plugin.js file.
+ *
+ * @CKEditorPlugin(
+ *   id = "tokenbrowser",
+ *   label = @Translation("Token browser")
+ * )
+ */
+class TokenBrowser extends CKEditorPluginBase {
+
+
+  /**
+   * {@inheritdoc}
+   *
+   * NOTE: The keys of the returned array corresponds to the CKEditor button
+   * names. They are the first argument of the editor.ui.addButton() or
+   * editor.ui.addRichCombo() functions in the plugin.js file.
+   */
+  public function getButtons() {
+    // Make sure that the path to the image matches the file structure of
+    // the CKEditor plugin you are implementing.
+
+    $options['query']['options'] = [
+      'token_types' => [],
+      'global_types' => TRUE,
+      'click_insert' => TRUE,
+      'show_restricted' => FALSE,
+      'show_nested' => FALSE,
+      'recursion_limit' => 3,
+    ];
+
+    $url = Url::fromRoute('token.tree');
+    $token = \Drupal::csrfToken()->get($url->getInternalPath());
+    $options['query']['options'] = Json::encode($options['query']['options']);
+    $options['query']['token'] = $token;
+    $url->setOptions($options);
+    $link = $url->toString();
+
+    return [
+      'tokenbrowser' => [
+        'id' => 'tokenbrowser',
+        'label' => t('Token browser'),
+        'image' => file_create_url(drupal_get_path('module', 'token_filter') . '/js/plugins/tokenbrowser/tokenbrowser.png'),
+        'link' =>  $link,
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFile() {
+    // Make sure that the path to the plugin.js matches the file structure of
+    // the CKEditor plugin you are implementing.
+    return drupal_get_path('module', 'token_filter') . '/js/plugins/tokenbrowser/plugin.js';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfig(Editor $editor) {
+    return [
+      'TokenBrowser_buttons' => $this->getButtons(),
+    ];
+  }
+
+}
