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)
Authentication Module for django rest auth

django-rest-knox Authentication Module for django rest auth Knox provides easy to use authentication for Django REST Framework The aim is to allow for

James McMahon 878 Jan 04, 2023
CheckList-Api - Created with django rest framework and JWT(Json Web Tokens for Authentication)

CheckList Api created with django rest framework and JWT(Json Web Tokens for Aut

shantanu nimkar 1 Jan 24, 2022
Skit-auth - Authorization for skit.ai's platform

skit-auth This is a simple authentication library for Skit's platform. Provides

Skit 3 Jan 08, 2022
API-key based security utilities for FastAPI, focused on simplicity of use

FastAPI simple security API key based security package for FastAPI, focused on simplicity of use: Full functionality out of the box, no configuration

Tolki 154 Jan 03, 2023
A module making it easier to manage Discord oAuth with Quart

quart_discord A module making it easier to manage Discord oAuth with Quart Install pip install git+https://github.com/xelA/ 5 Oct 27, 2022

python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

1k Dec 22, 2022
Social auth made simple

Python Social Auth Python Social Auth is an easy-to-setup social authentication/registration mechanism with support for several frameworks and auth pr

Matías Aguirre 2.8k Dec 24, 2022
Awesome Django authorization, without the database

rules rules is a tiny but powerful app providing object-level permissions to Django, without requiring a database. At its core, it is a generic framew

1.6k Dec 30, 2022
Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes

Flask-HTTPAuth Simple extension that provides Basic and Digest HTTP authentication for Flask routes. Installation The easiest way to install this is t

Miguel Grinberg 1.1k Jan 05, 2023
A simple model based API maker written in Python and based on Django and Django REST Framework

Fast DRF Fast DRF is a small library for making API faster with Django and Django REST Framework. It's easy and configurable. Full Documentation here

Mohammad Ashraful Islam 18 Oct 05, 2022
Multi-user accounts for Django projects

django-organizations Summary Groups and multi-user account management Author Ben Lopatin (http://benlopatin.com) Status Separate individual user ident

Ben Lopatin 1.1k Jan 02, 2023
Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator.

Django Admin Two-Factor Authentication Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator. Why Django

Iman Karimi 9 Dec 07, 2022
A Login/Registration GUI Application with SQLite database for manipulating data.

Login-Register_Tk A Login/Registration GUI Application with SQLite database for manipulating data. What is this program? This program is a GUI applica

Arsalan 1 Feb 01, 2022
Authentication with fastapi and jwt cd realistic

Authentication with fastapi and jwt cd realistic Dependencies bcrypt==3.1.7 data

Fredh Macau 1 Jan 04, 2022
examify-io is an online examination system that offers automatic grading , exam statistics , proctoring and programming tests , multiple user roles

examify-io is an online examination system that offers automatic grading , exam statistics , proctoring and programming tests , multiple user roles ( Examiner , Supervisor , Student )

Ameer Nasser 4 Oct 28, 2021
Login-python - Login system made in Python, using native libraries

login-python Sistema de login feito 100% em Python, utilizando bibliotecas nativ

Nicholas Gabriel De Matos Leal 2 Jan 28, 2022
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
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
A secure authentication module to validate user credentials in a Streamlit application.

Streamlit-Authenticator A secure authentication module to validate user credentials in a Streamlit application. Installation Streamlit-Authenticator i

M Khorasani 336 Dec 31, 2022
A JOSE implementation in Python

python-jose A JOSE implementation in Python Docs are available on ReadTheDocs. The JavaScript Object Signing and Encryption (JOSE) technologies - JSON

Michael Davis 1.2k Dec 28, 2022