diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 6df2ecf57a298d823000ccd3cc0013a79af962b0..1cd2302111ed9a10750c80a7ef12e64a40c6f551 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -16,9 +16,6 @@
         .replace(':id', group_id);
       return $.ajax({
         url: url,
-        data: {
-          private_token: gon.api_token
-        },
         dataType: "json"
       }).done(function(group) {
         return callback(group);
@@ -31,7 +28,6 @@
       return $.ajax({
         url: url,
         data: {
-          private_token: gon.api_token,
           search: query,
           per_page: 20
         },
@@ -46,7 +42,6 @@
       return $.ajax({
         url: url,
         data: {
-          private_token: gon.api_token,
           search: query,
           per_page: 20
         },
@@ -61,7 +56,6 @@
       return $.ajax({
         url: url,
         data: {
-          private_token: gon.api_token,
           search: query,
           order_by: order,
           per_page: 20
@@ -74,7 +68,6 @@
     newLabel: function(project_id, data, callback) {
       var url = Api.buildUrl(Api.labelsPath)
         .replace(':id', project_id);
-      data.private_token = gon.api_token;
       return $.ajax({
         url: url,
         type: "POST",
@@ -93,7 +86,6 @@
       return $.ajax({
         url: url,
         data: {
-          private_token: gon.api_token,
           search: query,
           per_page: 20
         },
diff --git a/doc/api/README.md b/doc/api/README.md
index 7661e1eea028b0db1591d410647caeb1637ba0ce..6e3295e0e0c413e2118299e6907a30e24101955f 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -55,11 +55,12 @@ The following documentation is for the [internal CI API](ci/README.md):
 
 ## Authentication
 
-All API requests require authentication via a token. There are three types of tokens
-available: private tokens, OAuth 2 tokens, and personal access tokens.
+All API requests require authentication via a session cookie or token. There are
+three types of tokens available: private tokens, OAuth 2 tokens, and personal
+access tokens.
 
-If a token is invalid or omitted, an error message will be returned with
-status code `401`:
+If authentication information is invalid or omitted, an error message will be
+returned with status code `401`:
 
 ```json
 {
@@ -98,6 +99,13 @@ that needs access to the GitLab API.
 Once you have your token, pass it to the API using either the `private_token`
 parameter or the `PRIVATE-TOKEN` header.
 
+
+### Session cookie
+
+When signing in to GitLab as an ordinary user, a `_gitlab_session` cookie is
+set. The API will use this cookie for authentication if it is present, but using
+the API to generate a new session cookie is currently not supported.
+
 ## Basic Usage
 
 API requests should be prefixed with `api` and the API version. The API version
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index 7e67edb203ac73243a45a4f3e0eed0d583a10e6c..8cc7a26f1fa71249e79d28f71308a5fdc097a251 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -33,46 +33,29 @@ module API
       #
       # If the token is revoked, then it raises RevokedError.
       #
-      # If the token is not found (nil), then it raises TokenNotFoundError.
+      # If the token is not found (nil), then it returns nil
       #
       # Arguments:
       #
       #   scopes: (optional) scopes required for this guard.
       #           Defaults to empty array.
       #
-      def doorkeeper_guard!(scopes: [])
-        if (access_token = find_access_token).nil?
-          raise TokenNotFoundError
-
-        else
-          case validate_access_token(access_token, scopes)
-          when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE
-            raise InsufficientScopeError.new(scopes)
-          when Oauth2::AccessTokenValidationService::EXPIRED
-            raise ExpiredError
-          when Oauth2::AccessTokenValidationService::REVOKED
-            raise RevokedError
-          when Oauth2::AccessTokenValidationService::VALID
-            @current_user = User.find(access_token.resource_owner_id)
-          end
-        end
-      end
-
       def doorkeeper_guard(scopes: [])
-        if access_token = find_access_token
-          case validate_access_token(access_token, scopes)
-          when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE
-            raise InsufficientScopeError.new(scopes)
+        access_token = find_access_token
+        return nil unless access_token
+
+        case validate_access_token(access_token, scopes)
+        when Oauth2::AccessTokenValidationService::INSUFFICIENT_SCOPE
+          raise InsufficientScopeError.new(scopes)
 
-          when Oauth2::AccessTokenValidationService::EXPIRED
-            raise ExpiredError
+        when Oauth2::AccessTokenValidationService::EXPIRED
+          raise ExpiredError
 
-          when Oauth2::AccessTokenValidationService::REVOKED
-            raise RevokedError
+        when Oauth2::AccessTokenValidationService::REVOKED
+          raise RevokedError
 
-          when Oauth2::AccessTokenValidationService::VALID
-            @current_user = User.find(access_token.resource_owner_id)
-          end
+        when Oauth2::AccessTokenValidationService::VALID
+          @current_user = User.find(access_token.resource_owner_id)
         end
       end
 
@@ -96,19 +79,6 @@ module API
     end
 
     module ClassMethods
-      # Installs the doorkeeper guard on the whole Grape API endpoint.
-      #
-      # Arguments:
-      #
-      #   scopes: (optional) scopes required for this guard.
-      #           Defaults to empty array.
-      #
-      def guard_all!(scopes: [])
-        before do
-          guard! scopes: scopes
-        end
-      end
-
       private
 
       def install_error_responders(base)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 150875ed4f083a790de485eebbccb46a59e3479e..714d4ea3dc642f5a64ff7062e11f3d01fd792b42 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -12,13 +12,30 @@ module API
       nil
     end
 
+    def private_token
+      params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]
+    end
+
+    def warden
+      env['warden']
+    end
+
+    # Check the Rails session for valid authentication details
+    def find_user_from_warden
+      warden ? warden.authenticate : nil
+    end
+
     def find_user_by_private_token
-      token_string = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s
-      User.find_by_authentication_token(token_string) || User.find_by_personal_access_token(token_string)
+      token = private_token
+      return nil unless token.present?
+
+      User.find_by_authentication_token(token) || User.find_by_personal_access_token(token)
     end
 
     def current_user
-      @current_user ||= (find_user_by_private_token || doorkeeper_guard)
+      @current_user ||= find_user_by_private_token
+      @current_user ||= doorkeeper_guard
+      @current_user ||= find_user_from_warden
 
       unless @current_user && Gitlab::UserAccess.new(@current_user).allowed?
         return nil
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index c5a11148d33f7c5dae8fa1c8b5811b91a177b9b7..2c21804fe7a6328b2f1d027b0dcacc918119d753 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -11,7 +11,6 @@ module Gitlab
 
       if current_user
         gon.current_user_id = current_user.id
-        gon.api_token = current_user.private_token
       end
     end
   end
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb
index bbdf8f03c2bc3578aec1c547d57853677ca2ed55..e66faeed705dbdfba330b74729e783cdf436785d 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/api_helpers_spec.rb
@@ -36,11 +36,36 @@ describe API::Helpers, api: true do
     params.delete(API::Helpers::SUDO_PARAM)
   end
 
+  def warden_authenticate_returns(value)
+    warden = double("warden", authenticate: value)
+    env['warden'] = warden
+  end
+
+  def doorkeeper_guard_returns(value)
+    allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ value }
+  end
+
   def error!(message, status)
     raise Exception
   end
 
   describe ".current_user" do
+    subject { current_user }
+
+    describe "when authenticating via Warden" do
+      before { doorkeeper_guard_returns false }
+
+      context "fails" do
+        it { is_expected.to be_nil }
+      end
+
+      context "succeeds" do
+        before { warden_authenticate_returns user }
+
+        it { is_expected.to eq(user) }
+      end
+    end
+
     describe "when authenticating using a user's private token" do
       it "returns nil for an invalid token" do
         env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'