{"title":"How to authenticate using REMOTE_USER","version":"5.2","locale":"en","docname":"howto/auth-remote-user","url":"/en/5.2/howto/auth-remote-user/","canonical":"https://djangodocs.dev/en/5.2/howto/auth-remote-user/","summary":"This document describes how to make use of external authentication sources (where the web server sets the REMOTE_USER environment variable) in your Django…","html":"<h1>How to authenticate using <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code><a class=\"heading-anchor\" href=\"#how-to-authenticate-using-remote-user\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>This document describes how to make use of external authentication sources\n(where the web server sets the <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> environment variable) in your\nDjango applications.  This type of authentication solution is typically seen on\nintranet sites, with single sign-on solutions such as IIS and Integrated\nWindows Authentication or Apache and <a class=\"reference external\" href=\"https://httpd.apache.org/docs/current/mod/mod_authnz_ldap.html\">mod_authnz_ldap</a>, <a class=\"reference external\" href=\"https://www.apereo.org/projects/cas\">CAS</a>, <a class=\"reference external\" href=\"https://uit.stanford.edu/service/authentication\">WebAuth</a>,\n<a class=\"reference external\" href=\"https://sourceforge.net/projects/mod-auth-sspi\">mod_auth_sspi</a>, etc.</p>\n<p>When the web server takes care of authentication it typically sets the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> environment variable for use in the underlying application.  In\nDjango, <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> is made available in the <a class=\"reference internal\" href=\"/en/5.2/ref/request-response/#django.http.HttpRequest.META\" title=\"django.http.HttpRequest.META\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.META</span></code></a> attribute.  Django can be configured to make\nuse of the <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> value using the <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code>\nor <code class=\"docutils literal notranslate\"><span class=\"pre\">PersistentRemoteUserMiddleware</span></code>, and\n<a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend\" title=\"django.contrib.auth.backends.RemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RemoteUserBackend</span></code></a> classes found in\n<a class=\"reference internal\" href=\"/en/5.2/topics/auth/#module-django.contrib.auth\" title=\"django.contrib.auth: Django's authentication framework.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.auth</span></code></a>.</p>\n<section id=\"configuration\">\n<h2>Configuration<a class=\"heading-anchor\" href=\"#configuration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>First, you must add the\n<a class=\"reference internal\" href=\"/en/5.2/ref/middleware/#django.contrib.auth.middleware.RemoteUserMiddleware\" title=\"django.contrib.auth.middleware.RemoteUserMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.middleware.RemoteUserMiddleware</span></code></a> to the\n<a class=\"reference internal\" href=\"/en/5.2/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> setting <strong>after</strong> the\n<a class=\"reference internal\" href=\"/en/5.2/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware\" title=\"django.contrib.auth.middleware.AuthenticationMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.middleware.AuthenticationMiddleware</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">MIDDLEWARE</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;...&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.middleware.AuthenticationMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.middleware.RemoteUserMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;...&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Next, you must replace the <a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend\" title=\"django.contrib.auth.backends.ModelBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code></a>\nwith <a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend\" title=\"django.contrib.auth.backends.RemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RemoteUserBackend</span></code></a> in the\n<a class=\"reference internal\" href=\"/en/5.2/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTHENTICATION_BACKENDS</span></code></a> setting:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">AUTHENTICATION_BACKENDS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.backends.RemoteUserBackend&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>With this setup, <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code> will detect the username in\n<code class=\"docutils literal notranslate\"><span class=\"pre\">request.META['REMOTE_USER']</span></code> and will authenticate and auto-login that user\nusing the <a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend\" title=\"django.contrib.auth.backends.RemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RemoteUserBackend</span></code></a>.</p>\n<p>Be aware that this particular setup disables authentication with the default\n<code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code>. This means that if the <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> value is not set\nthen the user is unable to log in, even using Django’s admin interface.\nAdding <code class=\"docutils literal notranslate\"><span class=\"pre\">'django.contrib.auth.backends.ModelBackend'</span></code> to the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">AUTHENTICATION_BACKENDS</span></code> list will use <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code> as a fallback\nif <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> is absent, which will solve these issues.</p>\n<p>Django’s user management, such as the views in <code class=\"docutils literal notranslate\"><span class=\"pre\">contrib.admin</span></code> and\nthe <a class=\"reference internal\" href=\"/en/5.2/ref/django-admin/#django-admin-createsuperuser\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">createsuperuser</span></code></a> management command, doesn’t integrate with\nremote users. These interfaces work with users stored in the database\nregardless of <code class=\"docutils literal notranslate\"><span class=\"pre\">AUTHENTICATION_BACKENDS</span></code>.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Since the <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserBackend</span></code> inherits from <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code>, you will\nstill have all of the same permissions checking that is implemented in\n<code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code>.</p>\n<p>Users with <a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">is_active=False</span></code></a> won’t be allowed to\nauthenticate. Use\n<a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.AllowAllUsersRemoteUserBackend\" title=\"django.contrib.auth.backends.AllowAllUsersRemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AllowAllUsersRemoteUserBackend</span></code></a> if\nyou want to allow them to.</p>\n</aside>\n<p>If your authentication mechanism uses a custom HTTP header and not\n<code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code>, you can subclass <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code> and set the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">header</span></code> attribute to the desired <code class=\"docutils literal notranslate\"><span class=\"pre\">request.META</span></code> key.  For example:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">mysite/middleware.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code> <span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.middleware</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">RemoteUserMiddleware</span>\n\n\n <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">CustomHeaderRemoteUserMiddleware</span><span class=\"p\">(</span><span class=\"n\">RemoteUserMiddleware</span><span class=\"p\">):</span>\n     <span class=\"n\">header</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;HTTP_AUTHUSER&quot;</span>\n</code></pre></figure>\n<p>This custom middleware is then used in the <a class=\"reference internal\" href=\"/en/5.2/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">MIDDLEWARE</span></code></a> setting\ninstead of <a class=\"reference internal\" href=\"/en/5.2/ref/middleware/#django.contrib.auth.middleware.RemoteUserMiddleware\" title=\"django.contrib.auth.middleware.RemoteUserMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.middleware.RemoteUserMiddleware</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">MIDDLEWARE</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;...&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.middleware.AuthenticationMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;mysite.middleware.CustomHeaderRemoteUserMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;...&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>Be very careful if using a <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code> subclass with a custom\nHTTP header. You must be sure that your front-end web server always sets or\nstrips that header based on the appropriate authentication checks, never\npermitting an end-user to submit a fake (or “spoofed”) header value. Since\nthe HTTP headers <code class=\"docutils literal notranslate\"><span class=\"pre\">X-Auth-User</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">X-Auth_User</span></code> (for example) both\nnormalize to the <code class=\"docutils literal notranslate\"><span class=\"pre\">HTTP_X_AUTH_USER</span></code> key in <code class=\"docutils literal notranslate\"><span class=\"pre\">request.META</span></code>, you must\nalso check that your web server doesn’t allow a spoofed header using\nunderscores in place of dashes.</p>\n<p>This warning doesn’t apply to <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code> in its default\nconfiguration with <code class=\"docutils literal notranslate\"><span class=\"pre\">header</span> <span class=\"pre\">=</span> <span class=\"pre\">'REMOTE_USER'</span></code>, since a key that doesn’t\nstart with <code class=\"docutils literal notranslate\"><span class=\"pre\">HTTP_</span></code> in <code class=\"docutils literal notranslate\"><span class=\"pre\">request.META</span></code> can only be set by your WSGI\nserver, not directly from an HTTP request header.</p>\n</aside>\n<p>If you need more control, you can create your own authentication backend\nthat inherits from <a class=\"reference internal\" href=\"/en/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend\" title=\"django.contrib.auth.backends.RemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RemoteUserBackend</span></code></a> and\noverride one or more of its attributes and methods.</p>\n</section>\n<section id=\"using-remote-user-on-login-pages-only\">\n<span id=\"persistent-remote-user-middleware-howto\"></span><h2>Using <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> on login pages only<a class=\"heading-anchor\" href=\"#using-remote-user-on-login-pages-only\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code> authentication middleware assumes that the HTTP\nrequest header <code class=\"docutils literal notranslate\"><span class=\"pre\">REMOTE_USER</span></code> is present with all authenticated requests. That\nmight be expected and practical when Basic HTTP Auth with <code class=\"docutils literal notranslate\"><span class=\"pre\">htpasswd</span></code> or\nsimilar mechanisms are used, but with Negotiate (GSSAPI/Kerberos) or other\nresource intensive authentication methods, the authentication in the front-end\nHTTP server is usually only set up for one or a few login URLs, and after\nsuccessful authentication, the application is supposed to maintain the\nauthenticated session itself.</p>\n<p><a class=\"reference internal\" href=\"/en/5.2/ref/middleware/#django.contrib.auth.middleware.PersistentRemoteUserMiddleware\" title=\"django.contrib.auth.middleware.PersistentRemoteUserMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">PersistentRemoteUserMiddleware</span></code></a>\nprovides support for this use case. It will maintain the authenticated session\nuntil explicit logout by the user. The class can be used as a drop-in\nreplacement of <a class=\"reference internal\" href=\"/en/5.2/ref/middleware/#django.contrib.auth.middleware.RemoteUserMiddleware\" title=\"django.contrib.auth.middleware.RemoteUserMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RemoteUserMiddleware</span></code></a>\nin the documentation above.</p>\n</section>","rootId":"how-to-authenticate-using-remote-user","toc":[{"title":"Configuration","anchor":"configuration","children":[]},{"title":"Using REMOTE_USER on login pages only","anchor":"using-remote-user-on-login-pages-only","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"How-to guides","url":"/en/5.2/howto/"}],"prev":{"docname":"howto/static-files/deployment","title":"How to deploy static files","url":"/en/5.2/howto/static-files/deployment/"},"next":{"docname":"howto/csrf","title":"How to use Django’s CSRF protection","url":"/en/5.2/howto/csrf/"},"formats":{"html":"/en/5.2/howto/auth-remote-user/","markdown":"/en/5.2/howto/auth-remote-user.md","json":"/en/5.2/howto/auth-remote-user.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/howto/auth-remote-user.txt","official":"https://docs.djangoproject.com/en/5.2/howto/auth-remote-user/","inVersions":["dev","6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9","1.8"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}