diff --git a/alembic/versions/e34e799e4182_add_reactions_to_issue_comments.py b/alembic/versions/e34e799e4182_add_reactions_to_issue_comments.py
new file mode 100644
index 0000000..d4d2247
--- /dev/null
+++ b/alembic/versions/e34e799e4182_add_reactions_to_issue_comments.py
@@ -0,0 +1,29 @@
+"""add_reactions_to_comments
+
+Revision ID: e34e799e4182
+Revises: 131ad2dc5bbd
+Create Date: 2018-05-17 18:44:32.189208
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'e34e799e4182'
+down_revision = '131ad2dc5bbd'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    ''' Add the _reactions column to table issue_comments.
+    '''
+    op.add_column(
+        'issue_comments',
+        sa.Column('_reactions', sa.Text, nullable=True)
+    )
+
+
+def downgrade():
+    ''' Remove the column _reactions from table issue_comments.
+    '''
+    op.drop_column('issue_comments', '_reactions')
diff --git a/alembic/versions/ef98dcb838e4_add_reactions_to_request_comments_py.py b/alembic/versions/ef98dcb838e4_add_reactions_to_request_comments_py.py
new file mode 100644
index 0000000..d99e8cb
--- /dev/null
+++ b/alembic/versions/ef98dcb838e4_add_reactions_to_request_comments_py.py
@@ -0,0 +1,29 @@
+"""add_reactions_to_request_comments.py
+
+Revision ID: ef98dcb838e4
+Revises: e34e799e4182
+Create Date: 2018-06-02 19:47:52.975503
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'ef98dcb838e4'
+down_revision = 'e34e799e4182'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    ''' Add the _reactions column to table pull_request_comments.
+    '''
+    op.add_column(
+        'pull_request_comments',
+        sa.Column('_reactions', sa.Text, nullable=True)
+    )
+
+
+def downgrade():
+    ''' Remove the column _reactions from table pull_request_comments.
+    '''
+    op.drop_column('pull_request_comments', '_reactions')
diff --git a/pagure/default_config.py b/pagure/default_config.py
index 24db249..8701134 100644
--- a/pagure/default_config.py
+++ b/pagure/default_config.py
@@ -422,3 +422,14 @@ EXTERNAL_COMMITTER = {}
 # Allows to require that the users are members of a certain group to be added
 # to a project (not a fork).
 REQUIRED_GROUPS = {}
+
+# Predefined reactions. Selecting others is possible by typing their name. The
+# order here will be preserved in the web UI picker for reactions.
+REACTIONS = [
+    ("Thumbs up", "emojione-1F44D"),    # Thumbs up
+    ("Thumbs down", "emojione-1F44E"),  # Thumbs down
+    ("Confused", "emojione-1F615"),     # Confused
+    ("Heart", "emojione-2764"),         # Heart
+]
+# This is used for faster indexing. Do not change.
+_REACTIONS_DICT = dict(REACTIONS)
diff --git a/pagure/lib/model.py b/pagure/lib/model.py
index 2d35c6c..e6640e4 100644
--- a/pagure/lib/model.py
+++ b/pagure/lib/model.py
@@ -1416,6 +1416,8 @@ class IssueComment(BASE):
         foreign_keys=[editor_id],
         remote_side=[User.id])
 
+    _reactions = sa.Column(sa.Text, nullable=True)
+
     @property
     def mail_id(self):
         ''' Return a unique reprensetation of the issue as string that
@@ -1429,6 +1431,20 @@ class IssueComment(BASE):
         ''' Return the parent, in this case the issue object. '''
         return self.issue
 
+    @property
+    def reactions(self):
+        ''' Return the reactions stored as a string in the database parsed as
+        an actual dict object.
+        '''
+        if self._reactions:
+            return json.loads(self._reactions)
+        return {}
+
+    @reactions.setter
+    def reactions(self, reactions):
+        ''' Ensures that reactions are properly saved. '''
+        self._reactions = json.dumps(reactions)
+
     def to_json(self, public=False):
         ''' Returns a dictionary representation of the issue.
 
@@ -1443,6 +1459,7 @@ class IssueComment(BASE):
             'editor': self.editor.to_json(public=public)
             if self.editor_id else None,
             'notification': self.notification,
+            'reactions': self.reactions,
         }
         return output
 
@@ -2000,6 +2017,8 @@ class PullRequestComment(BASE):
         foreign_keys=[editor_id],
         remote_side=[User.id])
 
+    _reactions = sa.Column(sa.Text, nullable=True)
+
     @property
     def mail_id(self):
         ''' Return a unique representation of the issue as string that
@@ -2013,6 +2032,20 @@ class PullRequestComment(BASE):
         ''' Return the parent, in this case the pull_request object. '''
         return self.pull_request
 
+    @property
+    def reactions(self):
+        ''' Return the reactions stored as a string in the database parsed as
+        an actual dict object.
+        '''
+        if self._reactions:
+            return json.loads(self._reactions)
+        return {}
+
+    @reactions.setter
+    def reactions(self, reactions):
+        ''' Ensures that reactions are properly saved. '''
+        self._reactions = json.dumps(reactions)
+
     def to_json(self, public=False):
         ''' Return a dict representation of the pull-request comment. '''
 
@@ -2030,6 +2063,7 @@ class PullRequestComment(BASE):
             'editor': self.editor.to_json(public=public)
             if self.editor_id else None,
             'notification': self.notification,
+            'reactions': self.reactions,
         }
 
 
diff --git a/pagure/static/reactions.js b/pagure/static/reactions.js
new file mode 100644
index 0000000..5411a95
--- /dev/null
+++ b/pagure/static/reactions.js
@@ -0,0 +1,37 @@
+(function () {
+    function send_reaction(commentid, reaction, emoji) {
+        var _url = location.href + '/comment/' + commentid + '/react';
+        var csrf_token = $("#csrf_token").val();
+        $.ajax({
+            url: _url + '?js=1',
+            type: 'POST',
+            data: {
+                'reaction': reaction,
+                'csrf_token': csrf_token,
+            },
+            success: function () {
+                var reactions = $(".issue_reactions[data-comment-id=" + commentid + "]>.btn-group");
+                var selected = reactions.find("span[class=" + emoji + "]");
+                if (selected.length > 0) {
+                    var counter = selected.next();
+                    counter.text(parseInt(counter.text(), 10) + 1);
+                } else {
+                    reactions.append(
+                        '<button class="btn btn-outline-secondary btn-sm" type="button">' +
+                            '    <span class="' + emoji + '"></span>' +
+                            '    <span class="count">' + 1 + '</span>' +
+                            '</button>');
+                }
+            },
+        });
+    }
+
+    $(document).ready(function () {
+        $(".reaction-picker button").click(function () {
+            var commentid = $(this).parents('.reaction-picker').data('comment-id');
+            var reaction = $(this).attr('title');
+            var emoji = $(this).find('span').attr('class');
+            send_reaction(commentid, reaction, emoji);
+        });
+    });
+})();
diff --git a/pagure/templates/_formhelper.html b/pagure/templates/_formhelper.html
index 6b8d21d..86f08a7 100644
--- a/pagure/templates/_formhelper.html
+++ b/pagure/templates/_formhelper.html
@@ -142,9 +142,37 @@
       {% if comment.edited_on %}
           <small class="text-muted">Edited {{ comment.edited_on | humanize }} by {{ comment.editor.username }} </small>
       {% endif %}
+      <div class="issue_reactions float-left pb-1" data-comment-id="{{ comment.id}}">
+        <div class="btn-group">
+          {% for r in comment.reactions | sort %}
+          <button class="btn btn-outline-secondary btn-sm"
+                  type="button"
+                  data-toggle="tooltip"
+                  title="{{ r }} sent by {{ comment.reactions[r] | join_prefix(10) }}">
+              <span class="{{ config.get('_REACTIONS_DICT', {})[r] }}"></span>
+              <span class="count">{{ comment.reactions[r] | length }}</span>
+          </button>
+          {% endfor %}
+        </div>
+      </div>
       <div class="issue_action icon float-right pb-1">
         <div class="btn-group" role="group" aria-label="Basic example">
           {% if id != 0 and g.fas_user %}
+            {% if config.get('REACTIONS') %}
+            <div class="btn-group dropup">
+              <button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-toggle="dropdown" title="Add reaction">
+                  <span class="oi" data-glyph="heart"></span>
+                  <span class="caret"></span>
+              </button>
+              <div class="dropdown-menu reaction-picker" data-comment-id="{{ comment.id }}">
+                {% for label, emoji in config.get('REACTIONS') %}
+                <button class="btn btn-outline-secondary btn-sm" type="button" title="{{ label }}">
+                    <span class="{{ emoji }}"></span>
+                </button>
+                {% endfor %}
+              </div>
+            </div>
+            {% endif %}
             <a class="reply btn btn-outline-secondary btn-sm" data-toggle="tooltip"
                 title="Reply to this comment - lose formatting">
               <span class="fa fa-share-square-o text-muted" title="Reply to this comment"></span>
diff --git a/pagure/templates/issue.html b/pagure/templates/issue.html
index d0dec58..190efc6 100644
--- a/pagure/templates/issue.html
+++ b/pagure/templates/issue.html
@@ -1046,5 +1046,6 @@ $( document ).ready(function() {
 {% if repo.quick_replies %}
 <script type="text/javascript" src="{{ url_for('static', filename='quick_reply.js') }}"></script>
 {% endif %}
+<script type="text/javascript" src="{{ url_for('static', filename='reactions.js') }}"></script>
 
 {% endblock %}
diff --git a/pagure/templates/pull_request.html b/pagure/templates/pull_request.html
index 00cf0a0..69de47c 100644
--- a/pagure/templates/pull_request.html
+++ b/pagure/templates/pull_request.html
@@ -1729,5 +1729,6 @@ sse = false;
 {% if repo.quick_replies %}
 <script type="text/javascript" src="{{ url_for('static', filename='quick_reply.js') }}"></script>
 {% endif %}
+<script type="text/javascript" src="{{ url_for('static', filename='reactions.js') }}"></script>
 
 {% endblock %}
diff --git a/pagure/ui/filters.py b/pagure/ui/filters.py
index e725fa1..7d25b3d 100644
--- a/pagure/ui/filters.py
+++ b/pagure/ui/filters.py
@@ -682,3 +682,15 @@ def flag_to_label(flag):
     """ For a given flag return the bootstrap label to use
     """
     return pagure_config['FLAG_STATUSES_LABELS'][flag.status.lower()]
+
+
+@UI_NS.app_template_filter('join_prefix')
+def join_prefix(values, num):
+    """Produce a string joining first `num` items in the list and indicate
+    total number total number of items.
+    """
+    if len(values) <= 1:
+        return "".join(values)
+    if len(values) <= num:
+        return ", ".join(values[:-1]) + " and " + values[-1]
+    return "%s and %d others" % (", ".join(values[:num]), len(values) - num)
diff --git a/pagure/ui/fork.py b/pagure/ui/fork.py
index 38ab14e..13e804a 100644
--- a/pagure/ui/fork.py
+++ b/pagure/ui/fork.py
@@ -1556,3 +1556,57 @@ def fork_edit_file(
     return flask.redirect(flask.url_for(
         'ui_ns.view_repo', repo=repo.name, username=username,
         namespace=namespace))
+
+
+@UI_NS.route(
+    '/<repo>/pull-request/<int:requestid>/comment/<int:commentid>/react', methods=['POST'])
+@UI_NS.route(
+    '/<namespace>/<repo>/pull-request/<int:requestid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<repo>/pull-request/<int:requestid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@login_required
+def pull_request_comment_add_reaction(repo, requestid, commentid,
+                                      username=None, namespace=None):
+    repo = flask.g.repo
+
+    form = pagure.forms.ConfirmationForm()
+    if not form.validate_on_submit():
+        flask.abort(400, 'CSRF token not valid')
+
+    request = pagure.lib.search_pull_requests(
+        flask.g.session, requestid=requestid, project_id=repo.id
+    )
+
+    if not request:
+        flask.abort(404, 'Comment not found')
+
+    comment = pagure.lib.get_request_comment(
+        flask.g.session, request.uid, commentid)
+
+    if 'reaction' not in flask.request.form:
+        flask.abort(400, 'Reaction not found')
+
+    reactions = comment.reactions
+    r = flask.request.form['reaction']
+    if not r:
+        flask.abort(400, 'Empty reaction is not acceptable')
+    if flask.g.fas_user.username in reactions.get(r, []):
+        flask.abort(409, 'Already posted this one')
+
+    reactions.setdefault(r, []).append(flask.g.fas_user.username)
+    comment.reactions = reactions
+    flask.g.session.add(comment)
+
+    try:
+        flask.g.session.commit()
+    except SQLAlchemyError as err:  # pragma: no cover
+        flask.g.session.rollback()
+        _log.error(err)
+        return 'error'
+
+    return 'ok'
diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py
index d440768..a46b60b 100644
--- a/pagure/ui/issues.py
+++ b/pagure/ui/issues.py
@@ -365,6 +365,79 @@ def update_issue(repo, issueid, username=None, namespace=None):
         )
 
 
+@UI_NS.route(
+    '/<repo>/issue/<int:issueid>/comment/<int:commentid>/react/',
+    methods=['POST'])
+@UI_NS.route(
+    '/<repo>/issue/<int:issueid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@UI_NS.route(
+    '/<namespace>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react/',
+    methods=['POST'])
+@UI_NS.route(
+    '/<namespace>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react/',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<namespace>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react/',
+    methods=['POST'])
+@UI_NS.route(
+    '/fork/<username>/<namespace>/<repo>/issue/<int:issueid>/comment/<int:commentid>/react',
+    methods=['POST'])
+@login_required
+@has_issue_tracker
+def issue_comment_add_reaction(repo, issueid, commentid, username=None,
+                               namespace=None):
+    '''Add a reaction to a comment of an issue'''
+    repo = flask.g.repo
+
+    issue = pagure.lib.search_issues(flask.g.session, repo, issueid=issueid)
+
+    if not issue or issue.project != repo:
+        flask.abort(404, 'Comment not found')
+
+    form = pagure.forms.ConfirmationForm()
+    if not form.validate_on_submit():
+        flask.abort(400, 'CSRF token not valid')
+
+    if issue.private and not flask.g.repo_committer \
+            and (not authenticated() or
+                 not issue.user.user == flask.g.fas_user.username):
+        flask.abort(
+            404, 'No such issue')
+
+    comment = pagure.lib.get_issue_comment(
+        flask.g.session, issue.uid, commentid)
+
+    if 'reaction' not in flask.request.form:
+        flask.abort(400, 'Reaction not found')
+
+    reactions = comment.reactions
+    r = flask.request.form['reaction']
+    if not r:
+        flask.abort(400, 'Empty reaction is not acceptable')
+    if flask.g.fas_user.username in reactions.get(r, []):
+        flask.abort(409, 'Already posted this one')
+
+    reactions.setdefault(r, []).append(flask.g.fas_user.username)
+    comment.reactions = reactions
+    flask.g.session.add(comment)
+
+    try:
+        flask.g.session.commit()
+    except SQLAlchemyError as err:  # pragma: no cover
+        flask.g.session.rollback()
+        _log.error(err)
+        return 'error'
+
+    return 'ok'
+
+
 @UI_NS.route('/<repo>/tag/<tag>/edit/', methods=('GET', 'POST'))
 @UI_NS.route('/<repo>/tag/<tag>/edit', methods=('GET', 'POST'))
 @UI_NS.route('/<namespace>/<repo>/tag/<tag>/edit/', methods=('GET', 'POST'))
diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py
index c38b0ae..3f6f685 100644
--- a/tests/test_pagure_flask_api_issue.py
+++ b/tests/test_pagure_flask_api_issue.py
@@ -2231,6 +2231,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
               "notification": False,
               "id": 1,
               "parent": None,
+              "reactions": {},
               "user": {
                 "fullname": "PY C",
                 "name": "pingou"
@@ -2257,6 +2258,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
               "notification": False,
               "id": 1,
               "parent": None,
+              "reactions": {},
               "user": {
                 "fullname": "PY C",
                 "name": "pingou"
@@ -2351,6 +2353,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
               "notification": False,
               "id": 1,
               "parent": None,
+              "reactions": {},
               "user": {
                 "fullname": "foo bar",
                 "name": "foo"
diff --git a/tests/test_pagure_flask_api_ui_private_repo.py b/tests/test_pagure_flask_api_ui_private_repo.py
index 4d7ee7c..d95d351 100644
--- a/tests/test_pagure_flask_api_ui_private_repo.py
+++ b/tests/test_pagure_flask_api_ui_private_repo.py
@@ -3093,6 +3093,7 @@ class PagurePrivateRepotest(tests.Modeltests):
                     "editor": None,
                     "id": 1,
                     "parent": None,
+                    "reactions": {},
                     "user": {
                         "fullname": "PY C",
                         "name": "pingou"
@@ -3119,6 +3120,7 @@ class PagurePrivateRepotest(tests.Modeltests):
                     "editor": None,
                     "id": 1,
                     "parent": None,
+                    "reactions": {},
                     "user": {
                         "fullname": "PY C",
                         "name": "pingou"
diff --git a/tests/test_pagure_flask_ui_fork.py b/tests/test_pagure_flask_ui_fork.py
index bce6766..468496e 100644
--- a/tests/test_pagure_flask_ui_fork.py
+++ b/tests/test_pagure_flask_ui_fork.py
@@ -3172,5 +3172,92 @@ index 0000000..2a552bb
 
         shutil.rmtree(newpath)
 
+    def _set_up_for_reaction_test(self):
+        self.session.add(pagure.lib.model.User(
+            user='jdoe',
+            fullname='John Doe',
+            password=b'password',
+            default_email='jdoe@example.com',
+        ))
+        self.session.commit()
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path, 'requests'), bare=True)
+        self.set_up_git_repo(new_project=None, branch_from='feature')
+        pagure.lib.get_authorized_project(self.session, 'test')
+        request = pagure.lib.search_pull_requests(
+            self.session, requestid=1, project_id=1,
+        )
+        pagure.lib.add_pull_request_comment(
+            self.session,
+            request=request,
+            commit=None,
+            tree_id=None,
+            filename=None,
+            row=None,
+            comment='Hello',
+            user='jdoe',
+            requestfolder=None,
+        )
+        self.session.commit()
+
+    @patch('pagure.lib.notify.send_email')
+    def test_add_reaction(self, send_email):
+        """ Test the request_pull endpoint. """
+        send_email.return_value = True
+
+        self._set_up_for_reaction_test()
+
+        user = tests.FakeUser()
+        user.username = 'pingou'
+        with tests.user_set(self.app.application, user):
+            output = self.app.get('/test/pull-request/1')
+            self.assertEqual(output.status_code, 200)
+
+            data = {
+                'csrf_token': self.get_csrf(output=output),
+                'reaction': 'Thumbs up',
+            }
+
+            output = self.app.post(
+                '/test/pull-request/1/comment/1/react',
+                data=data,
+                follow_redirects=True,
+            )
+            self.assertEqual(output.status_code, 200)
+
+            # Load the page and check reaction is added.
+            output = self.app.get('/test/pull-request/1')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                'Thumbs up sent by pingou',
+                output.get_data(as_text=True)
+            )
+
+    @patch('pagure.lib.notify.send_email')
+    def test_add_reaction_unauthenticated(self, send_email):
+        """ Test the request_pull endpoint. """
+        send_email.return_value = True
+
+        self._set_up_for_reaction_test()
+
+        output = self.app.get('/test/pull-request/1')
+        self.assertEqual(output.status_code, 200)
+
+        data = {
+            'csrf_token': self.get_csrf(output=output),
+            'reaction': 'Thumbs down',
+        }
+
+        output = self.app.post(
+            '/test/pull-request/1/comment/1/react',
+            data=data,
+            follow_redirects=False,
+        )
+        # Redirect to login page
+        self.assertEqual(output.status_code, 302)
+        self.assertIn('/login/', output.headers['Location'])
+
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/tests/test_pagure_flask_ui_issues.py b/tests/test_pagure_flask_ui_issues.py
index 6622c5e..c07590c 100644
--- a/tests/test_pagure_flask_ui_issues.py
+++ b/tests/test_pagure_flask_ui_issues.py
@@ -3807,6 +3807,126 @@ class PagureFlaskIssuestests(tests.Modeltests):
                     'title="Reply to this comment - lose formatting">',
                 ), 1)
 
+    def _set_up_for_reaction_test(self, private=False):
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
+
+        self.session.add(pagure.lib.model.User(
+            user='naysayer',
+            fullname='John Doe',
+            password=b'password',
+            default_email='jdoe@example.com',
+        ))
+        self.session.commit()
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue',
+            content='Fix me',
+            user='pingou',
+            ticketfolder=None,
+            private=private,
+        )
+        pagure.lib.add_issue_comment(
+            session=self.session,
+            issue=msg,
+            comment='How about no',
+            user='naysayer',
+            ticketfolder=None,
+        )
+        self.session.commit()
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_add_reaction(self, p_send_email, p_ugt):
+        ''' Test adding a reaction to an issue comment.'''
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        self._set_up_for_reaction_test()
+
+        user = tests.FakeUser()
+        user.username = 'pingou'
+        with tests.user_set(self.app.application, user):
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+
+            data = {
+                'csrf_token': self.get_csrf(output=output),
+                'reaction': 'Thumbs down',
+            }
+
+            output = self.app.post(
+                '/test/issue/1/comment/1/react',
+                data=data,
+                follow_redirects=True,
+            )
+            self.assertEqual(output.status_code, 200)
+
+            # Load the page and check reaction is added.
+            output = self.app.get('/test/issue/1')
+            self.assertEqual(output.status_code, 200)
+            self.assertIn(
+                'Thumbs down sent by pingou',
+                output.get_data(as_text=True)
+            )
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_add_reaction_unauthenticated(self, p_send_email, p_ugt):
+        '''
+        Test adding a reaction to an issue comment without authentication.
+        '''
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        self._set_up_for_reaction_test()
+
+        output = self.app.get('/test/issue/1')
+        self.assertEqual(output.status_code, 200)
+
+        data = {
+            'csrf_token': self.get_csrf(output=output),
+            'reaction': 'Thumbs down',
+        }
+
+        output = self.app.post(
+            '/test/issue/1/comment/1/react',
+            data=data,
+            follow_redirects=False,
+        )
+        # Redirect to login page
+        self.assertEqual(output.status_code, 302)
+        self.assertIn('/login/', output.headers['Location'])
+
+    @patch('pagure.lib.git.update_git')
+    @patch('pagure.lib.notify.send_email')
+    def test_add_reaction_private_issue(self, p_send_email, p_ugt):
+        '''Test adding a reaction to a private issue comment.'''
+        p_send_email.return_value = True
+        p_ugt.return_value = True
+
+        self._set_up_for_reaction_test(private=True)
+
+        user = tests.FakeUser()
+        user.username = 'naysayer'
+        with tests.user_set(self.app.application, user):
+            # Steal CSRF token from new issue page
+            output = self.app.get('/test/new_issue')
+
+            data = {
+                'csrf_token': self.get_csrf(output=output),
+                'reaction': 'Thumbs down',
+            }
+
+            output = self.app.post(
+                '/test/issue/1/comment/1/react',
+                data=data,
+                follow_redirects=True,
+            )
+            self.assertEqual(output.status_code, 404)
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/tests/test_pagure_lib_git.py b/tests/test_pagure_lib_git.py
index 82dffd0..09efc57 100644
--- a/tests/test_pagure_lib_git.py
+++ b/tests/test_pagure_lib_git.py
@@ -1687,7 +1687,7 @@ diff --git a/123 b/456
 index 458821a..77674a8
 --- a/123
 +++ b/456
-@@ -3,13 +3,31 @@
+@@ -3,13 +3,32 @@
      "blocks": [],
      "close_status": null,
      "closed_at": null,
@@ -1701,6 +1701,7 @@ index 458821a..77674a8
 +            "id": 1,
 +            "notification": false,
 +            "parent": null,
++            "reactions": {},
 +            "user": {
 +                "default_email": "foo@bar.com",
 +                "emails": [