diff --git a/db/migrations/stored/R__procedures.sql b/db/migrations/stored/R__procedures.sql
index 88fdbfa92830ac40905fe46b876b71a24413fef4..00b05fa0b4f4c48349ab472c6688d27f0da43d1c 100644
--- a/db/migrations/stored/R__procedures.sql
+++ b/db/migrations/stored/R__procedures.sql
@@ -1468,14 +1468,13 @@ CREATE PROCEDURE GetAuthTokens(
     IN pAccountID int(11))
 BEGIN
     -- accountID, Created, Accessed, Mask
-    IF pAccountID = 0 THEN
-        SELECT auth_tokens.*
-            FROM auth_tokens;
-    ELSE
-        SELECT auth_tokens.*
-            FROM auth_tokens
-            WHERE auth_tokens.AccountID = pAccountID;
-    END IF;
+    SELECT *
+    FROM auth_tokens
+    INNER JOIN accounts ON accounts.ID = auth_tokens.AccountID
+    WHERE
+        auth_tokens.AccountID = pAccountID OR
+        pAccountID = 0
+    ORDER BY auth_tokens.Created DESC;
 END//
 
 # -------------------------------------------------------------------------------------------
diff --git a/deploy/phpConfig/sidePanel/admin.json b/deploy/phpConfig/sidePanel/admin.json
index 66fddee1b797ca6af8fb3ecc545a9fd55015fd61..56fcc6594560ac99ee851624632511ca22783c3d 100644
--- a/deploy/phpConfig/sidePanel/admin.json
+++ b/deploy/phpConfig/sidePanel/admin.json
@@ -30,6 +30,7 @@
 		"Items": [
 			{ "Title": "История авторизаций", "Anchor": "logs" },
 			{ "Title": "История выставления баллов", "Anchor": "#", "Disabled": "true" },
+			{ "Title": "Токены авторизации", "Anchor": "authTokens" },
 			{ "Title": "Поддержка", "Anchor": "support" }
 		]
 	}
diff --git a/media/css/logs.css b/media/css/logs.css
deleted file mode 100644
index 088e14f204ffea31ed8a3dfef30a2dba9d8d67c7..0000000000000000000000000000000000000000
--- a/media/css/logs.css
+++ /dev/null
@@ -1,3 +0,0 @@
-table.equal-width-cols td {
-    padding: 5px;
-}
diff --git a/media/js/office/tokens.js b/media/js/office/tokens.js
new file mode 100644
index 0000000000000000000000000000000000000000..03092fa41ceb6158312abe8e34bbb25b83744186
--- /dev/null
+++ b/media/js/office/tokens.js
@@ -0,0 +1,54 @@
+$(() => {
+    $('#createToken').click(function () {
+        $(this).prop('disabled', true);
+        
+        $.getJSON(URLdir + 'handler/authTokens/create').success(result => {
+            Popup.success('Токен добавлен');
+            location.reload();
+        }).fail(jqXHR => {
+            let status = parseInt(jqXHR.status);
+            if (status == 403) {
+                Popup.error('Недостаточно прав');
+                return;
+            }
+            try {
+                if (status != 400) throw null;
+                let message = JSON.parse(jqXHR.responseText).message;
+                if (!message) throw null;
+                Popup.error(message);
+            } catch (error) {
+                Popup.error('Не удалось добавить токен');
+            }
+        }).always(() => $(this).prop('disabled', false));
+    });
+
+    $('.officeList').on('click', '.deleteToken', function (event) {
+        event.preventDefault();
+
+        $(this).prop('disabled', true);
+
+        let $body = $(this).parents('tbody');
+        let $row = $(this).parents('tr');
+        let token = $row.children('.token').text();
+
+        $.getJSON(URLdir + 'handler/authTokens/delete/' + token).success(() => {
+            $row.remove();
+            if (!$body.children().length) $body.append('<tr><td colspan="6" class="empty">Нет записей</td></tr>');
+            Popup.success('Токен удален');
+        }).fail(jqXHR => {
+            let status = parseInt(jqXHR.status);
+            if (status == 403) {
+                Popup.error('Недостаточно прав');
+                return;
+            }
+            try {
+                if (status != 400) throw null;
+                let message = JSON.parse(jqXHR.responseText).message;
+                if (!message) throw null;
+                Popup.error(message);
+            } catch (error) {
+                Popup.error('Не удалось удалить токен');
+            }
+        }).always(() => $(this).prop('disabled', false));
+    });
+});
\ No newline at end of file
diff --git a/media/less/office/list.less b/media/less/office/list.less
new file mode 100644
index 0000000000000000000000000000000000000000..3a2dfa878f5c1c9f431fd505a8b902170f6a57e9
--- /dev/null
+++ b/media/less/office/list.less
@@ -0,0 +1,41 @@
+@import (reference) "../common.less";
+
+.officeList {
+    overflow-x: auto;
+
+    table {
+        min-width: 100%;
+        border-collapse: collapse;
+
+        td {
+            padding: 5px;
+            border: 1px solid #ccc;
+            vertical-align: middle;
+        }
+
+        thead {
+            background-color: #f0f7fd;
+
+            text-align: center;
+            text-overflow: ellipsis;
+        }
+
+        tbody {
+            background-color: @ColorBaseWhite;
+            white-space: nowrap;
+
+            tr {
+                &:hover,
+                &.focus {
+                    background-color: @ColorBaseGrey;
+                }
+            }
+
+            .empty {
+                background-color: @ColorBaseWhite;
+
+                text-align: center;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/media/less/office/tokens.less b/media/less/office/tokens.less
new file mode 100644
index 0000000000000000000000000000000000000000..f9e899a0c751d33df06461d2365e0fa5c4275e3b
--- /dev/null
+++ b/media/less/office/tokens.less
@@ -0,0 +1,17 @@
+.main_side_content {
+    .contentTitle {
+        float: left;
+    }
+
+    .createToken {
+        float: right;
+        padding-left: 15px;
+        padding-right: 15px;
+        margin: 0;
+        margin-bottom: 10px;
+    }
+
+    .officeList {
+        clear: both;
+    }
+}
\ No newline at end of file
diff --git a/~dev_rating/application/classes/Controller/Handler/AuthTokens.php b/~dev_rating/application/classes/Controller/Handler/AuthTokens.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ae847eb715edb3dbbb32e9064cefc10f050d928
--- /dev/null
+++ b/~dev_rating/application/classes/Controller/Handler/AuthTokens.php
@@ -0,0 +1,33 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+/** Получение списка групп, курсов, предметов, и т.д. */
+class Controller_Handler_AuthTokens extends Controller_Handler
+{
+    public function before() {
+        parent::before();
+        
+        $this->user->checkAccess(User::RIGHTS_ADMIN);
+    }
+
+    public function action_create() {
+        $token = Model_Account::createAuthToken($this->user->ID);
+        if (is_null($token)) {
+            HTTP_API_Exception::factory(500, 'Ошибка приложения');
+        }
+
+        $this->response->body(json_encode([
+            success => true,
+            token   => $token,
+        ]));
+    }
+
+    public function action_delete() {
+        $token = $this->request->param('id');
+        $errorCode = Model_Account::deleteAuthToken($token);
+        if ($errorCode != 0) {
+            HTTP_API_Exception::factory(500, 'Ошибка приложения');
+        }
+
+        $this->response->body(json_encode([ success => true ]));
+    }
+}
\ No newline at end of file
diff --git a/~dev_rating/application/classes/Controller/Office/AuthTokens.php b/~dev_rating/application/classes/Controller/Office/AuthTokens.php
new file mode 100644
index 0000000000000000000000000000000000000000..cd9c2725b9a05c015a171690729e025bd6c09e8c
--- /dev/null
+++ b/~dev_rating/application/classes/Controller/Office/AuthTokens.php
@@ -0,0 +1,10 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Office_AuthTokens extends Controller_Environment_Office
+{
+    public function action_index() {
+        $this->twig->set([
+            'Tokens' => Model_Account::getAuthTokens(),
+        ])->set_filename(static::OFFICE . 'tokens');
+    }
+}
\ No newline at end of file
diff --git a/~dev_rating/application/classes/Model/Account.php b/~dev_rating/application/classes/Model/Account.php
index 22bd45375cd08d1c67d555b38a7a25a330a26462..d6cb4436878753e3dac54553fc8b701d80a2c0ef 100644
--- a/~dev_rating/application/classes/Model/Account.php
+++ b/~dev_rating/application/classes/Model/Account.php
@@ -155,13 +155,6 @@ class Model_Account extends Model
     //      auth tokens management
     // =====================================
 
-    public static function deleteAuthToken($token) {
-        $sql = 'SELECT `deleteAuthToken`(:token) AS `res`';
-        return DB::query(Database::SELECT, $sql)
-            ->param(':token', $token)
-            ->execute()->get('res');
-    }
-
     /**
      * @param int $accountID
      * @param int $mask bit mask with access rights
@@ -176,12 +169,19 @@ class Model_Account extends Model
             ])->execute()->get('token');
     }
 
+    public static function deleteAuthToken($token) {
+        $sql = 'SELECT `deleteAuthToken`(:token) AS `res`';
+        return DB::query(Database::SELECT, $sql)
+            ->param(':token', $token)
+            ->execute()->get('res');
+    }
+
     /**
      * @param int $accountID - 0 to get auth tokens of all users
      * @return mixed
      */
     public static function getAuthTokens($accountID = 0) {
-        $sql = 'CALL `GetAuthTokens`(:user)`';
+        $sql = 'CALL `GetAuthTokens`(:user)';
         return DB::query(Database::SELECT, $sql)
             ->param(':user', (int) $accountID)
             ->execute();
diff --git a/~dev_rating/application/views/office/logs.twig b/~dev_rating/application/views/office/logs.twig
index c40aa5e032ed40881eb45d8ccea429ca88797652..a9cec07aea3c811d0c99bb54772ee9d75ad33155 100644
--- a/~dev_rating/application/views/office/logs.twig
+++ b/~dev_rating/application/views/office/logs.twig
@@ -3,27 +3,31 @@
    
 {% block title %}История авторизаций{% endblock %}
 
-{% block office_content %}
-
-    {{ HTML.style('static/css/logs.css')|raw }}
+{% block office_media %}
+    {{ HTML.style('static/css/office/list.css')|raw }}
+{% endblock %}
 
+{% block office_content %}
     <h2 class="Margin10 Bottom">История авторизаций</h2>
 
-    <table class="equal-width-cols" cellpadding="20">
-
-        <tr class="TableHead">
-            <td>Дата и время</td>
-            <td>ФИО</td>
-            <td>AccoundID</td>
-        </tr>
-
-        {% for Log in Logs %}
-            <tr>
-                <td>{{ Log.Date }}</td>
-                <td>{{ Log.LastName }} {{ Log.FirstName }} {{ Log.SecondName }}</td>
-                <td>{{ Log.AccountID }}</td>
-            </tr>
-        {% endfor %}
-
-    </table>
+    <div class="officeList">
+        <table>
+            <thead>
+                <tr>
+                    <td>Дата авторизации</td>
+                    <td>ФИО пользователя</td>
+                </tr>
+            </thead>
+            <tbody>
+                {% for Log in Logs %}
+                    <tr>
+                        <td>{{ Log.Date }}</td>
+                        <td>{{ Log.LastName }} {{ Log.FirstName }} {{ Log.SecondName }}</td>
+                    </tr>
+                {% else %}
+                    <tr><td colspan="3" class="empty">Нет записей</td></tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
 {% endblock %}
diff --git a/~dev_rating/application/views/office/tokens.twig b/~dev_rating/application/views/office/tokens.twig
new file mode 100644
index 0000000000000000000000000000000000000000..03c656274fa150ab35baf0b9f730dd5f0de6f1e8
--- /dev/null
+++ b/~dev_rating/application/views/office/tokens.twig
@@ -0,0 +1,46 @@
+{% extends "office/base" %}
+
+   
+{% block title %}Токены авторизации{% endblock %}
+
+{% block office_media %}
+    {{ HTML.script('static/js/office/tokens.js')|raw }}
+
+    {{ HTML.style('static/css/office/list.css')|raw }}
+    {{ HTML.style('static/css/office/tokens.css')|raw }}
+{% endblock %}
+
+{% block office_content %}
+    <h2 class="Margin10 Bottom contentTitle">Токены авторизации</h2>
+
+    <button class="defaultForm GreenButton createToken" id="createToken">Создать токен</button>
+
+    <div class="officeList">
+        <table>
+            <thead>
+                <tr>
+                    <td>Дата создания</td>
+                    <td>ФИО пользователя</td>
+                    <td>Токен</td>
+                    <td>Дата авторизации</td>
+                    <td>Маска</td>
+                    <td>Действия</td>
+                </tr>
+            </thead>
+            <tbody>
+                {% for Token in Tokens %}
+                    <tr>
+                        <td>{{ Token.Created }}</td>
+                        <td>{{ Token.LastName }} {{ Token.FirstName }} {{ Token.SecondName }}</td>
+                        <td class='token'>{{ Token.Token }}</td>
+                        <td>{{ Token.Accessed }}</td>
+                        <td>{{ Token.Mask }}</td>
+                        <td><a href="#" class="deleteToken">Удалить токен</a></td>
+                    </tr>
+                {% else %}
+                    <tr><td colspan="6" class="empty">Нет записей</td></tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+{% endblock %}