diff --git a/lib/auth/types/AuthType.js b/lib/auth/types/AuthType.js
index 912a4cdf4b80898bd4b9c2929cd321b5717aa4fb..6fdc8bc52f403e46b41f9c001ed01f5def39061f 100644
--- a/lib/auth/types/AuthType.js
+++ b/lib/auth/types/AuthType.js
@@ -18,6 +18,7 @@ import { assign } from 'lodash';
 import Boom from 'boom';
 import InvalidSessionError from "../errors/invalid_session_error";
 import SessionExpiredError from "../errors/session_expired_error";
+import filterAuthHeaders from '../filter_auth_headers';
 
 export default class AuthType {
 
@@ -56,6 +57,13 @@ export default class AuthType {
          */
         this.authHeaderName = 'authorization';
 
+        /**
+         * Additional headers that should be passed as part as the authentication.
+         * Do not use headers here that have an effect on which user is logged in.
+         * @type {string[]}
+         */
+        this.allowedAdditionalAuthHeaders = ['sg_impersonate_as'];
+
         /**
          * This is a workaround for keeping track of what caused hapi-auth-cookie's validateFunc to fail.
          * There seems to be an issue with how the plugin checks the thrown error and instead of passing
@@ -81,6 +89,7 @@ export default class AuthType {
             options: {
                 authType: this.type,
                 authHeaderName: this.authHeaderName,
+                allowedAdditionalAuthHeaders: this.allowedAdditionalAuthHeaders,
                 authenticateFunction: this.authenticate.bind(this),
                 validateAvailableTenants: this.validateAvailableTenants
             }
@@ -149,7 +158,7 @@ export default class AuthType {
         return null;
     }
 
-    authenticate(credentials) {
+    authenticate(credentials, options = {}, additionalAuthHeaders = {}) {
         throw new Error('The authenticate method must be implemented by the sub class');
     }
 
@@ -269,6 +278,12 @@ export default class AuthType {
                 }
             }
 
+            // Make sure we don't have any conflicting auth headers
+            if (! this.validateAdditionalAuthHeaders(request, session)) {
+                request.auth.sgSessionStorage.clearStorage();
+                return {valid: false};
+            }
+
             // If we are still here, we need to compare the expiration time
             // JWT's .exp is denoted in seconds, not milliseconds.
             if (session.exp && session.exp < Math.floor(Date.now() / 1000)) {
@@ -300,6 +315,36 @@ export default class AuthType {
         return validate;
     }
 
+    /**
+     * Validates
+     * @param request
+     * @param session
+     * @returns {boolean}
+     */
+    validateAdditionalAuthHeaders(request, session) {
+
+        // Check if the request has any of the headers that can be used on authentication
+        const authHeadersInRequest = filterAuthHeaders(request.headers, this.allowedAdditionalAuthHeaders);
+
+        if (Object.keys(authHeadersInRequest).length === 0) {
+            return true;
+        }
+
+        // If we have applicable headers in the request, but not in the session, the validation fails
+        if (! session.additionalAuthHeaders) {
+            return false;
+        }
+
+        // If the request has a conflicting auth header we log out the user
+        for (const header in session.additionalAuthHeaders) {
+            if (session.additionalAuthHeaders[header] !== authHeadersInRequest[header]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     /**
      * Add credential headers to the passed request.
      * @param request
@@ -329,7 +374,7 @@ export default class AuthType {
                 try {
                     let authHeader = this.getAuthHeader(session);
                     if (authHeader !== false) {
-                        this.addAdditionalAuthHeaders(request, authHeader);
+                        this.addAdditionalAuthHeaders(request, authHeader, session);
                         assign(request.headers, authHeader);
                     }
                 } catch (error) {
@@ -361,10 +406,18 @@ export default class AuthType {
     /**
      * Method for adding additional auth type specific authentication headers.
      * Override this in the auth type for type specific headers.
+     *
+     * NB: Remember to call the super method if you do.
+     *
      * @param request
      * @param authHeader
+     * @param session
      */
-    addAdditionalAuthHeaders(request, authHeader) {
-
+    addAdditionalAuthHeaders(request, authHeader, session) {
+        if (session.additionalAuthHeaders) {
+            for (let header in session.additionalAuthHeaders) {
+                authHeader[header] = session.additionalAuthHeaders[header];
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/lib/auth/types/basicauth/BasicAuth.js b/lib/auth/types/basicauth/BasicAuth.js
index 3ddb9160871ec6e5ec56b27a1b7fbbf1839b77ce..98693e586b1c632c4b82ca062d0838f661afd731 100644
--- a/lib/auth/types/basicauth/BasicAuth.js
+++ b/lib/auth/types/basicauth/BasicAuth.js
@@ -39,7 +39,7 @@ export default class BasicAuth extends AuthType {
          * @type {boolean}
          */
         this.loadBalancerURL = this.config.get('searchguard.basicauth.loadbalancer_url');
-         
+
         /**
          * Allow anonymous access?
          * @type {boolean}
@@ -84,12 +84,12 @@ export default class BasicAuth extends AuthType {
         return null;
     }
 
-    async authenticate(credentials, options = {}) {
+    async authenticate(credentials, options = {}, additionalAuthHeaders = {}) {
 
         // A login can happen via a POST request (login form) or when we have request headers with user credentials.
         // We also need to re-authenticate if the credentials (headers) don't match what's in the session.
         try {
-            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue);
+            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue, additionalAuthHeaders);
             let session = {
                 username: user.username,
                 credentials: credentials,
diff --git a/lib/auth/types/jwt/Jwt.js b/lib/auth/types/jwt/Jwt.js
index 69b2987cb33dc71e03bec13fa1021a26b0938702..6b4ed44014a6a73b252cdc110394dd99eb46094c 100644
--- a/lib/auth/types/jwt/Jwt.js
+++ b/lib/auth/types/jwt/Jwt.js
@@ -88,11 +88,11 @@ export default class Jwt extends AuthType {
         return authHeaderValue;
     }
 
-    async authenticate(credentials) {
+    async authenticate(credentials, options = {}, additionalAuthHeaders = {}) {
         // A "login" can happen when we have a token (as header or as URL parameter but no session,
         // or when we have an existing session, but the passed token does not match what's in the session.
         try {
-            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue);
+            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue, additionalAuthHeaders);
             let tokenPayload = {};
             try {
                 tokenPayload = JSON.parse(Buffer.from(credentials.authHeaderValue.split('.')[1], 'base64').toString());
diff --git a/lib/auth/types/openid/OpenId.js b/lib/auth/types/openid/OpenId.js
index bd5aab947da16e32e8238fc8c28f1e459c1811ed..9dad981885cbf1a47bc49e599860a61af4d4fe76 100644
--- a/lib/auth/types/openid/OpenId.js
+++ b/lib/auth/types/openid/OpenId.js
@@ -58,12 +58,12 @@ export default class OpenId extends AuthType {
         }
     }
 
-    async authenticate(credentials)  {
+    async authenticate(credentials, options = {}, additionalAuthHeaders = {})  {
         // A "login" can happen when we have a token (as header or as URL parameter but no session,
         // or when we have an existing session, but the passed token does not match what's in the session.
         try {
 
-            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue);
+            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue, additionalAuthHeaders);
             let tokenPayload = {};
             try {
                 tokenPayload = JSON.parse(Buffer.from(credentials.authHeaderValue.split('.')[1], 'base64').toString());
diff --git a/lib/auth/types/proxycache/ProxyCache.js b/lib/auth/types/proxycache/ProxyCache.js
index de90e777b62d51cc9e67bfc9e57bffa54b6117dc..24c1a00b87a76bea6dc75182f12235715a974d0c 100644
--- a/lib/auth/types/proxycache/ProxyCache.js
+++ b/lib/auth/types/proxycache/ProxyCache.js
@@ -105,9 +105,9 @@ export default class ProxyCache extends AuthType {
         return false;
     }
 
-    async authenticate(credentialHeaders) {
+    async authenticate(credentialHeaders, options = {}, additionalAuthHeaders = {}) {
         try {
-            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeaders(credentialHeaders, credentialHeaders);
+            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeaders(credentialHeaders, credentialHeaders, additionalAuthHeaders);
 
             let session = {
                 username: user.username,
@@ -158,7 +158,9 @@ export default class ProxyCache extends AuthType {
         require('./routes')(this.pluginRoot, this.server, this.kbnServer, this.APP_ROOT, this.API_ROOT);
     }
 
-    addAdditionalAuthHeaders(request, authHeader) {
+    addAdditionalAuthHeaders(request, authHeader, session) {
+        super.addAdditionalAuthHeaders(request, authHeader, session);
+
         // for proxy cache mode, make it possible to assign the proxy ip,
         // usually as x-forwarded-for header. Only if no headers are already present
         let existingProxyHeaders = request.headers[this.config.get('searchguard.proxycache.proxy_header')];
diff --git a/lib/auth/types/saml/Saml.js b/lib/auth/types/saml/Saml.js
index 62db8a589714caeb4bb3484a4dd2af5b53003a7b..5eb08c6aa8e0fa482c8abcd91e7b807f1f25a224 100644
--- a/lib/auth/types/saml/Saml.js
+++ b/lib/auth/types/saml/Saml.js
@@ -32,12 +32,12 @@ export default class Saml extends AuthType {
         this.type = 'saml';
     }
 
-    async authenticate(credentials)  {
+    async authenticate(credentials, options = {}, additionalAuthHeaders = {})  {
         // A "login" can happen when we have a token (as header or as URL parameter but no session,
         // or when we have an existing session, but the passed token does not match what's in the session.
         try {
 
-            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue);
+            let user = await this.server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeader(this.authHeaderName, credentials.authHeaderValue, additionalAuthHeaders);
 
             let tokenPayload = {};
             try {
diff --git a/lib/backend/searchguard.js b/lib/backend/searchguard.js
index 13cf38aaccd82486fb0227b29a824c50cfd3012f..269f5543d673eb88c77fc1e25ff16a08e87393dd 100644
--- a/lib/backend/searchguard.js
+++ b/lib/backend/searchguard.js
@@ -57,7 +57,7 @@ export default class SearchGuardBackend {
         }
     }
 
-    async authenticateWithHeader(headerName, headerValue) {
+    async authenticateWithHeader(headerName, headerValue, additionalAuthHeaders = {}) {
 
         try {
             const credentials = {
@@ -65,7 +65,7 @@ export default class SearchGuardBackend {
                 headerValue: headerValue
             };
 
-            let headers = {};
+            let headers = filterAuthHeaders(additionalAuthHeaders, this._esconfig.requestHeadersWhitelist);
 
             // For anonymous auth, we wouldn't have any value here
             if (headerValue) {
@@ -93,7 +93,11 @@ export default class SearchGuardBackend {
      * @param credentials
      * @returns {Promise<User>}
      */
-    async authenticateWithHeaders(headers, credentials = {}) {
+    async authenticateWithHeaders(headers, credentials = {}, additionalAuthHeaders = {}) {
+        headers = {
+            ...filterAuthHeaders(additionalAuthHeaders, this._esconfig.requestHeadersWhitelist),
+            ...headers,
+        };
 
         try {
             const response = await this._client.searchguard.authinfo({
diff --git a/lib/session/sessionPlugin.js b/lib/session/sessionPlugin.js
index 46b5a9c57ba686bd119e6da2d395ebcbb0231415..f38f994909313a6de0bf46c032babaa89e8f7eaa 100755
--- a/lib/session/sessionPlugin.js
+++ b/lib/session/sessionPlugin.js
@@ -1,8 +1,9 @@
 import MissingTenantError from "../auth/errors/missing_tenant_error";
 import MissingRoleError from "../auth/errors/missing_role_error";
+import filterAuthHeaders from '../auth/filter_auth_headers';
 
-var Hoek = require('hoek');
-var Joi = require('joi');
+const Hoek = require('hoek');
+const Joi = require('joi');
 
 /**
  * Name of the cookie where we store additional session information, such as authInfo
@@ -15,6 +16,7 @@ let internals = {};
 internals.config = Joi.object({
     authType: Joi.string().allow(null),
     authHeaderName: Joi.string(),
+    allowedAdditionalAuthHeaders: Joi.array().default([]),
     authenticateFunction: Joi.func(),
     validateAvailableTenants: Joi.boolean().default(true),
     validateAvailableRoles: Joi.boolean().default(true)
@@ -38,10 +40,11 @@ const register = function (server, options) {
              */
             authenticate: async function (credentials, options = {}) {
                 try {
+                    const additionalAuthHeaders = filterAuthHeaders(request.headers, settings.allowedAdditionalAuthHeaders);
                     // authResponse is an object with .session and .user
-                    const authResponse = await settings.authenticateFunction(credentials, options);
+                    const authResponse = await settings.authenticateFunction(credentials, options, additionalAuthHeaders);
 
-                    return this._handleAuthResponse(credentials, authResponse);
+                    return this._handleAuthResponse(credentials, authResponse, additionalAuthHeaders);
                 } catch (error) {
                     // Make sure we clear any existing cookies if something went wrong
                     this.clear();
@@ -50,10 +53,10 @@ const register = function (server, options) {
 
             },
 
-
             authenticateWithHeaders: async function (headers, credentials = {}, options = {}) {
                 try {
-                    let user = await server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeaders(headers);
+                    const additionalAuthHeaders = filterAuthHeaders(request.headers, settings.allowedAdditionalAuthHeaders);
+                    let user = await server.plugins.searchguard.getSearchGuardBackend().authenticateWithHeaders(headers, credentials, additionalAuthHeaders);
                     let session = {
                         username: user.username,
                         credentials: credentials,
@@ -75,7 +78,7 @@ const register = function (server, options) {
                         user
                     };
 
-                    return this._handleAuthResponse(credentials, authResponse)
+                    return this._handleAuthResponse(credentials, authResponse, additionalAuthHeaders)
                 } catch (error) {
                     // Make sure we clear any existing cookies if something went wrong
                     this.clear();
@@ -90,7 +93,7 @@ const register = function (server, options) {
              * @returns {*}
              * @private
              */
-            _handleAuthResponse: function (credentials, authResponse) {
+            _handleAuthResponse: function (credentials, authResponse, additionalAuthHeaders = {}) {
                 // Make sure the user has a tenant that they can use
                 if (settings.validateAvailableTenants && server.config().get("searchguard.multitenancy.enabled") && !server.config().get("searchguard.multitenancy.tenants.enable_global")) {
                     let privateTenantEnabled = server.config().get("searchguard.multitenancy.tenants.enable_private");
@@ -110,6 +113,12 @@ const register = function (server, options) {
                     throw new MissingRoleError('No roles available for this user, please contact your system administrator.');
                 }
 
+                // If we used any additional auth headers when authenticating, we need to store them in the session
+                authResponse.session.additionalAuthHeaders = null;
+                if (Object.keys(additionalAuthHeaders).length) {
+                    authResponse.session.additionalAuthHeaders = additionalAuthHeaders;
+                }
+
                 request.cookieAuth.set(authResponse.session);
                 this.setAuthInfo(authResponse.user.username, authResponse.user.backendroles, authResponse.user.roles, authResponse.user.tenants, authResponse.user.selectedTenant);
 
@@ -327,4 +336,4 @@ const register = function (server, options) {
 exports.plugin = {
     name: 'sg-session-storage',
     register
-};
\ No newline at end of file
+};