{"title":"Password management in Django","version":"6.1","locale":"el","docname":"topics/auth/passwords","url":"/el/6.1/topics/auth/passwords/","canonical":"https://djangodocs.dev/el/6.1/topics/auth/passwords/","summary":"Password management is something that should generally not be reinvented unnecessarily, and Django endeavors to provide a secure and flexible set of tools for…","html":"<h1>Password management in Django<a class=\"heading-anchor\" href=\"#password-management-in-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Password management is something that should generally not be reinvented\nunnecessarily, and Django endeavors to provide a secure and flexible set of\ntools for managing user passwords. This document describes how Django stores\npasswords, how the storage hashing can be configured, and some utilities to\nwork with hashed passwords.</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">Δείτε επίσης</p>\n<p>Even though users may use strong passwords, attackers might be able to\neavesdrop on their connections. Use <a class=\"reference internal\" href=\"/el/6.1/topics/security/#security-recommendation-ssl\"><span class=\"std std-ref\">HTTPS</span></a> to avoid sending passwords (or any other\nsensitive data) over plain HTTP connections because they will be vulnerable\nto password sniffing.</p>\n</aside>\n<section id=\"how-django-stores-passwords\">\n<span id=\"auth-password-storage\"></span><h2>How Django stores passwords<a class=\"heading-anchor\" href=\"#how-django-stores-passwords\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django provides a flexible password storage system and uses PBKDF2 by default.</p>\n<p>The <a class=\"reference internal\" href=\"/el/6.1/ref/contrib/auth/#django.contrib.auth.models.User.password\" title=\"django.contrib.auth.models.User.password\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">password</span></code></a> attribute of a\n<a class=\"reference internal\" href=\"/el/6.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> object is a string in this format:</p>\n<div class=\"code-block\" data-language=\"text\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Text</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=\"Text code\"><code>&lt;algorithm&gt;$&lt;iterations&gt;$&lt;salt&gt;$&lt;hash&gt;\n</code></pre></div>\n<p>Those are the components used for storing a User’s password, separated by the\ndollar-sign character and consist of: the hashing algorithm, the number of\nalgorithm iterations (work factor), the random salt, and the resulting password\nhash. The algorithm is one of a number of one-way hashing or password storage\nalgorithms Django can use; see below. Iterations describe the number of times\nthe algorithm is run over the hash. Salt is the random seed used and the hash\nis the result of the one-way function.</p>\n<p>By default, Django uses the <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a> algorithm with a SHA256 hash, a\npassword stretching mechanism recommended by <a class=\"reference external\" href=\"https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf\">NIST</a>. This should be\nsufficient for most users: it’s quite secure, requiring massive\namounts of computing time to break.</p>\n<p>However, depending on your requirements, you may choose a different\nalgorithm, or even use a custom algorithm to match your specific\nsecurity situation. Again, most users shouldn’t need to do this – if\nyou’re not sure, you probably don’t. If you do, please read on:</p>\n<p>Django chooses the algorithm to use by consulting the\n<a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> setting. This is a list of hashing algorithm\nclasses that this Django installation supports.</p>\n<p>For storing passwords, Django will use the first hasher in\n<a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>. To store new passwords with a different algorithm,\nput your preferred algorithm first in <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>.</p>\n<p>For verifying passwords, Django will find the hasher in the list that matches\nthe algorithm name in the stored password. If a stored password names an\nalgorithm not found in <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>, trying to verify it will\nraise <code class=\"docutils literal notranslate\"><span class=\"pre\">ValueError</span></code>.</p>\n<p>The default for <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> is:</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\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>This means that Django will use <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a> to store all passwords but will support\nchecking passwords stored with PBKDF2SHA1, <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">argon2</a>, and <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Bcrypt\">bcrypt</a>.</p>\n<p>The next few sections describe a couple of common ways advanced users may want\nto modify this setting.</p>\n<section id=\"using-argon2-with-django\">\n<span id=\"argon2-usage\"></span><h3>Using Argon2 with Django<a class=\"heading-anchor\" href=\"#using-argon2-with-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">Argon2</a> is the winner of the 2015 <a class=\"reference external\" href=\"https://www.password-hashing.net/\">Password Hashing Competition</a>, a community\norganized open competition to select a next generation hashing algorithm. It’s\ndesigned not to be easier to compute on custom hardware than it is to compute\non an ordinary CPU. The default variant for the Argon2 password hasher is\nArgon2id.</p>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">Argon2</a> is not the default for Django because it requires a third-party\nlibrary. The Password Hashing Competition panel, however, recommends immediate\nuse of Argon2 rather than the other algorithms supported by Django.</p>\n<p>To use Argon2id as your default storage algorithm, do the following:</p>\n<ol class=\"arabic\">\n<li><p>Install the <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/argon2-cffi/\">argon2-cffi</a> package. This can be done by running\n<code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">django[argon2]</span></code>, which is equivalent to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">argon2-cffi</span></code> (along with any version requirement\nfrom Django’s <code class=\"docutils literal notranslate\"><span class=\"pre\">pyproject.toml</span></code>).</p></li>\n<li><p>Modify <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> to list <code class=\"docutils literal notranslate\"><span class=\"pre\">Argon2PasswordHasher</span></code> first.\nThat is, in your settings file, you’d put:</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\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Keep and/or add any entries in this list if you need Django to <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">upgrade\npasswords</span></a>.</p>\n</li>\n</ol>\n</section>\n<section id=\"using-bcrypt-with-django\">\n<span id=\"bcrypt-usage\"></span><h3>Using <code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt</span></code> with Django<a class=\"heading-anchor\" href=\"#using-bcrypt-with-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Bcrypt\">Bcrypt</a> is a popular password storage algorithm that’s specifically designed\nfor long-term password storage. It’s not the default used by Django since it\nrequires the use of third-party libraries, but since many people may want to\nuse it Django supports bcrypt with minimal effort.</p>\n<p>To use Bcrypt as your default storage algorithm, do the following:</p>\n<ol class=\"arabic\">\n<li><p>Install the <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/bcrypt/\">bcrypt</a> package. This can be done by running\n<code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">django[bcrypt]</span></code>, which is equivalent to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">bcrypt</span></code> (along with any version requirement from\nDjango’s <code class=\"docutils literal notranslate\"><span class=\"pre\">pyproject.toml</span></code>).</p></li>\n<li><p>Modify <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> to list <code class=\"docutils literal notranslate\"><span class=\"pre\">BCryptSHA256PasswordHasher</span></code>\nfirst. That is, in your settings file, you’d put:</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\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Keep and/or add any entries in this list if you need Django to <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">upgrade\npasswords</span></a>.</p>\n</li>\n</ol>\n<p>That’s it – now your Django install will use Bcrypt as the default storage\nalgorithm.</p>\n</section>\n<section id=\"using-scrypt-with-django\">\n<span id=\"scrypt-usage\"></span><h3>Using <code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code> with Django<a class=\"heading-anchor\" href=\"#using-scrypt-with-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> is similar to PBKDF2 and bcrypt in utilizing a set number of iterations\nto slow down brute-force attacks. However, because PBKDF2 and bcrypt do not\nrequire a lot of memory, attackers with sufficient resources can launch\nlarge-scale parallel attacks in order to speed up the attacking process.\n<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> is specifically designed to use more memory compared to other\npassword-based key derivation functions in order to limit the amount of\nparallelism an attacker can use, see <span class=\"target\" id=\"index-0\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc7914.html\"><strong>RFC 7914</strong></a> for more details.</p>\n<p>To use <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> as your default storage algorithm, do the following:</p>\n<ol class=\"arabic\">\n<li><p>Modify <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> to list <code class=\"docutils literal notranslate\"><span class=\"pre\">ScryptPasswordHasher</span></code> first.\nThat is, in your settings file:</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\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Keep and/or add any entries in this list if you need Django to <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">upgrade\npasswords</span></a>.</p>\n</li>\n</ol>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code> requires OpenSSL 1.1+.</p>\n</aside>\n</section>\n<section id=\"increasing-the-salt-entropy\">\n<h3>Increasing the salt entropy<a class=\"heading-anchor\" href=\"#increasing-the-salt-entropy\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Most password hashes include a salt along with their password hash in order to\nprotect against rainbow table attacks. The salt itself is a random value which\nincreases the size and thus the cost of the rainbow table and is currently set\nat 128 bits with the <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code> value in the <code class=\"docutils literal notranslate\"><span class=\"pre\">BasePasswordHasher</span></code>. As\ncomputing and storage costs decrease this value should be raised. When\nimplementing your own password hasher you are free to override this value in\norder to use a desired entropy level for your password hashes. <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code>\nis measured in bits.</p>\n<aside class=\"admonition-implementation-detail admonition\">\n<p class=\"admonition-title\">Implementation detail</p>\n<p>Due to the method in which salt values are stored the <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code>\nvalue is effectively a minimum value. For instance a value of 128 would\nprovide a salt which would actually contain 131 bits of entropy.</p>\n</aside>\n</section>\n<section id=\"increasing-the-work-factor\">\n<span id=\"increasing-password-algorithm-work-factor\"></span><h3>Increasing the work factor<a class=\"heading-anchor\" href=\"#increasing-the-work-factor\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"pbkdf2-and-bcrypt\">\n<h4>PBKDF2 and bcrypt<a class=\"heading-anchor\" href=\"#pbkdf2-and-bcrypt\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>The PBKDF2 and bcrypt algorithms use a number of iterations or rounds of\nhashing. This deliberately slows down attackers, making attacks against hashed\npasswords harder. However, as computing power increases, the number of\niterations needs to be increased. We’ve chosen a reasonable default (and will\nincrease it with each release of Django), but you may wish to tune it up or\ndown, depending on your security needs and available processing power. To do\nso, you’ll subclass the appropriate algorithm and override the <code class=\"docutils literal notranslate\"><span class=\"pre\">iterations</span></code>\nparameter (use the <code class=\"docutils literal notranslate\"><span class=\"pre\">rounds</span></code> parameter when subclassing a bcrypt hasher). For\nexample, to increase the number of iterations used by the default PBKDF2\nalgorithm:</p>\n<ol class=\"arabic\">\n<li><p>Create a subclass of <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.hashers.PBKDF2PasswordHasher</span></code></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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">PBKDF2PasswordHasher</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyPBKDF2PasswordHasher</span><span class=\"p\">(</span><span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">iterations</span> <span class=\"o\">=</span> <span class=\"n\">PBKDF2PasswordHasher</span><span class=\"o\">.</span><span class=\"n\">iterations</span> <span class=\"o\">*</span> <span class=\"mi\">100</span>\n</code></pre></div>\n<p>Save this somewhere in your project. For example, you might put this in\na file like <code class=\"docutils literal notranslate\"><span class=\"pre\">myproject/hashers.py</span></code>.</p>\n</li>\n<li><p>Add your new hasher as the first entry in <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</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\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;myproject.hashers.MyPBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n</li>\n</ol>\n<p>That’s it – now your Django install will use more iterations when it\nstores passwords using PBKDF2.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p>bcrypt <code class=\"docutils literal notranslate\"><span class=\"pre\">rounds</span></code> is a logarithmic work factor, e.g. 12 rounds means\n<code class=\"docutils literal notranslate\"><span class=\"pre\">2</span> <span class=\"pre\">**</span> <span class=\"pre\">12</span></code> iterations.</p>\n</aside>\n</section>\n<section id=\"argon2\">\n<h4>Argon2<a class=\"heading-anchor\" href=\"#argon2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Argon2 has the following attributes that can be customized:</p>\n<ol class=\"arabic simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> controls the number of iterations within the hash.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> controls the size of memory that must be used during the\ncomputation of the hash.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> controls how many CPUs the computation of the hash can be\nparallelized on.</p></li>\n</ol>\n<p>The default values of these attributes are probably fine for you. If you\ndetermine that the password hash is too fast or too slow, you can tweak it as\nfollows:</p>\n<ol class=\"arabic simple\">\n<li><p>Choose <code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> to be the number of threads you can\nspare computing the hash.</p></li>\n<li><p>Choose <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> to be the KiB of memory you can spare.</p></li>\n<li><p>Adjust <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> and measure the time hashing a password takes.\nPick a <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> that takes an acceptable time for you.\nIf <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> set to 1 is unacceptably slow, lower <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code>.</p></li>\n</ol>\n<aside class=\"admonition-memory-cost-interpretation admonition\">\n<p class=\"admonition-title\"><code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> interpretation</p>\n<p>The argon2 command-line utility and some other libraries interpret the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> parameter differently from the value that Django uses. The\nconversion is given by <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span> <span class=\"pre\">==</span> <span class=\"pre\">2</span> <span class=\"pre\">**</span> <span class=\"pre\">memory_cost_commandline</span></code>.</p>\n</aside>\n</section>\n<section id=\"scrypt\">\n<h4><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code><a class=\"heading-anchor\" href=\"#scrypt\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> has the following attributes that can be customized:</p>\n<ol class=\"arabic simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">work_factor</span></code> controls the number of iterations within the hash and the\nsize of memory for computation (<em>N</em>). It must be a power of 2.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">block_size</span></code> controls the internal block size (<em>r</em>), tuning the algorithm\nto memory latency.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> controls how many independent computations may run in\nparallel (<em>p</em>).</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">maxmem</span></code> limits the maximum size of memory that can be used during the\ncomputation of the hash. Defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">0</span></code>, which means the default\nlimitation from the OpenSSL library.</p></li>\n</ol>\n<p>We’ve chosen reasonable defaults, but you may wish to tune it up or down,\ndepending on your security needs and available processing power and memory.</p>\n<aside class=\"admonition-estimating-memory-usage admonition\">\n<p class=\"admonition-title\">Estimating memory usage</p>\n<p>The minimum memory requirement of <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> is:</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\">work_factor</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">block_size</span> <span class=\"o\">*</span> <span class=\"mi\">64</span>\n</code></pre></div>\n<p>so you may need to tweak <code class=\"docutils literal notranslate\"><span class=\"pre\">maxmem</span></code> when changing the <code class=\"docutils literal notranslate\"><span class=\"pre\">work_factor</span></code> or\n<code class=\"docutils literal notranslate\"><span class=\"pre\">block_size</span></code> values.</p>\n<p>If the underlying implementation of <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> is fully multithreaded, the\nmemory requirement is multiplied by the <code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> value.</p>\n</aside>\n</section>\n</section>\n<section id=\"password-upgrading\">\n<span id=\"password-upgrades\"></span><h3>Password upgrading<a class=\"heading-anchor\" href=\"#password-upgrading\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>When users log in, if their passwords are stored with anything other than\nthe preferred algorithm, Django will automatically upgrade the algorithm\nto the preferred one. This means that old installs of Django will get\nautomatically more secure as users log in, and it also means that you\ncan switch to new (and better) storage algorithms as they get invented.</p>\n<p>However, Django can only upgrade passwords that use algorithms mentioned in\n<a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>, so as you upgrade to new systems you should make\nsure never to <em>remove</em> entries from this list. If you do, users using\nunmentioned algorithms won’t be able to upgrade. Hashed passwords will be\nupdated when increasing (or decreasing) the number of PBKDF2 iterations, bcrypt\nrounds, or argon2 attributes.</p>\n<p>Be aware that if all the passwords in your database aren’t encoded in the\ndefault hasher’s algorithm, you may be vulnerable to a user enumeration timing\nattack due to a difference between the duration of a login request for a user\nwith a password encoded in a non-default algorithm and the duration of a login\nrequest for a nonexistent user (which runs the default hasher). You may be able\nto mitigate this by <a class=\"reference internal\" href=\"#wrapping-password-hashers\"><span class=\"std std-ref\">upgrading older password hashes</span></a>.</p>\n</section>\n<section id=\"password-upgrading-without-requiring-a-login\">\n<span id=\"wrapping-password-hashers\"></span><h3>Password upgrading without requiring a login<a class=\"heading-anchor\" href=\"#password-upgrading-without-requiring-a-login\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you have an existing database with an older, weak hash such as MD5, you\nmight want to upgrade those hashes yourself instead of waiting for the upgrade\nto happen when a user logs in (which may never happen if a user doesn’t return\nto your site). In this case, you can use a «wrapped» password hasher.</p>\n<p>For this example, we’ll migrate a collection of MD5 hashes to use\nPBKDF2(MD5(password)) and add the corresponding password hasher for checking\nif a user entered the correct password on login. We assume we’re using the\nbuilt-in <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code> model and that our project has an <code class=\"docutils literal notranslate\"><span class=\"pre\">accounts</span></code> app. You can\nmodify the pattern to work with any algorithm or with a custom user model.</p>\n<p>First, we’ll add the custom hasher:</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\">accounts/hashers.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.hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"p\">(</span>\n    <span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">,</span>\n    <span class=\"n\">MD5PasswordHasher</span><span class=\"p\">,</span>\n<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">PBKDF2WrappedMD5PasswordHasher</span><span class=\"p\">(</span><span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">):</span>\n    <span class=\"n\">algorithm</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;pbkdf2_wrapped_md5&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">encode</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span> <span class=\"o\">=</span> <span class=\"n\">MD5PasswordHasher</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s2\">&quot;$&quot;</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>The data migration might look something like:</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\">accounts/migrations/0002_migrate_md5_passwords.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.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">migrations</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">..hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">PBKDF2WrappedMD5PasswordHasher</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">forwards_func</span><span class=\"p\">(</span><span class=\"n\">apps</span><span class=\"p\">,</span> <span class=\"n\">schema_editor</span><span class=\"p\">):</span>\n    <span class=\"n\">User</span> <span class=\"o\">=</span> <span class=\"n\">apps</span><span class=\"o\">.</span><span class=\"n\">get_model</span><span class=\"p\">(</span><span class=\"s2\">&quot;auth&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;User&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">users</span> <span class=\"o\">=</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">password__startswith</span><span class=\"o\">=</span><span class=\"s2\">&quot;md5$&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">hasher</span> <span class=\"o\">=</span> <span class=\"n\">PBKDF2WrappedMD5PasswordHasher</span><span class=\"p\">()</span>\n    <span class=\"k\">for</span> <span class=\"n\">user</span> <span class=\"ow\">in</span> <span class=\"n\">users</span><span class=\"p\">:</span>\n        <span class=\"n\">algorithm</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span> <span class=\"o\">=</span> <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">password</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s2\">&quot;$&quot;</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">hasher</span><span class=\"o\">.</span><span class=\"n\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">update_fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;password&quot;</span><span class=\"p\">])</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Migration</span><span class=\"p\">(</span><span class=\"n\">migrations</span><span class=\"o\">.</span><span class=\"n\">Migration</span><span class=\"p\">):</span>\n    <span class=\"n\">dependencies</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;accounts&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;0001_initial&quot;</span><span class=\"p\">),</span>\n        <span class=\"c1\"># replace this with the latest migration in contrib.auth</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;auth&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;####_migration_name&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">operations</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"n\">migrations</span><span class=\"o\">.</span><span class=\"n\">RunPython</span><span class=\"p\">(</span><span class=\"n\">forwards_func</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n</code></pre></figure>\n<p>Be aware that this migration will take on the order of several minutes for\nseveral thousand users, depending on the speed of your hardware.</p>\n<p>Finally, we’ll add a <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> setting:</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/settings.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=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;accounts.hashers.PBKDF2WrappedMD5PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>Include any other hashers that your site uses in this list.</p>\n</section>\n<section id=\"included-hashers\">\n<span id=\"auth-included-hashers\"></span><h3>Included hashers<a class=\"heading-anchor\" href=\"#included-hashers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>The full list of hashers included in Django is:</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=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.MD5PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>The corresponding algorithm names are:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">pbkdf2_sha256</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">pbkdf2_sha1</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">argon2</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt_sha256</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">md5</span></code></p></li>\n</ul>\n</section>\n<section id=\"writing-your-own-hasher\">\n<span id=\"write-your-own-password-hasher\"></span><h3>Writing your own hasher<a class=\"heading-anchor\" href=\"#writing-your-own-hasher\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you write your own password hasher that contains a work factor such as a\nnumber of iterations, you should implement a\n<code class=\"docutils literal notranslate\"><span class=\"pre\">harden_runtime(self,</span> <span class=\"pre\">password,</span> <span class=\"pre\">encoded)</span></code> method to bridge the runtime gap\nbetween the work factor supplied in the <code class=\"docutils literal notranslate\"><span class=\"pre\">encoded</span></code> password and the default\nwork factor of the hasher. This prevents a user enumeration timing attack due\nto  difference between a login request for a user with a password encoded in an\nolder number of iterations and a nonexistent user (which runs the default\nhasher’s default number of iterations).</p>\n<p>Taking PBKDF2 as example, if <code class=\"docutils literal notranslate\"><span class=\"pre\">encoded</span></code> contains 20,000 iterations and the\nhasher’s default <code class=\"docutils literal notranslate\"><span class=\"pre\">iterations</span></code> is 30,000, the method should run <code class=\"docutils literal notranslate\"><span class=\"pre\">password</span></code>\nthrough another 10,000 iterations of PBKDF2.</p>\n<p>If your hasher doesn’t have a work factor, implement the method as a no-op\n(<code class=\"docutils literal notranslate\"><span class=\"pre\">pass</span></code>).</p>\n</section>\n</section>\n<section id=\"module-django.contrib.auth.hashers\">\n<span id=\"manually-managing-a-user-s-password\"></span><h2>Manually managing a user’s password<a class=\"heading-anchor\" href=\"#module-django.contrib.auth.hashers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The <a class=\"reference internal\" href=\"#module-django.contrib.auth.hashers\" title=\"django.contrib.auth.hashers\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.hashers</span></code></a> module provides a set of functions\nto create and validate hashed passwords. You can use them independently\nfrom the <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code> model.</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.check_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">check_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">setter</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">preferred</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.check_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.acheck_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">acheck_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">asetter</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">preferred</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.acheck_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p><em>Asynchronous version</em>: <code class=\"docutils literal notranslate\"><span class=\"pre\">acheck_password()</span></code></p>\n<p>If you’d like to manually authenticate a user by comparing a plaintext\npassword to the hashed password in the database, use the convenience\nfunction <a class=\"reference internal\" href=\"#django.contrib.auth.hashers.check_password\" title=\"django.contrib.auth.hashers.check_password\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">check_password()</span></code></a>. It takes two mandatory arguments: the\nplaintext password to check, and the full value of a user’s <code class=\"docutils literal notranslate\"><span class=\"pre\">password</span></code>\nfield in the database to check against. It returns <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> if they match,\n<code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> otherwise. Optionally, you can pass a callable <code class=\"docutils literal notranslate\"><span class=\"pre\">setter</span></code> that\ntakes the password and will be called when you need to regenerate it. You\ncan also pass <code class=\"docutils literal notranslate\"><span class=\"pre\">preferred</span></code> to change a hashing algorithm if you don’t want\nto use the default (first entry of <code class=\"docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code> setting). See\n<a class=\"reference internal\" href=\"#auth-included-hashers\"><span class=\"std std-ref\">Included hashers</span></a> for the algorithm name of each hasher.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.make_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">make_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">hasher</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.make_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Creates a hashed password in the format used by this application. It takes\none mandatory argument: the plaintext password (string or bytes).\nOptionally, you can provide a salt and a hashing algorithm to use, if you\ndon’t want to use the defaults (first entry of <code class=\"docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code>\nsetting). See <a class=\"reference internal\" href=\"#auth-included-hashers\"><span class=\"std std-ref\">Included hashers</span></a> for the algorithm name of each\nhasher. If the password argument is <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>, an unusable password is\nreturned (one that will never be accepted by <a class=\"reference internal\" href=\"#django.contrib.auth.hashers.check_password\" title=\"django.contrib.auth.hashers.check_password\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">check_password()</span></code></a>).</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.is_password_usable\">\n<span class=\"sig-name descname\"><span class=\"pre\">is_password_usable</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded_password</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.is_password_usable\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> if the password is a result of\n<a class=\"reference internal\" href=\"/el/6.1/ref/contrib/auth/#django.contrib.auth.models.User.set_unusable_password\" title=\"django.contrib.auth.models.User.set_unusable_password\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">User.set_unusable_password()</span></code></a>.</p>\n</dd></dl>\n\n</section>\n<section id=\"module-django.contrib.auth.password_validation\">\n<span id=\"id3\"></span><span id=\"password-validation\"></span><h2>Password validation<a class=\"heading-anchor\" href=\"#module-django.contrib.auth.password_validation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Users often choose poor passwords. To help mitigate this problem, Django\noffers pluggable password validation. You can configure multiple password\nvalidators at the same time. A few validators are included in Django, but you\ncan write your own as well.</p>\n<p>Each password validator must provide a help text to explain the requirements to\nthe user, validate a given password and return an error message if it does not\nmeet the requirements, and optionally define a callback to be notified when\nthe password for a user has been changed. Validators can also have optional\nsettings to fine tune their behavior.</p>\n<p>Validation is controlled by the <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a> setting.\nThe default for the setting is an empty list, which means no validators are\napplied. In new projects created with the default <a class=\"reference internal\" href=\"/el/6.1/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">startproject</span></code></a>\ntemplate, a set of validators is enabled by default.</p>\n<p>By default, validators are used in the forms to reset or change passwords and\nin the <a class=\"reference internal\" href=\"/el/6.1/ref/django-admin/#django-admin-createsuperuser\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">createsuperuser</span></code></a> and <a class=\"reference internal\" href=\"/el/6.1/ref/django-admin/#django-admin-changepassword\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">changepassword</span></code></a> management\ncommands. Validators aren’t applied at the model level, for example in\n<code class=\"docutils literal notranslate\"><span class=\"pre\">User.objects.create_user()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">create_superuser()</span></code>, because we assume\nthat developers, not users, interact with Django at that level and also because\nmodel validation doesn’t automatically run as part of creating models.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p>Password validation can prevent the use of many types of weak passwords.\nHowever, the fact that a password passes all the validators doesn’t\nguarantee that it is a strong password. There are many factors that can\nweaken a password that are not detectable by even the most advanced\npassword validators.</p>\n</aside>\n<section id=\"enabling-password-validation\">\n<h3>Enabling password validation<a class=\"heading-anchor\" href=\"#enabling-password-validation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Password validation is configured in the\n<a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</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\">AUTH_PASSWORD_VALIDATORS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.UserAttributeSimilarityValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.MinimumLengthValidator&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"mi\">9</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.CommonPasswordValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.NumericPasswordValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>This example enables all four included validators:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">UserAttributeSimilarityValidator</span></code>, which checks the similarity between\nthe password and a set of attributes of the user.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">MinimumLengthValidator</span></code>, which checks whether the password meets a minimum\nlength. This validator is configured with a custom option: it now requires\nthe minimum length to be nine characters, instead of the default eight.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">CommonPasswordValidator</span></code>, which checks whether the password occurs in a\nlist of common passwords. By default, it compares to an included list of\n20,000 common passwords.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">NumericPasswordValidator</span></code>, which checks whether the password isn’t\nentirely numeric.</p></li>\n</ul>\n<p>For <code class=\"docutils literal notranslate\"><span class=\"pre\">UserAttributeSimilarityValidator</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">CommonPasswordValidator</span></code>,\nwe’re using the default settings in this example. <code class=\"docutils literal notranslate\"><span class=\"pre\">NumericPasswordValidator</span></code>\nhas no settings.</p>\n<p>The help texts and any errors from password validators are always returned in\nthe order they are listed in <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>.</p>\n</section>\n<section id=\"included-validators\">\n<span id=\"included-password-validators\"></span><h3>Included validators<a class=\"heading-anchor\" href=\"#included-validators\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django includes four validators:</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">MinimumLengthValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">min_length</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">8</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Validates that the password is of a minimum length.\nThe minimum length can be customized with the <code class=\"docutils literal notranslate\"><span class=\"pre\">min_length</span></code> parameter.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator.get_error_message\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> error message. Defaults\nto <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;This</span> <span class=\"pre\">password</span> <span class=\"pre\">is</span> <span class=\"pre\">too</span> <span class=\"pre\">short.</span> <span class=\"pre\">It</span> <span class=\"pre\">must</span> <span class=\"pre\">contain</span> <span class=\"pre\">at</span> <span class=\"pre\">least</span> <span class=\"pre\">&lt;min_length&gt;</span>\n<span class=\"pre\">characters.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator.get_help_text\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the validator’s help text. Defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Your</span>\n<span class=\"pre\">password</span> <span class=\"pre\">must</span> <span class=\"pre\">contain</span> <span class=\"pre\">at</span> <span class=\"pre\">least</span> <span class=\"pre\">&lt;min_length&gt;</span> <span class=\"pre\">characters.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">UserAttributeSimilarityValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user_attributes</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">DEFAULT_USER_ATTRIBUTES</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">max_similarity</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">0.7</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Validates that the password is sufficiently different from certain\nattributes of the user.</p>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">user_attributes</span></code> parameter should be an iterable of names of user\nattributes to compare to. If this argument is not provided, the default\nis used: <code class=\"docutils literal notranslate\"><span class=\"pre\">'username',</span> <span class=\"pre\">'first_name',</span> <span class=\"pre\">'last_name',</span> <span class=\"pre\">'email'</span></code>.\nAttributes that don’t exist are ignored.</p>\n<p>The maximum allowed similarity of passwords can be set on a scale of 0.1\nto 1.0 with the <code class=\"docutils literal notranslate\"><span class=\"pre\">max_similarity</span></code> parameter. This is compared to the\nresult of <a class=\"reference external\" href=\"https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.quick_ratio\" title=\"(στη Python έκδοση 3.14)\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">difflib.SequenceMatcher.quick_ratio()</span></code></a>. A value of 0.1\nrejects passwords unless they are substantially different from the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">user_attributes</span></code>, whereas a value of 1.0 rejects only passwords that are\nidentical to an attribute’s value.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_error_message\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> error message. Defaults\nto <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;The</span> <span class=\"pre\">password</span> <span class=\"pre\">is</span> <span class=\"pre\">too</span> <span class=\"pre\">similar</span> <span class=\"pre\">to</span> <span class=\"pre\">the</span> <span class=\"pre\">&lt;user_attribute&gt;.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_help_text\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the validator’s help text. Defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Your</span>\n<span class=\"pre\">password</span> <span class=\"pre\">can’t</span> <span class=\"pre\">be</span> <span class=\"pre\">too</span> <span class=\"pre\">similar</span> <span class=\"pre\">to</span> <span class=\"pre\">your</span> <span class=\"pre\">other</span> <span class=\"pre\">personal</span> <span class=\"pre\">information.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">CommonPasswordValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_list_path</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">DEFAULT_PASSWORD_LIST_PATH</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Validates that the password is not a common password. This converts the\npassword to lowercase (to do a case-insensitive comparison) and checks it\nagainst a list of 20,000 common passwords created by <a class=\"reference external\" href=\"https://gist.github.com/roycewilliams/226886fd01572964e1431ac8afc999ce\">Royce Williams</a>.</p>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">password_list_path</span></code> can be set to the path of a custom file of\ncommon passwords. This file should contain one lowercase password per line\nand may be plain text or gzipped.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator.get_error_message\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> error message. Defaults\nto <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;This</span> <span class=\"pre\">password</span> <span class=\"pre\">is</span> <span class=\"pre\">too</span> <span class=\"pre\">common.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator.get_help_text\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the validator’s help text. Defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Your</span>\n<span class=\"pre\">password</span> <span class=\"pre\">can’t</span> <span class=\"pre\">be</span> <span class=\"pre\">a</span> <span class=\"pre\">commonly</span> <span class=\"pre\">used</span> <span class=\"pre\">password.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">NumericPasswordValidator</span></span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Validate that the password is not entirely numeric.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator.get_error_message\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> error message. Defaults\nto <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;This</span> <span class=\"pre\">password</span> <span class=\"pre\">is</span> <span class=\"pre\">entirely</span> <span class=\"pre\">numeric.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator.get_help_text\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A hook for customizing the validator’s help text. Defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Your</span>\n<span class=\"pre\">password</span> <span class=\"pre\">can’t</span> <span class=\"pre\">be</span> <span class=\"pre\">entirely</span> <span class=\"pre\">numeric.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"integrating-validation\">\n<h3>Integrating validation<a class=\"heading-anchor\" href=\"#integrating-validation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>There are a few functions in <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.password_validation</span></code> that\nyou can call from your own forms or other code to integrate password\nvalidation. This can be useful if you use custom forms for password setting,\nor if you have API calls that allow passwords to be set, for example.</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.validate_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">validate_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.validate_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Validates a password. If all validators find the password valid, returns\n<code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>. If one or more validators reject the password, raises a\n<a class=\"reference internal\" href=\"/el/6.1/ref/exceptions/#django.core.exceptions.ValidationError\" title=\"django.core.exceptions.ValidationError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code></a> with all the error messages\nfrom the validators.</p>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">user</span></code> object is optional: if it’s not provided, some validators may\nnot be able to perform any validation and will accept any password.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_changed\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_changed</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_changed\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Informs all validators that the password has been changed. This can be used\nby validators such as one that prevents password reuse. This should be\ncalled once the password has been successfully changed.</p>\n<p>For subclasses of <a class=\"reference internal\" href=\"/el/6.1/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AbstractBaseUser</span></code></a>,\nthe password field will be marked as «dirty» when calling\n<a class=\"reference internal\" href=\"/el/6.1/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser.set_password\" title=\"django.contrib.auth.models.AbstractBaseUser.set_password\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">set_password()</span></code></a> which\ntriggers a call to <code class=\"docutils literal notranslate\"><span class=\"pre\">password_changed()</span></code> after the user is saved.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_validators_help_texts\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_validators_help_texts</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_validators_help_texts\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns a list of the help texts of all validators. These explain the\npassword requirements to the user.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_validators_help_text_html\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_validators_help_text_html</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_validators_help_text_html\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns an HTML string with all help texts in an <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;ul&gt;</span></code>. This is\nhelpful when adding password validation to forms, as you can pass the\noutput directly to the <code class=\"docutils literal notranslate\"><span class=\"pre\">help_text</span></code> parameter of a form field.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.get_password_validators\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_password_validators</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">validator_config</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.get_password_validators\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Returns a set of validator objects based on the <code class=\"docutils literal notranslate\"><span class=\"pre\">validator_config</span></code>\nparameter. By default, all functions use the validators defined in\n<a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>, but by calling this function with an\nalternate set of validators and then passing the result into the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">password_validators</span></code> parameter of the other functions, your custom set\nof validators will be used instead. This is useful when you have a typical\nset of validators to use for most scenarios, but also have a special\nsituation that requires a custom set. If you always use the same set\nof validators, there is no need to use this function, as the configuration\nfrom <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a> is used by default.</p>\n<p>The structure of <code class=\"docutils literal notranslate\"><span class=\"pre\">validator_config</span></code> is identical to the\nstructure of <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>. The return value of\nthis function can be passed into the <code class=\"docutils literal notranslate\"><span class=\"pre\">password_validators</span></code> parameter\nof the functions listed above.</p>\n</dd></dl>\n\n<p>Note that where the password is passed to one of these functions, this should\nalways be the clear text password - not a hashed password.</p>\n</section>\n<section id=\"writing-your-own-validator\">\n<h3>Writing your own validator<a class=\"heading-anchor\" href=\"#writing-your-own-validator\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If Django’s built-in validators are not sufficient, you can write your own\npassword validators. Validators have a fairly small interface. They must\nimplement two methods:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">validate(self,</span> <span class=\"pre\">password,</span> <span class=\"pre\">user=None)</span></code>: validate a password. Return\n<code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> if the password is valid, or raise a\n<a class=\"reference internal\" href=\"/el/6.1/ref/exceptions/#django.core.exceptions.ValidationError\" title=\"django.core.exceptions.ValidationError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code></a> with an error message if the\npassword is not valid. You must be able to deal with <code class=\"docutils literal notranslate\"><span class=\"pre\">user</span></code> being\n<code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> - if that means your validator can’t run, return <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> for no\nerror.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">get_help_text()</span></code>: provide a help text to explain the requirements to\nthe user.</p></li>\n</ul>\n<p>Any items in the <code class=\"docutils literal notranslate\"><span class=\"pre\">OPTIONS</span></code> in <a class=\"reference internal\" href=\"/el/6.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a> for your\nvalidator will be passed to the constructor. All constructor arguments should\nhave a default value.</p>\n<p>Here’s a basic example of a validator, with one optional 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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.exceptions</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ValidationError</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils.translation</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">gettext</span> <span class=\"k\">as</span> <span class=\"n\">_</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MinimumLengthValidator</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">min_length</span><span class=\"o\">=</span><span class=\"mi\">8</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span> <span class=\"o\">=</span> <span class=\"n\">min_length</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">validate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">user</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">)</span> <span class=\"o\">&lt;</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n                <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;This password must contain at least </span><span class=\"si\">%(min_length)d</span><span class=\"s2\"> characters.&quot;</span><span class=\"p\">),</span>\n                <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;password_too_short&quot;</span><span class=\"p\">,</span>\n                <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">},</span>\n            <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_help_text</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_</span><span class=\"p\">(</span>\n            <span class=\"s2\">&quot;Your password must contain at least </span><span class=\"si\">%(min_length)d</span><span class=\"s2\"> characters.&quot;</span>\n            <span class=\"o\">%</span> <span class=\"p\">{</span><span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">}</span>\n        <span class=\"p\">)</span>\n</code></pre></div>\n<p>You can also implement <code class=\"docutils literal notranslate\"><span class=\"pre\">password_changed(password,</span> <span class=\"pre\">user=None</span></code>), which will\nbe called after a successful password change. That can be used to prevent\npassword reuse, for example. However, if you decide to store a user’s previous\npasswords, you should never do so in clear text.</p>\n</section>\n</section>","rootId":"password-management-in-django","toc":[{"title":"How Django stores passwords","anchor":"how-django-stores-passwords","children":[{"title":"Using Argon2 with Django","anchor":"using-argon2-with-django","children":[]},{"title":"Using bcrypt with Django","anchor":"using-bcrypt-with-django","children":[]},{"title":"Using scrypt with Django","anchor":"using-scrypt-with-django","children":[]},{"title":"Increasing the salt entropy","anchor":"increasing-the-salt-entropy","children":[]},{"title":"Increasing the work factor","anchor":"increasing-the-work-factor","children":[{"title":"PBKDF2 and bcrypt","anchor":"pbkdf2-and-bcrypt","children":[]},{"title":"Argon2","anchor":"argon2","children":[]},{"title":"scrypt","anchor":"scrypt","children":[]}]},{"title":"Password upgrading","anchor":"password-upgrading","children":[]},{"title":"Password upgrading without requiring a login","anchor":"password-upgrading-without-requiring-a-login","children":[]},{"title":"Included hashers","anchor":"included-hashers","children":[]},{"title":"Writing your own hasher","anchor":"writing-your-own-hasher","children":[]}]},{"title":"Manually managing a user’s password","anchor":"module-django.contrib.auth.hashers","children":[]},{"title":"Password validation","anchor":"module-django.contrib.auth.password_validation","children":[{"title":"Enabling password validation","anchor":"enabling-password-validation","children":[]},{"title":"Included validators","anchor":"included-validators","children":[]},{"title":"Integrating validation","anchor":"integrating-validation","children":[]},{"title":"Writing your own validator","anchor":"writing-your-own-validator","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"Using Django","url":"/el/6.1/topics/"},{"docname":"topics/auth/index","title":"User authentication in Django","url":"/el/6.1/topics/auth/"}],"prev":{"docname":"topics/auth/default","title":"Using the Django authentication system","url":"/el/6.1/topics/auth/default/"},"next":{"docname":"topics/auth/customizing","title":"Customizing authentication in Django","url":"/el/6.1/topics/auth/customizing/"},"formats":{"html":"/el/6.1/topics/auth/passwords/","markdown":"/el/6.1/topics/auth/passwords.md","json":"/el/6.1/topics/auth/passwords.json"},"source":"https://github.com/django/django/blob/stable/6.1.x/docs/topics/auth/passwords.txt","official":"https://docs.djangoproject.com/el/6.1/topics/auth/passwords/","inVersions":["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"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}