User-related REST API based on the awesome Django REST Framework

Overview

Django REST Registration

CircleCI Build Status Codecov Coverage PyPi Version Documentation Status

User registration REST API, based on Django REST Framework.

Documentation

Full documentation for the project is available at https://django-rest-registration.readthedocs.io/.

Requirements

  • Django (1.10+, 2.0+, 3.0+) and Django-REST-Framework (3.3+)
  • Python 3.4 or higher (no Python 2 support!)

Features

  • Supported views:
    • registration (sign-up) with verification
    • login/logout (sign-in), session- or token-based
    • user profile (retrieving / updating)
    • reset password
    • change password
    • register (change) e-mail
  • Views are compatible with django-rest-swagger
  • Views can be authenticated via session or auth token
  • Modeless (uses the user defined by settings.AUTH_USER_MODEL and also uses cryptographic signing instead of profile models)
  • Uses password validation
  • Heavily tested (Above 98% code coverage)

Current limitations

Installation & Configuration

You can install Django REST Registration latest version via pip:

pip install django-rest-registration

Then, you should add it to the INSTALLED_APPS so the app templates for notification emails can be accessed:

INSTALLED_APPS=(
    ...

    'rest_registration',
)

After that, you can use the urls in your urlconfig, for instance (using new Django 2.x syntax):

api_urlpatterns = [
    ...

    path('accounts/', include('rest_registration.api.urls')),
]


urlpatterns = [
    ...

    path('api/v1/', include(api_urlpatterns)),
]

In Django 1.x you can use old url instead of path.

You can configure Django REST Registraton using the REST_REGISTRATION setting in your Django settings (similarly to Django REST Framework).

Below is sample, minimal config you can provide in your django settings which will satisfy the system checks:

REST_REGISTRATION = {
    'REGISTER_VERIFICATION_ENABLED': False,
    'RESET_PASSWORD_VERIFICATION_ENABLED': False,
    'REGISTER_EMAIL_VERIFICATION_ENABLED': False,
}

However, the preferred base configuration would be:

REST_REGISTRATION = {
    'REGISTER_VERIFICATION_URL': 'https://frontend-host/verify-user/',
    'RESET_PASSWORD_VERIFICATION_URL': 'https://frontend-host/reset-password/',
    'REGISTER_EMAIL_VERIFICATION_URL': 'https://frontend-host/verify-email/',

    'VERIFICATION_FROM_EMAIL': '[email protected]',
}

The frontend urls are not provided by the library but should be provided by the user of the library, because Django REST Registration is frontend-agnostic. The frontend urls will receive parameters as GET query and should pass them to corresponding REST API views via HTTP POST request.

In case when any verification is enabled (which is the default!), your Django application needs to be properly configured so it can send e-mails.

You can read more about basic configuration here.

You can read more about detailed configuration here.

Configuration options

You can find all REST_REGISTRATION configuration options here.

Contributing

If you want to contribute, please refer to separate document CONTRIBUTING.md.

Comments
  • Token authentication with expiring token.

    Token authentication with expiring token.

    It would be a nice feature if rest-registration provides inbuilt token authentication with expiring token. JWT provides expiring tokens but handling logout with blacklisting token is a headache that I feel but in the case of expiring token, it doesn't need any blacklisting on logout. It will increase the strength of authentication with the token mechanism.

    type:feature-request 
    opened by itzmanish 11
  • Swagger does not pick up django-rest-registration endpoints.

    Swagger does not pick up django-rest-registration endpoints.

    So I did setup everything like we you have here in example, and it seems like django-rest-swagger does not pick endpoints.

    Here are my urls:

    from django.conf import settings
    from django.urls import path, re_path, include, reverse_lazy
    from django.conf.urls.static import static
    from django.contrib import admin
    from django.views.generic.base import RedirectView
    from rest_framework.routers import DefaultRouter
    from rest_framework.authtoken import views
    from .users.views import UserViewSet, UserCreateViewSet
    
    from rest_framework_swagger.views import get_swagger_view
    
    schema_view = get_swagger_view(title='Luken API')
    
    router = DefaultRouter()
    router.register(r'users', UserViewSet)
    router.register(r'users', UserCreateViewSet)
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('accounts/', include('rest_registration.api.urls')),
        path('api/v1/', include(router.urls)),
        path('api/swagger/', schema_view),
    
        re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)),
    
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    Here is the result.

    screen

    If you notice accounts are not being displayed.

    opened by polinom 10
  • Switch to class-based views

    Switch to class-based views

    Class-based views greatly simplify adding extra logic into views. I am therefore proposing to refactor the views into class-based views.

    Here are some examples why this is useful, at least as far as the user registration view is concerned:

    1.) For user registration, I would like to record the client IP address. This is best done in the register view, by calling serializer_class() with an extra context argument, like serializer_class(data=request.data, context={'request': request}). This way, the serializer can access self.context['request'].META.get('REMOTE_ADDR') and populate a field on the model instance it creates.

    As far as I can see, this is currently not possible, except by replacing the view by a copy of it and modifying it. This violates the DRY principle and is also detached from future upstream changes in this view.

    If the registration view was a class-based view inheriting from DRF's GenericAPIView (e.g. a CreateAPIView), the following few lines of code would be sufficient to solve this (assuming the upstream registration view is called DefaultRegisterUserView):

    class RegisterUserView(DefaultRegisterUserView):
        def get_serializer_context(self):
            return {'request': self.request}
    
    class RegisterUserSerializer(DefaultRegisterUserSerializer):
        def create(self, validated_data):
            data = validated_data.copy()
            data['registration_remote_ip'] = self.context['request'].META.get('REMOTE_ADDR')
            return super().create(data)
    

    ... plus the two lines in urls.py and settings.py where the view and the serializer are configured.

    2.) Also, one may consider changing the response of the registration view such that information like "user with this email exists" is not leaked. Instead, 202 Accepted could be an appropriate status code in all cases, with the view redirecting to the password reset view if the email address is already taken, and otherwise sending the regular registration verification email.

    (It would be the frontend's responsibility to react with a proper message, like "We have sent you an email with further instructions", which would be true in all cases.)

    This way, one could expose a unified register+reset endpoint which acts as a general "give me access to an account with this email address" endpoint. The frontend could of course present it in different variations for registration and for password reset purposes.

    I am not proposing that these endpoints be merged (that would be another interesting issue); I am rather making the point that if the registration endpoint was a class-based view, one could easily achieve the above with something like (rough sketch):

    class RegisterUserView(DefaultRegisterUserView):
        def post(request, *args, **kwargs):
            try:
                # Try to register user as usual
                return super().post(request, *args, *kwargs)
            except ValidationError as e:
                # Perform password reset if account exists
                email_error = e.message_dict.get('email')
                if email_error and email_error.endswith(' already exists.'):
                    return PasswortResetView.as_view()(request)
    
                # For other errors, continue as usual
                raise e
    
    type:feature-request release:next-major-version 
    opened by peterthomassen 9
  • *_VERIFICATION_EMAIL_TEMPLATES is invalid

    *_VERIFICATION_EMAIL_TEMPLATES is invalid

    I try to use the package without any TEMPLATES option. I've added in settings minimal REST_REGISTRATION config, but get REGISTER_EMAIL_/REGISTER_VERIFICATION_/RESET_PASSWORD_VERIFICATION_EMAIL_TEMPLATES is invalid (3 SystemCheck errors). Also I've tried to set this options in {}, '', None, but unsuccessfully. Minimal config to launch server:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'APP_DIRS': True,
        },
    ]
    

    Do I something wrong understand with using the package or Django..?

    type:question 
    opened by ruslankrivoshein 8
  • Using username instead of user_id in signer

    Using username instead of user_id in signer

    I am trying to use username instead of user_id. But i am getting this error File "/home/krishna/Projects/django/cms/account/views.py", line 79, in _calculate_salt if registration_settings.REGISTER_VERIFICATION_ONE_TIME_USE: File "/home/krishna/anaconda3/envs/django/lib/python3.7/site-packages/rest_registration/utils/nested_settings.py", line 38, in __getattr__ self=self, attr=attr)) AttributeError: Invalid REST_REGISTRATION setting: 'REGISTER_VERIFICATION_ONE_TIME_USE' However this is not related to username or userid data but yet i am getting this error. I tried to trackdown this error in nested_settings.py and settings_field.py but there is no problem.

    Also i am using whole view.py from rest-registration/api/views/register.py

    type:feature-request priority:high 
    opened by itzmanish 8
  • Verify email does not seems to behave like expected

    Verify email does not seems to behave like expected

    So I hit resgiter email and receive a following email:

    Please verify your account by clicking on this link:
    
    http://localhost:8000/verify-account/?user_id=cb185c07-143f-4d99-ac64-18a280e221ff&timestamp=1519787713&signature=4uB1gS9O32bPa7skbCvEh88XCec
    

    I want to activate this account, so I take user_id, timestamp signature and email address end send this to our POST /api/v1/accounts/verify-email/

    I get response:

    {
      "detail": "Invalid signature"
    }
    

    And btw,

    http://localhost:8000/verify-account/?user_id=cb185c07-143f-4d99-ac64-18a280e221ff&timestamp=1519787713&signature=4uB1gS9O32bPa7skbCvEh88XCec

    urls that i get in email is not working

    opened by polinom 8
  • Invalid Signature When Verifying Email Address and More Using Postman

    Invalid Signature When Verifying Email Address and More Using Postman

    Checklist

    • [X] I searched existing issues before opening this one
    • [X] I reproduced the bug with the newest version

    Describe the bug

    The views that require posting in a JSON body, such as verify-email, will fail with an Invalid Signature error when using Postman. This has been reported in some form in #11 and #42, but neither had a solution.

    Expected behavior

    Posting into these endpoints succeeds and returns a 2XX error code as expected, like it does with cURL.

    Actual behavior

    The problem appears to occur due to some temporary headers that Postman is setting. This problem has been reported with a number of APIs in other forms in https://community.getpostman.com/t/disable-temporary-headers/5271 and other tickets. After some testing, I believe it comes down to the "Accept-Encoding: gzip, deflate" header. When I include that one with cURL, I receive an error relating to binary data coming back or an invalid signature error. Excluding that single temporary header that Postman sets (which is not supported by the tool itself) allows the request to succeed.

    Steps to reproduce

    Steps to reproduce the behavior:

    1. Create a new request in Postman to POST to the verify-email endpoint with correct data
    2. Send the request and receive an error

    Diagnostic info

    (Please provide below contents of your Django settings.py file (after removing all sensitive information like secrets), or at least provide specific settings mentioned below)

    REST_REGISTRATION = {
        'REGISTER_VERIFICATION_URL': 'https://mysite.example/verify-user/',
        'RESET_PASSWORD_VERIFICATION_URL': 'https://mysite.example/reset-password/',
        'REGISTER_EMAIL_VERIFICATION_URL': 'https://mysite.example/verify-email/',
    
        'VERIFICATION_FROM_EMAIL': '[email protected]',
    
        # Excluding this and using the normal id field does not change the behavior
        'USER_VERIFICATION_ID_FIELD': 'uuid',
    }
    
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'knox.auth.TokenAuthentication',
        ),
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated'
        ],
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 25,
        'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
    }
    
    INSTALLED_APPS = (
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'api.apps.ApiConfig',
        'knox',
        'oauth2_provider',
        'rest_framework',
        'rest_registration',
        'rolepermissions',
        'simple_history',
    )
    

    Additional context

    I've also requested that Postman provide a method for excluding temporary headers because of this problem (as have many other people), but I'm not sure what their release timeframe is. Hopefully this is simpler to reproduce and fix on this end.

    type:bug 
    opened by beittenc 7
  • fix profile view with api renderer

    fix profile view with api renderer

    This is fix for bug, that occurs when using rest_framework.renderers.BrowsableAPIRenderer with profile view. It throws following error:

    Traceback (most recent call last):
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
        response = get_response(request)
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 158, in _get_response
        response = self.process_exception_by_middleware(e, request)
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 156, in _get_response
        response = response.render()
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/django/template/response.py", line 106, in render
        self.content = self.rendered_content
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/rest_framework/response.py", line 73, in rendered_content
        ret = renderer.render(self.data, accepted_media_type, context)
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/rest_framework/renderers.py", line 719, in render
        context = self.get_context(data, accepted_media_type, renderer_context)
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/rest_framework/renderers.py", line 652, in get_context
        raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request)
      File "/home/petr/soubory/programovani/climboard/env/lib/python3.6/site-packages/rest_framework/renderers.py", line 555, in get_raw_data_form
        serializer = view.get_serializer(instance=instance)
    TypeError: _get_serializer() got an unexpected keyword argument 'instance'
    
    opened by PetrDlouhy 7
  • Why is there a check for a specific backend?

    Why is there a check for a specific backend?

    At some point a check for a specific authentication backend was introduced. I get this error message:

    django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:
    
    ERRORS:
    ?: (rest_registration.E014) invalid authentication backends configuration: LOGIN_DEFAULT_SESSION_AUTHENTICATION_BACKEND is not in AUTHENTICATION_BACKENDS
    

    I implemented my own authentication backend but use rest-registration for the signup process. This error prevents me from upgrading django to a more recent version and is also very restraining. People should be able to use the rest-registration package standalone without it being opinionated about which authentication backend to use.

    This could be changed to a warning to indicate that if you have a problem, you should look into the authentication backends setting.

    type:bug state:needs-answer 
    opened by saevarom 6
  • Return user profile after successful login

    Return user profile after successful login

    With my custom login view I get the user data after successful login via the login endpoint. Unfortunately with django-rest-registration all I get is:

    { "detail": "Login successful" }

    Which means that I have to make another request to the profile endpoint to completely login a user in my frontend. Is this how it should be done? It seems unnecessary to do 2 request if it could be done in one. Curious to hear how others handle this.

    type:feature-request 
    opened by kris7ian 6
  • Default register output serializer should include a token when appropriate

    Default register output serializer should include a token when appropriate

    If the client does not get an AuthToken after registration, the user must provide credentials immediately after registering.

    I was able to add a token to the default serializer with the following custom serializer, but the token should really be created in the view instead.

    from rest_registration.api.serializers import DefaultUserProfileSerializer
    from rest_framework import serializers
    from rest_framework.authtoken.models import Token
    
    
    class MyRegistrationSerializer(DefaultUserProfileSerializer):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.Meta.fields += ('token',)
    
        token = serializers.SerializerMethodField()
    
        def get_token(self, user):
            token = Token.objects.create(user=user)
            return token.key
    

    and in settings.py:

    REST_REGISTRATION = {
    # ...
        'REGISTER_OUTPUT_SERIALIZER_CLASS': '...MyRegistrationSerializer',
    }
    
    closed-as:wontfix 
    opened by ckeeney 6
  • Allow superuser to not be verified

    Allow superuser to not be verified

    Description

    This PR aims to fix #144: when a custom flag field is used, and one tries to change the email of a superuser created by createsuperuser whose flag field is not enabled.

    The strategy employed is to disable user verification in rest_registration.utils.users.get_user_by_lookup_dict if the requested user is a superuser (i.e. is_superuser is True). In other words, a superuser can be unverified.

    Two tests check if, when setting a custom flag field, the email address can be changed for an unverified superuser, and cannot be changed for an unverified normal user.

    Improvements

    Disabling user verification could be made optional. Either with an extra argument to the function (required_verified_superuser defaults to False), or with a settings (SUPERUSER_MUST_BE_VALIDATED defaults to False).

    Why the change is needed?

    See #144.

    Related issues, pull requests, links

    #144

    opened by Neraste 0
  • Cannot change superuser email when using custom flag field and createsuperuser

    Cannot change superuser email when using custom flag field and createsuperuser

    Describe the bug

    I changed the default flag field with USER_VERIFICATION_FLAG_FIELD and created a superuser with the Django command createsuperuser. Changing this superuser's email results in an error when verifying the email.

    Expected behavior

    Superuser email is changed.

    Actual behavior

    Error 400 with the error message: "User not found."

    Steps to reproduce

    1. Create a Boolean field in user model and set USER_VERIFICATION_FLAG_FIELD to this field;
    2. Create a superuser with Django admin command createsuperuser;
    3. Register a new mail for this superuser;
    4. Validate the new email.

    Possible explanation

    This is due to the fact createsuperuser will not enable the custom flag field (as it sets username, email and password by default), hence this superuser is not considered as valid and cannot be retrieved.

    In rest_registration.api.views.register_email.process_verify_email_data, get_user_by_verification_id is called with argument require_verified True by default.

    Associated PR

    See #145.

    type:bug 
    opened by Neraste 3
  • Differentiate bad signature from already used signatures

    Differentiate bad signature from already used signatures

    Checklist

    • [x] I read Contribution Guidelines
    • [x] I searched the documentation to ensure that the requested feature is not already implemented and described
    • [x] I searched existing issues before opening this one

    Is your feature request related to a problem? Please describe.

    From what I read in the source code there are no specific exception when a signature had already been used. It just raise a BadSignature: https://github.com/apragacz/django-rest-registration/blob/master/rest_registration/utils/verification.py#L9 This is because the salt used is not the same after the account had been registered and from the comments this seems by design: https://github.com/apragacz/django-rest-registration/blob/master/rest_registration/api/views/register.py#L46

    The problem is it can lead to a bad user experience. For example, in our setup we have REGISTER_VERIFICATION_AUTO_LOGIN and REGISTER_VERIFICATION_ONE_TIME_USE enabled. If a user follows the verification link on a device, he got registered and logged in. Later on he follows the link on an other device and here we are only able to show a generic error message: "The link is invalid."

    Describe the solution you'd like

    • We would like a specific exception to be raised like SignatureAlreadyUsed OR
    • if there was a way to override the verify_registration endpoint we could first check if a user is verified and if not go on with the usual verification

    In both cases this will allow us to display a relevant error message to our users like "You are already verified, please log in"

    Describe alternatives you've considered

    We tried to enable REGISTER_VERIFICATION_AUTO_LOGIN and disable REGISTER_VERIFICATION_ONE_TIME_USE but this leads to this error:

    REGISTER_VERIFICATION_AUTO_LOGIN is enabled, but REGISTER_VERIFICATION_ONE_TIME_USE is not enabled. This can allow multiple logins using the verification url.

    This is indeed not ideal for security.

    type:feature-request state:research priority:low 
    opened by ppawlak 1
Releases(0.7.3)
Google Auth Python Library

Google Auth Python Library This library simplifies using Google's various server-to-server authentication mechanisms to access Google APIs. Installing

Google APIs 598 Jan 07, 2023
JSON Web Token Authentication support for Django REST Framework

REST framework JWT Auth JSON Web Token Authentication support for Django REST Framework Overview This package provides JSON Web Token Authentication s

Styria Digital Development 178 Jan 02, 2023
Simplifying third-party authentication for web applications.

Velruse is a set of authentication routines that provide a unified way to have a website user authenticate to a variety of different identity provider

Ben Bangert 253 Nov 14, 2022
A generic, spec-compliant, thorough implementation of the OAuth request-signing logic

OAuthLib - Python Framework for OAuth1 & OAuth2 *A generic, spec-compliant, thorough implementation of the OAuth request-signing logic for Python 3.5+

OAuthlib 2.5k Jan 01, 2023
Django-registration (redux) provides user registration functionality for Django websites.

Description: Django-registration provides user registration functionality for Django websites. maintainers: Macropin, DiCato, and joshblum contributor

Andrew Cutler 920 Jan 08, 2023
Simple Login - Login Extension for Flask - maintainer @cuducos

Login Extension for Flask The simplest way to add login to flask! Top Contributors Add yourself, send a PR! How it works First install it from PyPI. p

Flask Extensions 181 Jan 01, 2023
Flask App With Login

Flask App With Login by FranciscoCharles Este projeto basico é o resultado do estudos de algumas funcionalidades do micro framework Flask do Python. O

Charles 3 Nov 14, 2021
Python library for generating a Mastercard API compliant OAuth signature.

oauth1-signer-python Table of Contents Overview Compatibility References Usage Prerequisites Adding the Library to Your Project Importing the Code Loa

23 Aug 01, 2022
Todo app with authentication system.

todo list web app with authentication system. User can register, login, logout. User can login and create, delete, update task Home Page here you will

Anurag verma 3 Aug 18, 2022
Django Rest Framework App wih JWT Authentication and other DRF stuff

Django Queries App with JWT authentication, Class Based Views, Serializers, Swagger UI, CI/CD and other cool DRF stuff API Documentaion /swagger - Swa

Rafael Salimov 4 Jan 29, 2022
Quick and simple security for Flask applications

Note This project is non maintained anymore. Consider the Flask-Security-Too project as an alternative. Flask-Security It quickly adds security featur

Matt Wright 1.6k Dec 19, 2022
Web authentication testing framework

What is this This is a framework designed to test authentication for web applications. While web proxies like ZAProxy and Burpsuite allow authenticate

OWASP 88 Jan 01, 2023
Library - Recent and favorite documents

Thingy Thingy is used to quickly access recent and favorite documents. It's an XApp so it can work in any distribution and many desktop environments (

Linux Mint 23 Sep 11, 2022
Extending the Django authentication system with a phone verification step.

Extending the Django authentication system with a phone verification step.

Miguel Grinberg 50 Dec 04, 2022
Per object permissions for Django

django-guardian django-guardian is an implementation of per object permissions [1] on top of Django's authorization backend Documentation Online docum

3.3k Jan 01, 2023
Alisue 299 Dec 06, 2022
This Python based program checks your CC Stripe Auth 1$ Based Checker

CC-Checker This Python based program checks your CC Stripe Auth 1$ Based Checker About Author Coded by xBlackx Reach Me On Telegram @xBlackx_Coder jOI

xBlackxCoder 11 Nov 20, 2022
Auth-Starters - Different APIs using Django & Flask & FastAPI to see Authentication Service how its work

Auth-Starters Different APIs using Django & Flask & FastAPI to see Authentication Service how its work, and how to use it. This Repository based on my

Yasser Tahiri 7 Apr 22, 2022
Object Moderation Layer

django-oml Welcome to the documentation for django-oml! OML means Object Moderation Layer, the idea is to have a mixin model that allows you to modera

Angel Velásquez 12 Aug 22, 2019
Djagno grpc authentication service with jwt auth

Django gRPC authentication service STEP 1: Install packages pip install -r requirements.txt STEP 2: Make migrations and migrate python manage.py makem

Saeed Hassani Borzadaran 3 May 16, 2022