I am completely confused by the django middleware available:

I simply want to get password-reset (and later password-change) functionality running, using `django` with `rest_auth` on the backend and Vue on the frontend.

Step 1: Requesting the Reset-Link via Mail
==========================================

### Views

So far I have made a `CustomPasswordResetView`:

```py
# project/accounts/views.py
from rest_auth.views import PasswordResetView

class CustomPasswordResetView(PasswordResetView):
pass

```

### Serializers

and a `CustomPasswordResetSerializer`:

```py
# project/accounts/serializers.py
from rest_auth.serializers import PasswordResetSerializer

class CustomPasswordResetSerializer(PasswordResetSerializer):
    email = serializers.EmailField()
    password_reset_form_class = ResetPasswordForm

    def validate_email(self, value):
        # Create PasswordResetForm with the serializer
        self.reset_form = self.password_reset_form_class(data=self.initial_data)
        if not self.reset_form.is_valid():
            raise serializers.ValidationError(self.reset_form.errors)

        ###### FILTER YOUR USER MODEL ######
        if not get_user_model().objects.filter(email=value).exists():
            raise serializers.ValidationError(_('Invalid e-mail address'))

        return value

    def save(self):
        request = self.context.get('request')
        # Set some values to trigger the send_email method.
        opts = {
            'use_https': request.is_secure(),
            'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
            'request': request,
        }
        opts.update(self.get_email_options())
        self.reset_form.save(**opts)

```

### Settings.py

In the `settings.py` I have these fields, which seem relevant to me for my problem:

```py
# project/vuedj/settings.py
REST_AUTH_SERIALIZERS = {
    "USER_DETAILS_SERIALIZER": "accounts.serializers.CustomUserDetailsSerializer",
    "LOGIN_SERIALIZER": "accounts.serializers.CustomUserLoginSerializer",
    "PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer"
}

```

(The complete `settings.py` is attached at the bottom)

### URL patterns

My urls already catch my API request in order to send the Password-Reset Email:

```py
# project/vuedj/urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('api.urls')),
    path('accounts/', include('allauth.urls')),
    path('', api_views.index, name='home')
]

```

```py
# project/api/urls.py
urlpatterns = [
    path('auth/', include('accounts.urls')),
    # other paths...
]

```

```py
# project/accounts/urls.py
urlpatterns = [
    path('', acc_views.UserListView.as_view(), name='user-list'),
    path('login/', acc_views.UserLoginView.as_view(), name='login'),
    path('logout/', acc_views.UserLogoutView.as_view(),  name='logout'),
    path('register/', acc_views.CustomRegisterView.as_view(),  name='register'),
    path('reset-password/', acc_views.CustomPasswordResetView.as_view(), name='reset-password'),
    path('reset-password-confirm/', acc_views.CustomPasswordResetConfirmView.as_view(), name='reset-password-confirm'),
    path('<int:pk>/', acc_views.UserDetailView.as_view(), name='user-detail')
]

```

### Email with PW-Reset Token Generator

The CustomPasswordReset view will eventually generate a nice email with a nice pw-reset link. The link is valid, as I click it, I can reset the password through the allauth templates perfectly.

This code is used by rest-auth (indirectly) to generate the reset-token:

```py
# project/.venv/Lib/site-packages/allauth/account/forms.py
def save(self, request, **kwargs):
    current_site = get_current_site(request)
    email = self.cleaned_data["email"]
    token_generator = kwargs.get("token_generator",
                                 default_token_generator)

    for user in self.users:

        temp_key = token_generator.make_token(user)

        # save it to the password reset model
        # password_reset = PasswordReset(user=user, temp_key=temp_key)
        # password_reset.save()

        # send the password reset email
        path = reverse("account_reset_password_from_key",
                       kwargs=dict(uidb36=user_pk_to_url_str(user),
                                   key=temp_key))
        url = build_absolute_uri(
            request, path)

        context = {"current_site": current_site,
                   "user": user,
                   "password_reset_url": url,
                   "request": request}

        if app_settings.AUTHENTICATION_METHOD \
                != AuthenticationMethod.EMAIL:
            context['username'] = user_username(user)
        get_adapter(request).send_mail(
            'account/email/password_reset_key',
            email,
            context)
    return self.cleaned_data["email"]

```

This `PasswordResetTokenGenerator` is used in the code above:

```py
# project/.venv/Lib/site-packages/django/contrib/auth/tokens.py
class PasswordResetTokenGenerator:
        """
        Strategy object used to generate and check tokens for the password
        reset mechanism.
        """
        key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator"
        secret = settings.SECRET_KEY

        def make_token(self, user):
                """
                Return a token that can be used once to do a password reset
                for the given user.
                """
                return self._make_token_with_timestamp(user, self._num_days(self._today()))

        def check_token(self, user, token):
                """
                Check that a password reset token is correct for a given user.
                """
                if not (user and token):
                        return False
                # Parse the token
                try:
                        ts_b36, hash = token.split("-")
                except ValueError:
                        return False

                try:
                        ts = base36_to_int(ts_b36)
                except ValueError:
                        return False

                # Check that the timestamp/uid has not been tampered with
                if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
                        return False

                # Check the timestamp is within limit. Timestamps are rounded to
                # midnight (server time) providing a resolution of only 1 day. If a
                # link is generated 5 minutes before midnight and used 6 minutes later,
                # that counts as 1 day. Therefore, PASSWORD_RESET_TIMEOUT_DAYS = 1 means
                # "at least 1 day, could be up to 2."
                if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
                        return False

                return True

```

The classes above will be called by the `rest_auth` `PasswordResetView`:

```py
# project/.venv/Lib/site-packages/rest_auth/views.py
class PasswordResetView(GenericAPIView):
        """
        Calls Django Auth PasswordResetForm save method.

        Accepts the following POST parameters: email
        Returns the success/fail message.
        """
        serializer_class = PasswordResetSerializer
        permission_classes = (AllowAny,)

        def post(self, request, *args, **kwargs):
                # Create a serializer with request.data
                serializer = self.get_serializer(data=request.data)
                serializer.is_valid(raise_exception=True)

                serializer.save() # <----- Code from above (TokenGenerator) will be called inside this .save() method
                # Return the success message with OK HTTP status
                return Response(
                        {"detail": _("Password reset e-mail has been sent.")},
                        status=status.HTTP_200_OK
                )

```

As you can see, the Tokengenerator will return a `uidb36` with the token.
It also assumes a `uidb36` when the user would confirm the password-reset.
A generated token (for example the full link in the generated mail) would look like this:

```
http://localhost:8000/accounts/password/reset/key/16-52h-42b222e6dc30690b2e91/

```

Where **`16`** is the user id in base 36 (`uidb36`), I do not yet know what `52h` means, but I assume, the third part of the token is the token itself (`42b222e6dc30690b2e91`)

Step 2: Send the token to the backend (aka "User clicks link")
==============================================================

I am stuck here.
The [API-Endpoints](https://django-rest-auth.readthedocs.io/en/latest/api_endpoints.html) of the [Rest-Auth-Framework](https://django-rest-auth.readthedocs.io/en/latest/index.html) say:

> 
> /rest-auth/password/reset/confirm/ (POST)  
> 
> `uid`  
> 
> `token`  
> 
> `new_password1`  
> 
> `new_password2`  
> 
> 
> 
> 

And when I send an object e.g:

```js
{
    uid: '16', // TODO maybe I have to convert it to base10...
    token: '42b222e6dc30690b2e91',
    new_password1: 'test123A$',
    new_password2: 'test123A$'
}

```

via my api to `http://localhost:8000/api/v1/auth/reset-password/` with the object above in the body of an `axios`-post request, my `CustomPasswordResetConfirmView` is triggered like expected, which is also just a Subclass of `PasswordResetConfirmView` from `rest_auth`, so this code is executed:

```py
# project/.venv/Lib/site-packages/rest_auth/views.py
class PasswordResetConfirmView(GenericAPIView):
        """
        Password reset e-mail link is confirmed, therefore
        this resets the user's password.

        Accepts the following POST parameters: token, uid,
                new_password1, new_password2
        Returns the success/fail message.
        """
        serializer_class = PasswordResetConfirmSerializer
        permission_classes = (AllowAny,)

        @sensitive_post_parameters_m
        def dispatch(self, *args, **kwargs):
                return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)

        def post(self, request, *args, **kwargs):
                serializer = self.get_serializer(data=request.data)
                serializer.is_valid(raise_exception=True)
                serializer.save()
                return Response(
                        {"detail": _("Password has been reset with the new password.")}
                )

```

The line `serializer.is_valid(raise_exception=True)` will call `run_validation` of the `Serializer(BaseSerializer)` of the `rest_framework`.
This will further use the `PasswordResetConfirmSerializer` of `rest_auth`:

```py
# project/.venv/Lib/site-packages/rest_auth/serializers.py
class PasswordResetConfirmSerializer(serializers.Serializer):
        """
        Serializer for requesting a password reset e-mail.
        """
        new_password1 = serializers.CharField(max_length=128)
        new_password2 = serializers.CharField(max_length=128)
        uid = serializers.CharField()
        token = serializers.CharField()

        set_password_form_class = SetPasswordForm

        def custom_validation(self, attrs):
                pass

        def validate(self, attrs):
                self._errors = {}

                # Decode the uidb64 to uid to get User object
                try:
                        uid = force_text(uid_decoder(attrs['uid']))
                        self.user = UserModel._default_manager.get(pk=uid)
                except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
                        raise ValidationError({'uid': ['Invalid value']})

                self.custom_validation(attrs)
                # Construct SetPasswordForm instance
                self.set_password_form = self.set_password_form_class(
                        user=self.user, data=attrs
                )
                if not self.set_password_form.is_valid():
                        raise serializers.ValidationError(self.set_password_form.errors)
                if not default_token_generator.check_token(self.user, attrs['token']):
                        raise ValidationError({'token': ['Invalid value']})

                return attrs

```

And as you can finally see, this class is expecting a uidb64 instead of a uidb36 for the user id, and I do not even want to know whether the token-format is anyhow matching what is expected here.

I really cannot find good documentation about how to setup `rest_auth` properly for the full password-reset process: I got the email working, but for me it seems, `rest_auth` would generate a wrong token/reset-link for what it is actually expecting back from the user.

### Summary

I believe, the password-reset-confirmation process is ending in the correct backend-code, while the email/token-generation is messed up.

All I want is to retrieve a **uid** and a **token** which I can send back to django rest-auth in order to let users reset their passwords.
Currently, it seems that these uids and tokens are created by one library and consumed by another library which both expect and create different formats of tokens and uids?

Thanks in advance!

Full `settings.py`
------------------

Here is my full `settings.py`:

```py
# project/vuedj/settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
SECRET_KEY = persisted_settings.SECRET_KEY
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
CORS_ORIGIN_ALLOW_ALL = True
CORS_URLS_REGEX = r'^/api/.*$'
CORS_ALLOW_CREDENTIALS = True

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'rest_framework',
    'rest_framework.authtoken',
    'corsheaders',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.github',
    'rest_auth',
    'rest_auth.registration',
    'sceneries',
    'accounts',
    'api',
    'app',
]

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = 'app-messages'
SITE_ID = 1

AUTH_USER_MODEL = 'accounts.User'
ACCOUNT_USER_MODEL_USERNAME_FIELD = 'username'
ACCOUNT_AUTHENTICATION_METHOD = 'username_email'

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'none'
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = True
ACCOUNT_USER_EMAIL_FIELD = 'email'
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_FORMS = {"login": "accounts.forms.UserLoginForm"}
LOGIN_REDIRECT_URL = 'home'
LOGIN_URL = 'api/v1/accounts/login/'

CSRF_COOKIE_NAME = "csrftoken"

REST_AUTH_SERIALIZERS = {
    "USER_DETAILS_SERIALIZER": "accounts.serializers.CustomUserDetailsSerializer",
    "LOGIN_SERIALIZER": "accounts.serializers.CustomUserLoginSerializer",
    "PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer"
}

REST_AUTH_REGISTER_SERIALIZERS = {
    "REGISTER_SERIALIZER": "accounts.serializers.CustomRegisterSerializer",
}

# Following is added to enable registration with email instead of username
AUTHENTICATION_BACKENDS = (
    # Needed to login by username in Django admin, regardless of `allauth`
    "django.contrib.auth.backends.ModelBackend",
    # `allauth` specific authentication methods, such as login by e-mail
    "allauth.account.auth_backends.AuthenticationBackend",
)

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'vuedj.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            'templates/',
            'templates/emails/'
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'vuedj.wsgi.application'

try:
        DATABASES = persisted_settings.DATABASES
except AttributeError:
        DATABASES = {
                'default': {
                        'ENGINE': 'django.db.backends.sqlite3',
                        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
                }
        }

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
STATIC_ROOT = os.path.join(BASE_DIR, '../staticfiles/static')
MEDIA_ROOT = os.path.join(BASE_DIR, '../staticfiles/mediafiles')
STATIC_URL = '/static/'
MEDIA_URL = '/media/'

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

NOSE_ARGS = [
    '--with-coverage',
    '--cover-package=app',  # For multiple apps use '--cover-package=foo, bar'
]

```