diff --git a/app/corpora/routes.py b/app/corpora/routes.py
index 5446f1449567b2402fe15b981db295d8e84d4c75..92664d4358d31d0f11c83cdc40b127ab20061c9c 100644
--- a/app/corpora/routes.py
+++ b/app/corpora/routes.py
@@ -66,15 +66,11 @@ def disable_corpus_is_public(corpus_id):
 @bp.route('/<hashid:corpus_id>/follow/<token>')
 @login_required
 def follow_corpus(corpus_id, token):
-    corpus = current_user.verify_follow_corpus_token(token)['corpus']
-    role = current_user.verify_follow_corpus_token(token)['role']
-    if not (current_user.is_authenticated and current_user.verify_follow_corpus_token(token)):
-        abort(403)
-    if not current_user.is_following_corpus(corpus) and current_user != corpus.user:
-        current_user.follow_corpus(corpus, role)
+    if current_user.follow_corpus_by_token(token):
         db.session.commit()
         flash(f'You are following {corpus.title} now', category='corpus')
-    return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
+        return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
+    abort(403)    
 
 
 @bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>/unfollow', methods=['POST'])
@@ -174,12 +170,14 @@ def corpus(corpus_id):
             title='Corpus'
         )
     if current_user.is_following_corpus(corpus) or corpus.is_public:
+        cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first_or_404()
         corpus_files = [x.to_json_serializeable() for x in corpus.files]
         owner = corpus.user.to_json_serializeable()
         return render_template(
             'corpora/public_corpus.html.j2',
             corpus=corpus,
             corpus_files=corpus_files,
+            cfa=cfa,
             owner=owner,
             title='Corpus',
         )
diff --git a/app/models.py b/app/models.py
index d363c0bb5757fb7a8e64b889d67fb21edf64f994..de995a5c36106852c79278232affe8161b66886c 100644
--- a/app/models.py
+++ b/app/models.py
@@ -792,14 +792,15 @@ class User(HashidMixin, UserMixin, db.Model):
     def is_following_corpus(self, corpus):
         return corpus in self.followed_corpora
     
-    def generate_follow_corpus_token(self, corpus_id, role, expiration=7):
+    def generate_follow_corpus_token(self, corpus_hashid, role_name, expiration=7):
         now = datetime.utcnow()
         payload = {
             'exp': expiration,
             'iat': now,
             'iss': current_app.config['SERVER_NAME'],
-            'sub': corpus_id,
-            'role': role
+            'purpose': 'User.follow_corpus',
+            'role_name': role_name,
+            'sub': corpus_hashid
         }
         return jwt.encode(
             payload,
@@ -807,23 +808,31 @@ class User(HashidMixin, UserMixin, db.Model):
             algorithm='HS256'
         )
     
-    def verify_follow_corpus_token(self, token):
+    def follow_corpus_by_token(self, token):
         try:
             payload = jwt.decode(
                 token,
                 current_app.config['SECRET_KEY'],
                 algorithms=['HS256'],
                 issuer=current_app.config['SERVER_NAME'],
-                options={'require': ['exp', 'iat', 'iss', 'sub']}
+                options={'require': ['exp', 'iat', 'iss', 'purpose', 'role_name', 'sub']}
             )
         except jwt.PyJWTError:
             return False
-        corpus_id = payload.get('sub')
+        if payload.get('purpose') != 'User.follow_corpus':
+            return False
+        corpus_hashid = payload.get('sub')
+        corpus_id = hashids.decode(corpus_hashid)
         corpus = Corpus.query.get_or_404(corpus_id)
-        role = CorpusFollowerRole.query.filter_by(name=payload.get('role')).first()
         if corpus is None:
             return False
-        return {'corpus': corpus, 'role': role}
+        role_name = payload.get('role_name')
+        role = CorpusFollowerRole.query.filter_by(name=role_name).first()
+        if role is None:
+            return False
+        self.follow_corpus(corpus, role)
+        db.session.add(self)
+        return True
 
     def to_json_serializeable(self, backrefs=False, relationships=False, filter_by_privacy_settings=False):
         json_serializeable = {