diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 01f984796235efac8a47d189b746e9a16ee1712b..5a4d0a5c8b048f266c460081d6e24dc09f81c18f 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -205,3 +205,6 @@
     text-align: center;
   }
 }
+.personal-access-tokens-revoked-label {
+  color: #bbb;
+}
\ No newline at end of file
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index dbf06cb4c6d87c1adfafe6f2c4a2d3f429f0a68a..59de0b26eeee2634536165c30f1fb179ccd0bb62 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -1,7 +1,11 @@
 class Profiles::PersonalAccessTokensController < ApplicationController
   def index
     @user = current_user
-    @personal_access_token = current_user.personal_access_tokens.new
+
+    # Prefer this to `@user.personal_access_tokens.new`, because it
+    # litters the view's call to `@user.personal_access_tokens` with
+    # this stub personal access token.
+    @personal_access_token = PersonalAccessToken.new(user: @user)
   end
 
   def create
@@ -14,6 +18,16 @@ class Profiles::PersonalAccessTokensController < ApplicationController
     end
   end
 
+  def revoke
+    @personal_access_token = current_user.personal_access_tokens.find(params[:id])
+
+    if @personal_access_token.revoke!
+      redirect_to profile_personal_access_tokens_path, notice: "Revoked personal access token #{@personal_access_token.name}!"
+    else
+      render :index
+    end
+  end
+
   private
 
   def personal_access_token_params
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index 29f2275475f31d7f903b3b59a92c18ec535f78c3..e5f1f9749f8c89851e9c10ad5a99b2517d2b093a 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -1,9 +1,16 @@
 class PersonalAccessToken < ActiveRecord::Base
   belongs_to :user
 
+  scope :active, -> { where.not(revoked: true) }
+
   def self.generate(params)
     personal_access_token = self.new(params)
     personal_access_token.token = Devise.friendly_token(50)
     personal_access_token
   end
+
+  def revoke!
+    self.revoked = true
+    self.save
+  end
 end
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 05eed3c5c3ca897f9105ec59b0c4f53653838bab..02d15269c850739ddd8228c7092ea06bbfaa85f7 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -34,11 +34,18 @@
               %th Name
               %th Token
               %th Created At
+              %th Actions
           %tbody
-            - @user.personal_access_tokens.each do |token|
+            - @user.personal_access_tokens.order(:revoked).each do |token|
               %tr
                 %td= token.name
                 %td= token.token
                 %td= token.created_at
+                - if token.revoked?
+                  %td
+                    %span.personal-access-tokens-revoked-label Revoked
+                - else
+                  %td= link_to "Revoke", revoke_profile_personal_access_token_path(token), method: :put, class: "btn btn-danger", data: {confirm: t('profile.personal_access_tokens.revoke.confirmation')}
+
     - else
       %span You don't have any tokens yet.
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index cedb5e207bd3798f0ff2a8e6651937ba368d2b8a..b5b8c4467b04dccf65fd7b86065242975229f2e1 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -12,3 +12,7 @@ en:
     pagination:
       previous: "Prev"
       next: "Next"
+  profile:
+    personal_access_tokens:
+      revoke:
+        confirmation: "Are you sure? This cannot be undone."
diff --git a/config/routes.rb b/config/routes.rb
index d1be826d2a15b429c7c661bcb9a68d6725ad458d..4e4666762f8af23d9e51c8698d724001d5e35272 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -333,7 +333,11 @@ Rails.application.routes.draw do
       resources :keys
       resources :emails, only: [:index, :create, :destroy]
       resource :avatar, only: [:destroy]
-      resources :personal_access_tokens, only: [:index, :create]
+      resources :personal_access_tokens, only: [:index, :create] do
+        member do
+          put :revoke
+        end
+      end
       resource :two_factor_auth, only: [:new, :create, :destroy] do
         member do
           post :codes
diff --git a/db/migrate/20160415144643_add_column_revoked_to_personal_access_tokens.rb b/db/migrate/20160415144643_add_column_revoked_to_personal_access_tokens.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8eecdfc5a1c9aa7d43a486bd0b87c53b420d19cb
--- /dev/null
+++ b/db/migrate/20160415144643_add_column_revoked_to_personal_access_tokens.rb
@@ -0,0 +1,5 @@
+class AddColumnRevokedToPersonalAccessTokens < ActiveRecord::Migration
+  def change
+    add_column :personal_access_tokens, :revoked, :boolean, default: false
+  end
+end
diff --git a/lib/api/helpers/authentication.rb b/lib/api/helpers/authentication.rb
index e1d7ac83ff6f87df2aac0eab7e712eafc66647f7..666bf3ffa169bad2f51bffb98df688a33fb6ad16 100644
--- a/lib/api/helpers/authentication.rb
+++ b/lib/api/helpers/authentication.rb
@@ -15,7 +15,7 @@ module API
 
       def find_user_by_personal_access_token
         personal_access_token_string = (params[PERSONAL_ACCESS_TOKEN_PARAM] || env[PERSONAL_ACCESS_TOKEN_HEADER]).to_s
-        personal_access_token = PersonalAccessToken.find_by_token(personal_access_token_string)
+        personal_access_token = PersonalAccessToken.active.find_by_token(personal_access_token_string)
         personal_access_token.user if personal_access_token
       end