feat: implement email verification flow with account activation and secure cookie configuration

This commit is contained in:
Your Name
2026-04-10 10:18:32 +05:30
parent f1c3b3f9f2
commit d74fcc0b9c
6 changed files with 69 additions and 1 deletions
+6
View File
@@ -11,6 +11,8 @@ class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError(_("The Email must be set"))
# set default activation state as False to enforce email verification
extra_fields.setdefault("is_active", False)
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
@@ -39,6 +41,10 @@ class User(AbstractUser):
full_name = models.CharField(max_length=100)
email = models.EmailField(_("email address"), unique=True)
kdf_salt = models.CharField(max_length=128, blank=True, null=True)
# Default is False to enforce email verification
is_active = models.BooleanField(default=False)
objects = CustomUserManager()
+4
View File
@@ -1,6 +1,8 @@
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from users.views import ActivationView
from .views import MeView, RegisterView
urlpatterns = [
@@ -11,4 +13,6 @@ urlpatterns = [
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
# Get current user info
path("me/", MeView.as_view(), name="me"),
# Activate user account
path("activate/<str:uidb64>/<str:token>/", ActivationView.as_view(), name="activate"),
]
+22
View File
@@ -0,0 +1,22 @@
from django.conf import settings
from django.contrib.auth.tokens import default_token_generator
from django.core.mail import send_mail
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
def send_activation_email(user):
token = default_token_generator.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
activation_url = f"{settings.FRONTEND_URL}/activate/{uid}/{token}"
subject = "Activate Your Piku Account"
message = f"""Hi {user.full_name},
Welcome to Pi Ku.
Please click the link below to activate your account:
>> {activation_url}
If you did not create this account, please ignore this email."""
send_mail(subject, message, settings.FROM_EMAIL, [user.email], fail_silently=False)
return True
+23 -1
View File
@@ -1,5 +1,8 @@
from django.contrib.auth import get_user_model
from rest_framework import generics, permissions
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode
from rest_framework import generics, permissions, status
from rest_framework.response import Response
from .serializers import UserSerializer
@@ -12,6 +15,25 @@ class RegisterView(generics.CreateAPIView):
serializer_class = UserSerializer
class ActivationView(generics.GenericAPIView):
permission_classes = (permissions.AllowAny,)
serializer_class = UserSerializer
def get(self, request, uidb64, token):
try:
uid = urlsafe_base64_decode(uidb64).decode()
user = User.objects.get(pk=uid)
except (User.DoesNotExist, TypeError, ValueError):
return Response({"detail": "Invalid activation link: User Error"}, status=status.HTTP_400_BAD_REQUEST)
# validate token
if not default_token_generator.check_token(user, token):
return Response({"detail": "Invalid activation link: Token Error"}, status=status.HTTP_400_BAD_REQUEST)
# activate user
user.is_active = True
user.save()
return Response({"detail": "Account activated successfully"}, status=status.HTTP_200_OK)
class MeView(generics.RetrieveAPIView):
serializer_class = UserSerializer
permission_classes = (permissions.IsAuthenticated,)