{"id":13481664,"url":"https://github.com/anexia-it/django-rest-passwordreset","last_synced_at":"2026-02-19T06:32:50.277Z","repository":{"id":39873752,"uuid":"84864340","full_name":"anexia-it/django-rest-passwordreset","owner":"anexia-it","description":"An extension of django rest framework, providing a configurable password reset strategy","archived":false,"fork":false,"pushed_at":"2024-11-13T17:39:13.000Z","size":360,"stargazers_count":436,"open_issues_count":32,"forks_count":151,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-09-27T18:21:01.563Z","etag":null,"topics":["django","django-rest-framework","hacktoberfest","password-reset"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anexia-it.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-03-13T19:06:30.000Z","updated_at":"2025-09-27T17:51:27.000Z","dependencies_parsed_at":"2024-06-18T13:45:26.193Z","dependency_job_id":"92dd81d4-cece-4944-8491-270de0c6393c","html_url":"https://github.com/anexia-it/django-rest-passwordreset","commit_stats":{"total_commits":113,"total_committers":39,"mean_commits":"2.8974358974358974","dds":0.7256637168141593,"last_synced_commit":"60570e1d3d02227830c0dac047c1f37039fffc7d"},"previous_names":["anx-ckreuzberger/django-rest-passwordreset"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/anexia-it/django-rest-passwordreset","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anexia-it%2Fdjango-rest-passwordreset","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anexia-it%2Fdjango-rest-passwordreset/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anexia-it%2Fdjango-rest-passwordreset/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anexia-it%2Fdjango-rest-passwordreset/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anexia-it","download_url":"https://codeload.github.com/anexia-it/django-rest-passwordreset/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anexia-it%2Fdjango-rest-passwordreset/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29604800,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T05:11:50.834Z","status":"ssl_error","status_checked_at":"2026-02-19T05:11:38.921Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-rest-framework","hacktoberfest","password-reset"],"created_at":"2024-07-31T17:00:53.917Z","updated_at":"2026-02-19T06:32:50.259Z","avatar_url":"https://github.com/anexia-it.png","language":"Python","funding_links":[],"categories":["Packages"],"sub_categories":["Authentication"],"readme":"# Django Rest Password Reset\n\n[![PyPI version](https://img.shields.io/pypi/v/django-rest-passwordreset.svg)](https://pypi.org/project/django-rest-passwordreset/)\n[![build-and-test actions status](https://github.com/anexia-it/django-rest-passwordreset/actions/workflows/test.yml/badge.svg)](https://github.com/anexia-it/django-rest-passwordreset/actions)\n[![Codecov](https://img.shields.io/codecov/c/gh/anexia-it/django-rest-passwordreset)](https://codecov.io/gh/anexia-it/django-rest-passwordreset)\n\nThis python package provides a simple password reset strategy for django rest framework, where users can request password \nreset tokens via their registered e-mail address.\n\nThe main idea behind this package is to not make any assumptions about how the token is delivered to the end-user (e-mail, text-message, etc...).\nInstead, this package provides a signal that can be reacted on (e.g., by sending an e-mail or a text message).\n\nThis package basically provides two REST endpoints:\n\n* Request a token\n* Verify (confirm) a token (and change the password)\n\n## Quickstart\n\n1. Install the package from pypi using pip:\n```bash\npip install django-rest-passwordreset\n```\n\n2. Add ``django_rest_passwordreset`` to your ``INSTALLED_APPS`` (after ``rest_framework``) within your Django settings file:\n```python\nINSTALLED_APPS = (\n    ...\n    'django.contrib.auth',\n    ...\n    'rest_framework',\n    ...\n    'django_rest_passwordreset',\n    ...\n)\n```\n\n3. This package stores tokens in a separate database table (see [django_rest_passwordreset/models.py](django_rest_passwordreset/models.py)). Therefore, you have to run django migrations:\n```bash\npython manage.py migrate\n```\n\n4. This package provides three endpoints, which can be included by including ``django_rest_passwordreset.urls`` in your ``urls.py`` as follows:\n```python\nfrom django.urls import path, include\n\nurlpatterns = [\n    ...\n    path(r'^api/password_reset/', include('django_rest_passwordreset.urls', namespace='password_reset')),\n    ...\n]\n```\n**Note**: You can adapt the URL to your needs.\n\n### Endpoints\n\nThe following endpoints are provided:\n\n * `POST ${API_URL}/` - request a reset password token by using the ``email`` parameter\n * `POST ${API_URL}/confirm/` - using a valid ``token``, the users password is set to the provided ``password``\n * `POST ${API_URL}/validate_token/` - will return a 200 if a given ``token`` is valid\n \nwhere `${API_URL}/` is the url specified in your *urls.py* (e.g., `api/password_reset/` as in the example above)\n\n \n### Signals\n\n* ``reset_password_token_created(sender, instance, reset_password_token)`` Fired when a reset password token is generated\n* ``pre_password_reset(sender, user, reset_password_token)`` - fired just before a password is being reset\n* ``post_password_reset(sender, user, reset_password_token)`` - fired after a password has been reset\n\n### Example for sending an e-mail\n\n1. Create two new django templates: `email/user_reset_password.html` and `email/user_reset_password.txt`. Those templates will contain the e-mail message sent to the user, aswell as the password reset link (or token).\nWithin the templates, you can access the following context variables: `current_user`, `username`, `email`, `reset_password_url`. Feel free to adapt this to your needs.\n\n2. Add the following code, which contains a Django Signal Receiver (`@receiver(...)`), to your application. Take care where to put this code, as it needs to be executed by the python interpreter (see the section *The `reset_password_token_created` signal is not fired* below, aswell as [this part of the django documentation](https://docs.djangoproject.com/en/1.11/topics/signals/#connecting-receiver-functions) and [How to Create Django Signals Tutorial](https://simpleisbetterthancomplex.com/tutorial/2016/07/28/how-to-create-django-signals.html) for more information).\n```python\nfrom django.core.mail import EmailMultiAlternatives\nfrom django.dispatch import receiver\nfrom django.template.loader import render_to_string\nfrom django.urls import reverse\n\nfrom django_rest_passwordreset.signals import reset_password_token_created\n\n\n@receiver(reset_password_token_created)\ndef password_reset_token_created(sender, instance, reset_password_token, *args, **kwargs):\n    \"\"\"\n    Handles password reset tokens\n    When a token is created, an e-mail needs to be sent to the user\n    :param sender: View Class that sent the signal\n    :param instance: View Instance that sent the signal\n    :param reset_password_token: Token Model Object\n    :param args:\n    :param kwargs:\n    :return:\n    \"\"\"\n    # send an e-mail to the user\n    context = {\n        'current_user': reset_password_token.user,\n        'username': reset_password_token.user.username,\n        'email': reset_password_token.user.email,\n        'reset_password_url': \"{}?token={}\".format(\n            instance.request.build_absolute_uri(reverse('password_reset:reset-password-confirm')),\n            reset_password_token.key)\n    }\n\n    # render email text\n    email_html_message = render_to_string('email/user_reset_password.html', context)\n    email_plaintext_message = render_to_string('email/user_reset_password.txt', context)\n\n    msg = EmailMultiAlternatives(\n        # title:\n        \"Password Reset for {title}\".format(title=\"Some website title\"),\n        # message:\n        email_plaintext_message,\n        # from:\n        \"noreply@somehost.local\",\n        # to:\n        [reset_password_token.user.email]\n    )\n    msg.attach_alternative(email_html_message, \"text/html\")\n    msg.send()\n\n```\n\n3. You should now be able to use the endpoints to request a password reset token via your e-mail address. \nIf you want to test this locally, I recommend using some kind of fake mailserver (such as maildump).\n\n\n\n# Configuration / Settings\n\nThe following settings can be set in Django ``settings.py`` file:\n\n* `DJANGO_REST_MULTITOKENAUTH_RESET_TOKEN_EXPIRY_TIME` - time in hours about how long the token is active (Default: 24)\n\n  **Please note**: expired tokens are automatically cleared based on this setting in every call of ``ResetPasswordRequestToken.post``.\n\n* `DJANGO_REST_PASSWORDRESET_NO_INFORMATION_LEAKAGE` - will cause a 200 to be returned on `POST ${API_URL}/reset_password/`\n  even if the user doesn't exist in the databse (Default: False) \n\n* `DJANGO_REST_MULTITOKENAUTH_REQUIRE_USABLE_PASSWORD` - allows password reset for a user that does not \n  [have a usable password](https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.has_usable_password) (Default: True)\n\n## Custom Email Lookup\n\nBy default, `email` lookup is used to find the user instance. You can change that by adding \n```python\nDJANGO_REST_LOOKUP_FIELD = 'custom_email_field'\n```\ninto Django settings.py file.\n\n## Custom Remote IP Address and User Agent Header Lookup\n\nIf your setup demands that the IP adress of the user is in another header (e.g., 'X-Forwarded-For'), you can configure that (using Django Request Headers):\n\n```python\nDJANGO_REST_PASSWORDRESET_IP_ADDRESS_HEADER = 'HTTP_X_FORWARDED_FOR'\n```\n\nThe same is true for the user agent:\n\n```python\nDJANGO_REST_PASSWORDRESET_HTTP_USER_AGENT_HEADER = 'HTTP_USER_AGENT'\n```\n\n## Custom Token Generator\n\nBy default, a random string token of length 10 to 50 is generated using the ``RandomStringTokenGenerator`` class.\nThis library offers a possibility to configure the params of ``RandomStringTokenGenerator`` as well as switch to\nanother token generator, e.g. ``RandomNumberTokenGenerator``. You can also generate your own token generator class.\n\nYou can change that by adding \n```python\nDJANGO_REST_PASSWORDRESET_TOKEN_CONFIG = {\n    \"CLASS\": ...,\n    \"OPTIONS\": {...}\n}\n```\ninto Django settings.py file.\n\n\n### RandomStringTokenGenerator\nThis is the default configuration. \n```python\nDJANGO_REST_PASSWORDRESET_TOKEN_CONFIG = {\n    \"CLASS\": \"django_rest_passwordreset.tokens.RandomStringTokenGenerator\"\n}\n```\n\nYou can configure the length as follows:\n```python\nDJANGO_REST_PASSWORDRESET_TOKEN_CONFIG = {\n    \"CLASS\": \"django_rest_passwordreset.tokens.RandomStringTokenGenerator\",\n    \"OPTIONS\": {\n        \"min_length\": 20,\n        \"max_length\": 30\n    }\n}\n```\n\nIt uses `os.urandom()` to generate a good random string.\n   \n\n### RandomNumberTokenGenerator\n```python\nDJANGO_REST_PASSWORDRESET_TOKEN_CONFIG = {\n    \"CLASS\": \"django_rest_passwordreset.tokens.RandomNumberTokenGenerator\"\n}\n```\n\nYou can configure the minimum and maximum number as follows:\n```python\nDJANGO_REST_PASSWORDRESET_TOKEN_CONFIG = {\n    \"CLASS\": \"django_rest_passwordreset.tokens.RandomNumberTokenGenerator\",\n    \"OPTIONS\": {\n        \"min_number\": 1500,\n        \"max_number\": 9999\n    }\n}\n```\n\nIt uses `random.SystemRandom().randint()` to generate a good random number.\n\n\n### Write your own Token Generator\n\nPlease see [token_configuration/django_rest_passwordreset/tokens.py](token_configuration/django_rest_passwordreset/tokens.py) for example implementation of number and string token generator.\n\nThe basic idea is to create a new class that inherits from BaseTokenGenerator, takes arbitrary arguments (`args` and `kwargs`)\nin the ``__init__`` function as well as implementing a `generate_token` function.\n\n```python\nfrom django_rest_passwordreset.tokens import BaseTokenGenerator\n\n\nclass RandomStringTokenGenerator(BaseTokenGenerator):\n    \"\"\"\n    Generates a random string with min and max length using os.urandom and binascii.hexlify\n    \"\"\"\n\n    def __init__(self, min_length=10, max_length=50, *args, **kwargs):\n        self.min_length = min_length\n        self.max_length = max_length\n\n    def generate_token(self, *args, **kwargs):\n        \"\"\" generates a pseudo random code using os.urandom and binascii.hexlify \"\"\"\n        # determine the length based on min_length and max_length\n        length = random.randint(self.min_length, self.max_length)\n\n        # generate the token using os.urandom and hexlify\n        return binascii.hexlify(\n            os.urandom(self.max_length)\n        ).decode()[0:length]\n```\n\n\n### Throttling\n\nThe endpoint to request a reset password token provides throttling.\nPer default the throttling rate is `3/day` per IP address.\n\nThe throttling rate can be customized using the `REST_FRAMEWORK` setting and the scope `\"django-rest-passwordreset-request-token\"`:\n\n```\nREST_FRAMEWORK = {\"DEFAULT_THROTTLE_RATES\": {\"django-rest-passwordreset-request-token\": \"5/hour\"}}\n```\n\nSee also: https://www.django-rest-framework.org/api-guide/throttling/#setting-the-throttling-policy\n\n\n## Compatibility Matrix\n\nThis library should be compatible with the latest Django and Django Rest Framework Versions. For reference, here is\na matrix showing the guaranteed and tested compatibility.\n\ndjango-rest-passwordreset Version | Django Versions     | Django Rest Framework Versions | Python |\n--------------------------------- |---------------------| ------------------------------ | ------ |\n0.9.7 | 1.8, 1.11, 2.0, 2.1 | 3.6 - 3.9 | 2.7\n1.0 | 1.11, 2.0, 2.2 | 3.6 - 3.9 | 2.7\n1.1 | 1.11, 2.2 | 3.6 - 3.9 | 2.7\n1.2 | 2.2, 3.0, 3.1 | 3.10, 3.11 | 3.5 - 3.8\n1.3 | 3.2, 4.0, 4.1 | 3.12, 3.13, 3.14 | 3.7 - 3.10\n1.4 | 3.2, 4.2, 5.0 | 3.13, 3.14 | 3.8 - 3.12\n1.5 | 4.2, 5.0, 5.1 | 3.15 | 3.9 - 3.13\n\n## Documentation / Browsable API\n\nThis package supports the [DRF auto-generated documentation](https://www.django-rest-framework.org/topics/documenting-your-api/) (via `coreapi`) as well as the [DRF browsable API](https://www.django-rest-framework.org/topics/browsable-api/).\n\nTo add the endpoints to the browsable API, you can use a helper function in your `urls.py` file:\n```python\nfrom rest_framework.routers import DefaultRouter\nfrom django_rest_passwordreset.urls import add_reset_password_urls_to_router\n\nrouter = DefaultRouter()\nadd_reset_password_urls_to_router(router, base_path='api/auth/passwordreset')\n```\n\nAlternatively you can import the ViewSets manually and customize the routes for your setup:\n```python\nfrom rest_framework.routers import DefaultRouter\nfrom django_rest_passwordreset.views import ResetPasswordValidateTokenViewSet, ResetPasswordConfirmViewSet, \\\n    ResetPasswordRequestTokenViewSet\n\nrouter = DefaultRouter()\nrouter.register(\n    r'api/auth/passwordreset/validate_token',\n    ResetPasswordValidateTokenViewSet,\n    basename='reset-password-validate'\n)\nrouter.register(\n    r'api/auth/passwordreset/confirm',\n    ResetPasswordConfirmViewSet,\n    basename='reset-password-confirm'\n)\nrouter.register(\n    r'api/auth/passwordreset/',\n    ResetPasswordRequestTokenViewSet,\n    basename='reset-password-request'\n)\n```\n\n![drf_browsable_email_validation](docs/browsable_api_email_validation.png \"Browsable API E-Mail Validation\")\n\n![drf_browsable_password_validation](docs/browsable_api_password_validation.png \"Browsable API E-Mail Validation\")\n\n![coreapi_docs](docs/coreapi_docs.png \"Core API Docs\")\n\n\n## Known Issues / FAQ\n\n### Django 2.1 Migrations - Multiple Primary keys for table ...\nDjango 2.1 introduced a breaking change for migrations (see [Django Issue #29790](https://code.djangoproject.com/ticket/29790)). We therefore had to rewrite the migration [0002_pk_migration.py](django_rest_passwordreset/migrations/0002_pk_migration.py) such that it covers Django versions before (`\u003c`) 2.1 and later (`\u003e=`) 2.1.\n\nSome information is written down in Issue #8.\n\n### The `reset_password_token_created` signal is not fired\nYou need to make sure that the code with `@receiver(reset_password_token_created)` is executed by the python interpreter. To ensure this, you have two options:\n\n1. Put the code at a place that is automatically loaded by Django (e.g., models.py, views.py), or\n\n2. Import the file that contains the signal within your app.py `ready` function:\n\n  *some_app/signals.py*\n  ```python\n  from django.core.mail import EmailMultiAlternatives\n  from django.dispatch import receiver\n  from django.template.loader import render_to_string\n  from django.urls import reverse\n\n  from django_rest_passwordreset.signals import reset_password_token_created\n\n\n  @receiver(reset_password_token_created)\n  def password_reset_token_created(sender, instance, reset_password_token, *args, **kwargs):\n      # ...\n  ```\n  \n  *some_app/app.py*\n  ```python\n  from django.apps import AppConfig\n\n  class SomeAppConfig(AppConfig):\n      name = 'your_django_project.some_app'\n      verbose_name = 'Some App'\n\n      def ready(self):\n          import your_django_project.some_app.signals  # noqa\n  ```\n  \n  *some_app/__init__.py*\n  ```python\n  default_app_config = 'your_django_project.some_app.SomeAppConfig'\n  ```\n\n### MongoDB not working\n\nApparently, the following piece of code in the Django Model prevents MongodB from working:\n\n```python\n id = models.AutoField( \n     primary_key=True \n ) \n```\n\nSee issue #49 for details.\n\n## Contributions\n\nThis library tries to follow the unix philosophy of \"do one thing and do it well\" (which is providing a basic password reset endpoint for Django Rest Framework). Contributions are welcome in the form of pull requests and issues! If you create a pull request, please make sure that you are not introducing breaking changes. \n\n## Tests\n\nSee folder [tests/](tests/). Basically, all endpoints are covered with multiple\nunit tests.\n\nFollow below instructions to run the tests.\nYou may exchange the installed Django and DRF versions according to your requirements. \n:warning: Depending on your local environment settings you might need to explicitly call `python3` instead of `python`.\n```bash\n# install dependencies\npython -m pip install --upgrade pip\npip install -r tests/requirements.txt\n\n# setup environment\npip install -e .\n\n# run tests\ncd tests \u0026\u0026 python manage.py test\n```\n\n## Release on PyPi\n\nTo release this package on pypi, the following steps are used:\n\n```bash\nrm -rf dist/ build/\npython setup.py sdist\ntwine upload dist/*\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanexia-it%2Fdjango-rest-passwordreset","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanexia-it%2Fdjango-rest-passwordreset","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanexia-it%2Fdjango-rest-passwordreset/lists"}