Skip to content

Instantly share code, notes, and snippets.

@garzuze
Created February 26, 2025 10:07
Show Gist options
  • Save garzuze/007f73a8ea630f45ae89f341a51f4d26 to your computer and use it in GitHub Desktop.
Save garzuze/007f73a8ea630f45ae89f341a51f4d26 to your computer and use it in GitHub Desktop.
How to create an email verification system without having to add any extra field in your user model - Django
# Create a User registration serializer
# When the user sends the request with his data — in this case, email and password —,
# we create a new user with is_verified=False (builtin field in default user model)
# Then we send an email containing a verification link
# You can customize it so you link points to a route in your fronted, if you use Django only for the backend
# After that you can create a view that uses this serializer
from django.urls import reverse
from rest_framework import serializers
from django.core.mail import send_mail
from django.conf import settings
from .utils import generate_email_verification_token
from django.contrib.auth import get_user_model
User = get_user_model()
class RegistrationSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'password', 'is_active')
extra_kwargs = {
'password': {'write_only': True}
}
def validate(self, data):
return data
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
token = generate_email_verification_token(user)
verify_path = reverse('verify-email')
verification_url = f"http://127.0.0.1:8000/{verify_path}?uid={user.pk}&token={token}"
# Email content
subject = "Verify your email"
message = (
"Welcome!\n\n"
"Please, verify your addres clicking in the link below:\n"
f"{verification_url}\n\n"
)
send_mail(
subject,
message,
settings.DEFAULT_FROM_EMAIL,
[user.email],
fail_silently=False,
)
return user
# Email verification settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('GMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('GMAIL_PASS')
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
# Configure your urls.py
urlpatterns = [
path('api/register/', RegistrationView.as_view(), name='register'),
path('api/verify-email/', VerifyEmailAPIView.as_view(), name='verify-email'),
]
# We use django bultin function, that receives the user as a parameter, to generate a token
# We use this to create the one-time use link that will be sent to the user's email
# You can go even crazier and make a more secure token based on user data
from django.contrib.auth.tokens import default_token_generator
def generate_email_verification_token(user):
return default_token_generator.make_token(user)
from rest_framework import generics
from .serializers import RegistrationSerializer
from rest_framework.views import APIView
from rest_framework import status
# Create a view that receives the user id and the token and verify it
class VerifyEmailAPIView(APIView):
def get(self, request):
uid = request.query_params.get('uid')
token = request.query_params.get('token')
if not uid or not token:
return Response({"error": "Invalid verification link."}, status=status.HTTP_400_BAD_REQUEST)
user = get_object_or_404(User, pk=uid)
# If the token matches, the user can be verified!
if default_token_generator.check_token(user, token):
user.is_active = True
user.save()
return Response({"message": "Email verified successfully."}, status=status.HTTP_200_OK)
else:
return Response({"error": "Invalid or expired token."}, status=status.HTTP_400_BAD_REQUEST)
# Create the RegistrationView using the serializer previouly created
class RegistrationView(generics.CreateAPIView):
serializer_class = RegistrationSerializer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment