{"id":27243744,"url":"https://github.com/hire-abroad/jwt-passwordless","last_synced_at":"2026-02-28T07:04:57.764Z","repository":{"id":286789151,"uuid":"962015172","full_name":"Hire-Abroad/jwt-passwordless","owner":"Hire-Abroad","description":"A Django Rest Framework package that uses JWT tokens for passwordless authentication.","archived":false,"fork":false,"pushed_at":"2025-04-11T02:55:08.000Z","size":115,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-04-12T01:40:49.601Z","etag":null,"topics":["django","django-rest-framework","jwt","passwordless-authentication"],"latest_commit_sha":null,"homepage":"","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/Hire-Abroad.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2025-04-07T14:15:36.000Z","updated_at":"2025-04-11T02:55:11.000Z","dependencies_parsed_at":"2025-04-12T00:27:51.174Z","dependency_job_id":null,"html_url":"https://github.com/Hire-Abroad/jwt-passwordless","commit_stats":null,"previous_names":["hire-abroad/jwt-drf-passwordless","hire-abroad/jwt-passwordless"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hire-Abroad%2Fjwt-passwordless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hire-Abroad%2Fjwt-passwordless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hire-Abroad%2Fjwt-passwordless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hire-Abroad%2Fjwt-passwordless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hire-Abroad","download_url":"https://codeload.github.com/Hire-Abroad/jwt-passwordless/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248663206,"owners_count":21141712,"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","jwt","passwordless-authentication"],"created_at":"2025-04-10T20:58:23.083Z","updated_at":"2026-02-28T07:04:57.759Z","avatar_url":"https://github.com/Hire-Abroad.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JWT Passwordless\n\n[![PyPI version](https://badge.fury.io/py/jwt-passwordless.svg)](https://pypi.org/project/jwt-passwordless/)\n\n\nA Django REST Framework package that makes implementing passwordless authentication with JWT tokens simple and secure.\n\nThis package is a fork of [django-rest-framework-passwordless](https://github.com/aaronn/django-rest-framework-passwordless) by Aaron Ng, which hasn't been maintained for a couple of years. This fork adds JWT support and several other improvements while maintaining the same core functionality.\n\n### This package is actively maintained by the Hire Abroad tech team and is used in production across Hire Abroad projects.\n\n## Why JWT Passwordless?\n\nPasswordless authentication improves user experience and security by eliminating password management. Users receive a short-lived token via email or SMS, which they can exchange for a JWT token to authenticate in your application.\n\n### Key Differences from Original Repository\n\nThis fork introduces several important improvements over the original repository:\n\n1. **JWT Authentication**: Uses `djangorestframework-simplejwt` instead of DRF's TokenAuthentication for more flexible token-based auth with no server-side storage requirements\n2. **Configurable Token Length**: Token length can be customized (3-6 digits) through settings\n3. **Improved Test Coverage**: More comprehensive testing for better reliability\n4. **Fixed Custom Field Bug**: The original repository had a bug where custom email field names worked only in signals but not in other parts of the code (it used hardcoded \"email\" field in many places). This fork ensures that custom field names work consistently throughout the codebase\n5. **Fixed OTP Invalidation Logic**: In the original package, only OTPs generated within the user-defined token lifetime were invalidated—leaving older expired OTPs still active in the system. Over time, this led to a buildup of stale tokens, which could eventually exhaust the pool of possible unique OTPs. As a result, the system could collapse or fail to generate a new OTP once all possible unique values were taken. This fork resolves the issue by properly invalidating all expired OTPs, ensuring that the system can reliably generate new, unique codes.\n### Key Benefits\n\n- 🔒 **Enhanced Security**: No passwords to be hacked, phished, or forgotten\n- 🌐 **Better User Experience**: Frictionless sign-in experience without password frustrations\n- 🔄 **Seamless JWT Integration**: Works with Django REST Framework's JWT authentication\n- 📱 **Multiple Channels**: Support for both email and mobile authentication\n- ✅ **Verification Tracking**: Built-in support for tracking verified emails/phones\n\n\n## Installation\n\n### From PyPI\n\n```bash\npip install jwt-passwordless\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/Hire-Abroad/jwt-drf-passwordless.git\ncd jwt-drf-passwordless\npip install -e .\n```\n\n\u003e **Note**: If you're familiar with the original `drfpasswordless` package, note that this package uses different import names (`jwt_passwordless` instead of `drfpasswordless`)\n\n## Quick Start\n\n### 1. Add to INSTALLED_APPS in settings.py\n\n```python\nINSTALLED_APPS = [\n    # ...\n    'rest_framework',\n    'rest_framework_simplejwt',  # Required for JWT functionality\n    'jwt_passwordless',\n    # ...\n]\n```\n\n### 2. Include the URLs in your project\n\n```python\nfrom django.urls import path, include\n\nurlpatterns = [\n    # ...\n    path('api/', include('jwt_passwordless.urls', namespace='jwt_passwordless')),\n    # ...\n]\n```\n\n### 3. Configure Settings in settings.py\n\n```python\nPASSWORDLESS_AUTH = {\n    # Authentication types - 'EMAIL', 'MOBILE', or both\n    'PASSWORDLESS_AUTH_TYPES': ['EMAIL'],\n    \n    # Token expiry time in seconds (default: 15 minutes)\n    'PASSWORDLESS_TOKEN_EXPIRE_TIME': 15 * 60,\n    \n    # Email settings\n    'PASSWORDLESS_EMAIL_NOREPLY_ADDRESS': 'noreply@example.com',\n    'PASSWORDLESS_EMAIL_SUBJECT': \"Your Login Token\",\n    'PASSWORDLESS_EMAIL_PLAINTEXT_MESSAGE': \"Enter this token to sign in: %s\",\n    \n    # Optional: customize token length (3-6 digits)\n    'PASSWORDLESS_TOKEN_LENGTH': 6,\n    \n    # Optional: Mark email as verified after successful authentication\n    'PASSWORDLESS_USER_MARK_EMAIL_VERIFIED': True,\n    'PASSWORDLESS_USER_EMAIL_VERIFIED_FIELD_NAME': 'email_verified',\n    \n    # Optional: For SMS authentication\n    # 'PASSWORDLESS_AUTH_TYPES': ['EMAIL', 'MOBILE'],\n    # 'PASSWORDLESS_MOBILE_NOREPLY_NUMBER': '+15551234567',\n    # 'PASSWORDLESS_MOBILE_MESSAGE': \"Your login code is: %s\",\n}\n\n# Configure djangorestframework-simplejwt (optional but recommended)\nfrom datetime import timedelta\nSIMPLE_JWT = {\n    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),\n    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),\n    # ... other JWT settings\n}\n\n# Required if using mobile authentication with Twilio\n# import os\n# os.environ['TWILIO_ACCOUNT_SID'] = 'your-account-sid'\n# os.environ['TWILIO_AUTH_TOKEN'] = 'your-auth-token'\n```\n\n## Usage\n\n### Email Authentication Flow\n\n1. **Request a token**:\n   ```http\n   POST /api/auth/email/\n   {\"email\": \"user@example.com\"}\n   ```\n\n2. **System sends a token to the user's email**\n\n3. **Exchange token for JWT**:\n   ```http\n   POST /api/auth/token/\n   {\"email\": \"user@example.com\", \"token\": \"123456\"}\n   ```\n\n4. **Receive JWT tokens**:\n   ```json\n   {\n     \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\",\n     \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\"\n   }\n   ```\n\n5. **Use the JWT token for authentication**:\n   ```http\n   GET /api/some-protected-endpoint/\n   Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...\n   ```\n\n### Mobile Authentication Flow\n\nSimilar to email flow but using mobile endpoints:\n\n1. **Request a token**:\n   ```http\n   POST /api/auth/mobile/\n   {\"mobile\": \"+15551234567\"}\n   ```\n\n2. **System sends a token to the user's mobile number**\n\n3. **Exchange token for JWT**:\n   ```http\n   POST /api/auth/token/\n   {\"mobile\": \"+15551234567\", \"token\": \"123456\"}\n   ```\n\n## Advanced Configuration\n\n\n\n### Custom Field Names\n\nYou can customize the field names used for email and mobile authentication:\n\n```python\nPASSWORDLESS_AUTH = {\n    # ...\n    'PASSWORDLESS_USER_EMAIL_FIELD_NAME': 'email',  # Default is 'email'\n    'PASSWORDLESS_USER_MOBILE_FIELD_NAME': 'phone',  # If your field is named 'phone' instead of 'mobile'\n    # ...\n}\n```\n\n### Custom Callbacks\n\nYou can customize how tokens are sent by providing your own callback functions:\n\n```python\nPASSWORDLESS_AUTH = {\n    # ...\n    'PASSWORDLESS_EMAIL_CALLBACK': 'myapp.utils.send_custom_email_with_callback_token',\n    'PASSWORDLESS_SMS_CALLBACK': 'myapp.utils.send_custom_sms_with_callback_token',\n    # ...\n}\n```\n\n### Customizing Token Creation\n\nYou can customize how JWT tokens are created and serialized:\n\n```python\nPASSWORDLESS_AUTH = {\n    # ...\n    'PASSWORDLESS_AUTH_TOKEN_CREATOR': 'myapp.utils.create_custom_jwt_token_for_user',\n    'PASSWORDLESS_AUTH_TOKEN_SERIALIZER': 'myapp.serializers.CustomJWTTokenResponseSerializer',\n    # ...\n}\n```\n\n\n## Security Considerations\n\n- **Token Expiration**: Tokens are designed to expire quickly (default: 15 minutes)\n- **Token Invalidation**: Creating a new token invalidates previous tokens\n- **Verified Status**: Email/mobile verified status is tracked and updated\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n\n## Contact\n\nHire Abroad - contact@hireabroad.com\n\nProject Link: [https://github.com/Hire-Abroad/jwt-passwordless](https://github.com/Hire-Abroad/jwt-passwordless)  \nOriginal Project: [https://github.com/aaronn/django-rest-framework-passwordless](https://github.com/aaronn/django-rest-framework-passwordless)\n\n---\n\nMade by [Hire Abroad tech team](https://github.com/Hire-Abroad)  \nOriginal package by [Aaron Ng](https://github.com/aaronn)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhire-abroad%2Fjwt-passwordless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhire-abroad%2Fjwt-passwordless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhire-abroad%2Fjwt-passwordless/lists"}