{"id":15785683,"url":"https://github.com/sergioisidoro/djoser-passwordless","last_synced_at":"2025-03-14T11:30:26.075Z","repository":{"id":156328385,"uuid":"632036674","full_name":"sergioisidoro/djoser-passwordless","owner":"sergioisidoro","description":"A Passwordless login add-on for Djoser (Django Rest Framework authentication). Built with djoser, django-sms and django-phonenumber-field","archived":false,"fork":false,"pushed_at":"2023-05-04T20:46:00.000Z","size":69,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-05T20:41:14.013Z","etag":null,"topics":["django","django-rest-framework","otp","passwordless","passwordless-authentication","passwordless-login"],"latest_commit_sha":null,"homepage":"https://github.com/sergioisidoro/djoser-passwordless","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sergioisidoro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/contributing.rst","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}},"created_at":"2023-04-24T15:19:21.000Z","updated_at":"2024-08-28T10:20:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"a1acac7a-b78c-4312-b0b8-b927e6e72e05","html_url":"https://github.com/sergioisidoro/djoser-passwordless","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergioisidoro%2Fdjoser-passwordless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergioisidoro%2Fdjoser-passwordless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergioisidoro%2Fdjoser-passwordless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergioisidoro%2Fdjoser-passwordless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sergioisidoro","download_url":"https://codeload.github.com/sergioisidoro/djoser-passwordless/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243568995,"owners_count":20312344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","otp","passwordless","passwordless-authentication","passwordless-login"],"created_at":"2024-10-04T20:41:08.039Z","updated_at":"2025-03-14T11:30:26.064Z","avatar_url":"https://github.com/sergioisidoro.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"**⛔️ WORK IN PROGRESS - not yet released**\n![Main status](https://github.com/sergioisidoro/djoser-passwordless/actions/workflows/test-suite.yml/badge.svg)\n[![codecov](https://codecov.io/gh/sergioisidoro/djoser-passwordless/branch/main/graph/badge.svg?token=96USU05I2T)](https://codecov.io/gh/sergioisidoro/djoser-passwordless)\n\n# Djoser passwordless\nA Passwordless login add-on for Djoser (Django Rest Framework authentication). Built with `djoser`, `django-sms` and `django-phonenumber-field`\n\n## 🔑 Before you start!\nPlease consider your risk and threat landscape before adopting this library. \n\nAuthentication is always a trade-off of usability and security. This library has been built to give you the power to adjust those trade-offs as much as possible, and made an attempt to give you a reasonable set of defaults, but it's up to you to make those decisions. Please consider the following risks bellow \n\n## Installation \n```.sh\npip install djoser_passwordless\n```\n\n`settings.py`\n```.py\nINSTALLED_APPS = (\n    ...\n    \"djoser\",\n    \"djoser_passwordless\",\n    ...\n)\n...\nDJOSER_PASSWORDLESS = {\n    \"ALLOWED_PASSWORDLESS_METHODS\": [\"EMAIL\", \"MOBILE\"]\n}\n```\n**Remember to set the settings for `django-sms` and `django-phonenumber-field`** if you are using mobile token requests\n\n```\nurlpatterns = (\n    ...\n    re_path(r\"^passwordless/\", include(\"djoser_passwordless.urls\")),\n    ...\n)\n```\n\n## 🕵️ Risks \n### Brute force\nAlthough token requests are throttled by default, and token lifetime is limited, if you know a user email/phone it is possible to continuously request tokens (the default throttle is 1 minute), and try to brute force that token during the token lifetime (10 minutes).\n\n#### Mitigations\n* Set `INCORRECT_SHORT_TOKEN_REDEEMS_TOKEN` to `True`, so that any attempts at redeeming a token from an account will count as a user (`MAX_TOKEN_USES` is default set to 1) - **Tradeoff** is that if a user is being a victim of brute force attack, they will not be able to login with passwordless tokens, since it's likely the attacker will exhaust the token uses with failed attempts \n\n* Set `DECORATORS.token_redeem_rate_limit_decorator` or `DECORATORS.token_request_rate_limit_decorator` with your choice of request throttling library. - **Tradeoff** is that if there is an attacker hitting your service, you might prevent **any** user from logging in because someone is hitting this endpoint, so beware how you implement it. Note that because request limiting usually requires a key value db like redis, it is explicitly left out of this project to reduce it's dependencies and configuration needs.\n\n## Features\n* International phone number validation and standardization (expects db phone numbers to be in same format)\n* Basic throttling\n* Configurable tokens\n* Short (for SMS) and long tokens for magic links\n* Configurable serializers, permissions and decorators.\n\n## URLs and Examples:\n\n#### Available URLS\n* `request/email/`\n* `request/mobile`\n* `exchange/standalone/`\n* `exchange/email/`\n* `exchange/mobile/`\n\n**Requesting a token**\n```.sh\ncurl --request POST \\\n  --url http://localhost:8000/passwordless/request/email/ \\\n  --data '{\n\t\"email\": \"sergioisidoro@example.com\"\n}'\n```\nResponse\n```.json\n{\n\t\"detail\": \"A token has been sent to you\"\n}\n```\n\n**Exchanging a one time token for a auth token**\n```.sh\ncurl --request POST \\\n  --url http://localhost:8000/passwordless/exchange/ \\\n  --data '{\n\t\"email\": \"sergioisidoro@example.com\"\n\t\"token\": \"902488\"\n}'\n```\n```.json\n{\n\t\"auth_token\": \"3b8e6a2aed0435f95495e728b0fb41d0367a872d\"\n}\n```\n\n## Config\n\n#### Basic configuration\n\n* `ALLOWED_PASSWORDLESS_METHODS` (default=[\"email\"]) - Which methods can be used to request a token? (Valid - `[\"email\", \"mobile\"]`)\n* `EMAIL_FIELD_NAME` (default=\"email\") - Name of the user field that holds the email info\n* `MOBILE_FIELD_NAME` (default=\"phone_number\") - Name of the user field that holds phone number info\n* `SHORT_TOKEN_LENGTH` (default=6) - The length of the short tokens\n* `LONG_TOKEN_LENGTH` (default=64) - The length of the tokens that can redeemed standalone (without the original request data)\n* `SHORT_TOKEN_CHARS` (default=\"0123456789\") - The characters to be used when generating the short token\n* `LONG_TOKEN_CHARS` (default=\"abcdefghijklmnopqrstuvwxyz0123456789\") - Tokens used to generate the long token\n* `TOKEN_LIFETIME` (default=600) - Number of seconds the token is valid\n* `MAX_TOKEN_USES` (default=1) - How many times a token can be used - This can be adjusted because some email clients try to follow links, and might accidentally use tokens.\n* `TOKEN_REQUEST_THROTTLE_SECONDS` - (default=60) - How many seconds to wait before allowing a new token to be issued for a particular user\n* `ALLOW_ADMIN_AUTHENTICATION` (default=False) - Allow admin users to login without password (checks `is_admin` and `is_staff` from Django `AbstractUser`)\n* `REGISTER_NONEXISTENT_USERS` (default=False) - Register users who do not have an account and request a passwordless login token? - Will generate a random username which is configurable (See. conf.py)\n* `REGISTRATION_SETS_UNUSABLE_PASSWORD` (Default=True) - When unusable password is set, users cannot reset passwords via the normal Django flows. This means users registered via passwordless cannot login through password.\n* `INCORRECT_SHORT_TOKEN_REDEEMS_TOKEN` (default=False) - Should incorrect short token auth attempts count to the uses of a token? When set to true, together with `MAX_TOKEN_USES` to 1, this means a token has only one shot at being used.\n* `PASSWORDLESS_EMAIL_LOGIN_URL` (default=None) - URL template for the link redeeming the standalone link: eg `my-app://page/{token}`\n\n\n## Credits\nThis package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.\n\n* Aaronn's `django-rest-framework-passwordless` project https://github.com/aaronn/django-rest-framework-passwordless\n* Sunscrapers' Djoser project - https://github.com/sunscrapers/djoser\n* Cookiecutter: https://github.com/audreyr/cookiecutter\n* `audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage\n\n## License\n* Free software: MIT license\n* Do no harm","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergioisidoro%2Fdjoser-passwordless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsergioisidoro%2Fdjoser-passwordless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergioisidoro%2Fdjoser-passwordless/lists"}