diff --git a/api/Gemfile b/api/Gemfile
index c38971f1e..9f6428e75 100644
--- a/api/Gemfile
+++ b/api/Gemfile
@@ -19,6 +19,7 @@ gem 'mimemagic', '~> 0.3'
 gem 'octokit', '~> 4.7'
 gem 'paranoia', '~> 2.4'
 gem 'pdfkit', '~> 0.8.2'
+gem 'pundit', '~> 1.1'
 gem 'rack-cors', require: 'rack/cors'
 gem 'redcarpet', '~> 3.4.0'
 gem 'redis-rails', '~> 5.0.2'
diff --git a/api/Gemfile.lock b/api/Gemfile.lock
index f2e95fc95..ca371f1a5 100644
--- a/api/Gemfile.lock
+++ b/api/Gemfile.lock
@@ -158,6 +158,8 @@ GEM
       method_source (~> 0.9.0)
     public_suffix (3.0.1)
     puma (3.11.0)
+    pundit (1.1.0)
+      activesupport (>= 3.0.0)
     rack (2.0.3)
     rack-cors (1.0.2)
     rack-protection (2.0.0)
@@ -327,6 +329,7 @@ DEPENDENCIES
   pdfkit (~> 0.8.2)
   pg (~> 0.18.4)
   puma (~> 3.0)
+  pundit (~> 1.1)
   rack-cors
   rails (~> 5.1)
   redcarpet (~> 3.4.0)
diff --git a/api/app/controllers/application_controller.rb b/api/app/controllers/application_controller.rb
index 13c271fb6..156e6dde9 100644
--- a/api/app/controllers/application_controller.rb
+++ b/api/app/controllers/application_controller.rb
@@ -1,4 +1,5 @@
 # frozen_string_literal: true
 
+# See V1::ApiController for base controller of API V1.
 class ApplicationController < ActionController::API
 end
diff --git a/api/app/controllers/v1/api_controller.rb b/api/app/controllers/v1/api_controller.rb
index 2fd9c156e..0b20e0c19 100644
--- a/api/app/controllers/v1/api_controller.rb
+++ b/api/app/controllers/v1/api_controller.rb
@@ -2,6 +2,11 @@
 
 module V1
   class ApiController < ApplicationController
+    include Pundit
+
+    rescue_from Pundit::NotAuthorizedError, with: :render_access_denied
+    rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
+
     def render_success(obj = { success: true }, status = 200)
       render json: obj, status: status
     end
diff --git a/api/app/controllers/v1/concerns/user_auth.rb b/api/app/controllers/v1/concerns/user_auth.rb
index f0f70a9eb..e1d5063dd 100644
--- a/api/app/controllers/v1/concerns/user_auth.rb
+++ b/api/app/controllers/v1/concerns/user_auth.rb
@@ -28,6 +28,10 @@ def authenticate_user
     end
   end
 
+  def current_user
+    @user
+  end
+
   protected
 
   def render_unauthenticated
diff --git a/api/app/controllers/v1/leader_profiles_controller.rb b/api/app/controllers/v1/leader_profiles_controller.rb
index 50c10ff08..2c1f516f3 100644
--- a/api/app/controllers/v1/leader_profiles_controller.rb
+++ b/api/app/controllers/v1/leader_profiles_controller.rb
@@ -5,19 +5,15 @@ class LeaderProfilesController < ApiController
     include UserAuth
 
     def show
-      profile = LeaderProfile.find_by(id: params[:id])
-
-      return render_not_found unless profile
-      return render_access_denied if profile.user != @user
+      profile = LeaderProfile.find(params[:id])
+      authorize profile
 
       render_success(profile)
     end
 
     def update
-      profile = LeaderProfile.find_by(id: params[:id])
-
-      return render_not_found unless profile
-      return render_access_denied if profile.user != @user
+      profile = LeaderProfile.find(params[:id])
+      authorize profile
 
       if profile.submitted_at.present?
         return render_field_error(
diff --git a/api/app/controllers/v1/new_club_applications_controller.rb b/api/app/controllers/v1/new_club_applications_controller.rb
index 4872853b2..190e894b0 100644
--- a/api/app/controllers/v1/new_club_applications_controller.rb
+++ b/api/app/controllers/v1/new_club_applications_controller.rb
@@ -4,6 +4,13 @@ module V1
   class NewClubApplicationsController < ApiController
     include UserAuth
 
+    # All applications
+    def full_index
+      return render_access_denied unless @user.admin?
+      render_success NewClubApplication.all
+    end
+
+    # Applications for a specific user
     def index
       if params[:user_id] == @user.id.to_s
         render_success(@user.new_club_applications)
@@ -13,28 +20,21 @@ def index
     end
 
     def show
-      application = NewClubApplication.find_by(id: params[:id])
-
-      return render_not_found unless application
+      application = NewClubApplication.find(params[:id])
+      authorize application
 
-      if application.users.include? @user
-        render_success(application)
-      else
-        render_access_denied
-      end
+      render_success(application)
     end
 
     def create
-      c = NewClubApplication.create(users: [@user],
-                                    point_of_contact: @user)
+      c = NewClubApplication.create(users: [@user], point_of_contact: @user)
 
       render_success(c, 201)
     end
 
     def update
       c = NewClubApplication.find(params[:id])
-
-      return render_access_denied unless c.users.include? @user
+      authorize c
 
       if c.update_attributes(club_application_params)
         render_success(c)
@@ -44,10 +44,8 @@ def update
     end
 
     def add_user
-      app = NewClubApplication.find_by(id: params[:new_club_application_id])
-
-      return render_not_found unless app
-      return render_access_denied unless app.users.include? @user
+      app = NewClubApplication.find(params[:new_club_application_id])
+      authorize app
 
       if app.submitted_at.present?
         return render_field_error(:base, 'cannot edit application after submit')
@@ -73,14 +71,10 @@ def add_user
     end
 
     def remove_user
-      app = NewClubApplication.find_by(id: params[:new_club_application_id])
-      to_remove = User.find_by(id: params[:user_id])
-
-      return render_not_found unless app && to_remove
+      app = NewClubApplication.find(params[:new_club_application_id])
+      to_remove = User.find(params[:user_id])
 
-      return render_access_denied unless app.users.include? @user
-
-      return render_access_denied unless app.point_of_contact == @user
+      authorize app
 
       if app.submitted_at.present?
         return render_field_error(:base, 'cannot edit application after submit')
@@ -99,10 +93,8 @@ def remove_user
     end
 
     def submit
-      app = NewClubApplication.find_by(id: params[:new_club_application_id])
-
-      return render_not_found unless app
-      return render_access_denied unless app.users.include? @user
+      app = NewClubApplication.find(params[:new_club_application_id])
+      authorize app
 
       if app.submit!
         render_success(app)
diff --git a/api/app/models/user.rb b/api/app/models/user.rb
index d666615e4..a202dadd8 100644
--- a/api/app/models/user.rb
+++ b/api/app/models/user.rb
@@ -34,4 +34,16 @@ def generate_auth_token!
       break unless User.find_by(auth_token: auth_token)
     end
   end
+
+  def make_admin!
+    self.admin_at = Time.current
+  end
+
+  def remove_admin!
+    self.admin_at = nil
+  end
+
+  def admin?
+    admin_at.present?
+  end
 end
diff --git a/api/app/policies/application_policy.rb b/api/app/policies/application_policy.rb
new file mode 100644
index 000000000..c1f09aae9
--- /dev/null
+++ b/api/app/policies/application_policy.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+class ApplicationPolicy
+  attr_reader :user, :record
+
+  def initialize(user, record)
+    @user = user
+    @record = record
+  end
+
+  def index?
+    false
+  end
+
+  def show?
+    scope.where(id: record.id).exists?
+  end
+
+  def create?
+    false
+  end
+
+  def new?
+    create?
+  end
+
+  def update?
+    false
+  end
+
+  def edit?
+    update?
+  end
+
+  def destroy?
+    false
+  end
+
+  def scope
+    Pundit.policy_scope!(user, record.class)
+  end
+
+  class Scope
+    attr_reader :user, :scope
+
+    def initialize(user, scope)
+      @user = user
+      @scope = scope
+    end
+
+    def resolve
+      scope
+    end
+  end
+end
diff --git a/api/app/policies/leader_profile_policy.rb b/api/app/policies/leader_profile_policy.rb
new file mode 100644
index 000000000..9a4f0464c
--- /dev/null
+++ b/api/app/policies/leader_profile_policy.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class LeaderProfilePolicy < ApplicationPolicy
+  def show?
+    owns_profile?
+  end
+
+  def update?
+    owns_profile?
+  end
+
+  private
+
+  def owns_profile?
+    record.user == user
+  end
+end
diff --git a/api/app/policies/new_club_application_policy.rb b/api/app/policies/new_club_application_policy.rb
new file mode 100644
index 000000000..f06032167
--- /dev/null
+++ b/api/app/policies/new_club_application_policy.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class NewClubApplicationPolicy < ApplicationPolicy
+  def show?
+    user_added?
+  end
+
+  def update?
+    user_added?
+  end
+
+  def add_user?
+    user_added?
+  end
+
+  def remove_user?
+    user_added? && record.point_of_contact == user
+  end
+
+  def submit?
+    user_added?
+  end
+
+  private
+
+  def user_added?
+    record.users.include? user
+  end
+end
diff --git a/api/config/routes.rb b/api/config/routes.rb
index 1a381787b..6a4a6c2f1 100644
--- a/api/config/routes.rb
+++ b/api/config/routes.rb
@@ -18,6 +18,8 @@
     resources :donations, only: [:create]
 
     resources :club_applications, only: [:create]
+
+    get '/new_club_applications', to: 'new_club_applications#full_index'
     resources :new_club_applications, only: %i[show update] do
       post 'add_user'
       delete 'remove_user'
diff --git a/api/db/migrate/20180127102450_add_admin_at_to_user.rb b/api/db/migrate/20180127102450_add_admin_at_to_user.rb
new file mode 100644
index 000000000..42c9a13a8
--- /dev/null
+++ b/api/db/migrate/20180127102450_add_admin_at_to_user.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddAdminAtToUser < ActiveRecord::Migration[5.1]
+  def change
+    add_column :users, :admin_at, :datetime
+  end
+end
diff --git a/api/db/schema.rb b/api/db/schema.rb
index b2a3a076a..95cf699d5 100644
--- a/api/db/schema.rb
+++ b/api/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20180127084614) do
+ActiveRecord::Schema.define(version: 20180127102450) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -341,6 +341,7 @@
     t.datetime "auth_token_generation"
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
+    t.datetime "admin_at"
   end
 
   add_foreign_key "athul_clubs", "clubs"
diff --git a/api/spec/models/user_spec.rb b/api/spec/models/user_spec.rb
index 2d5a84dc9..448d39b55 100644
--- a/api/spec/models/user_spec.rb
+++ b/api/spec/models/user_spec.rb
@@ -7,7 +7,10 @@
 
   it { should have_db_column :email }
   it { should have_db_column :login_code }
+  it { should have_db_column :login_code_generation }
   it { should have_db_column :auth_token }
+  it { should have_db_column :auth_token_generation }
+  it { should have_db_column :admin_at }
 
   it { should validate_presence_of :email }
   it { should validate_email_format_of :email }
@@ -57,4 +60,24 @@
     # changes every time
     expect { subject.generate_auth_token! }.to change { subject.auth_token }
   end
+
+  example ':make_admin!' do
+    subject.admin_at = nil
+
+    subject.make_admin!
+
+    expect(subject.admin_at).to be_within(1.second).of(Time.current)
+    expect(subject.admin?).to eq(true)
+  end
+
+  example ':remove_admin!' do
+    subject.admin_at = nil
+
+    subject.make_admin!
+    expect(subject.admin?).to eq(true)
+
+    subject.remove_admin!
+    expect(subject.admin_at).to eq(nil)
+    expect(subject.admin?).to eq(false)
+  end
 end
diff --git a/api/spec/requests/v1/new_club_applications_spec.rb b/api/spec/requests/v1/new_club_applications_spec.rb
index ca192979d..545467f0c 100644
--- a/api/spec/requests/v1/new_club_applications_spec.rb
+++ b/api/spec/requests/v1/new_club_applications_spec.rb
@@ -6,6 +6,33 @@
   let(:user) { create(:user_authed) }
   let(:auth_headers) { { 'Authorization': "Bearer #{user.auth_token}" } }
 
+  describe 'GET /v1/new_club_applications' do
+    it 'requires authentication' do
+      get '/v1/new_club_applications'
+      expect(response.status).to eq(401)
+    end
+
+    it 'requires admin access' do
+      get '/v1/new_club_applications', headers: auth_headers
+      expect(response.status).to eq(403)
+    end
+
+    it 'lists all applications' do
+      my_app = create(:new_club_application)
+      my_app.users << user
+
+      create(:new_club_application) # someone else's application
+
+      # make user an admin
+      user.make_admin! && user.save
+
+      get '/v1/new_club_applications', headers: auth_headers
+      expect(response.status).to eq(200)
+
+      expect(json.length).to eq(2)
+    end
+  end
+
   describe 'GET /v1/users/:id/new_club_applications' do
     it 'requires authentication' do
       get "/v1/users/#{user.id}/new_club_applications"