0

I'm trying to implement a custom login mechanism in Odoo where users authenticate using an OTP (One-Time Password) sent to their email, instead of the traditional username/password method.

My goal:

  1. User enters their email address on the login screen.
  2. An OTP is generated and sent to their email.
  3. User enters the OTP, and if it’s valid and not expired, they are logged in.

What I’ve tried:

  • Created a custom controller with @http.route('/web/login/request_otp', ...) to handle OTP generation.
  • Stored OTPs in a new model (res.users.otp) with expiry timestamp.
  • Used mail.template to send OTP to the user’s email.
  • Created another route to validate the OTP and authenticate using request.session.authenticate(...).

Issue:

When I try to access /web/login/[email protected], I get a 404 Not Found error.
I'm not sure if:

  • The route is properly registered.
  • The controller is loaded correctly.
  • The module was upgraded properly.

Environment:

  • Odoo version: 16 (also trying on 17)
  • Custom module created under addons/
  • SMTP is configured and working for other mail templates

My questions:

  1. What's the correct way to register a custom public HTTP route for login in Odoo?
  2. How to properly authenticate a user from a controller using OTP (without requiring password)?
  3. Any security concerns or best practices I should follow when implementing OTP login in Odoo?

Any help or working example would be appreciated 🙏

Route code:

from odoo import http
from odoo.http import request 

class AuthOtpController(http.Controller): 
    @http.route('/web/login/verify_password', type='http', 
                 auth='public', website=True, csrf=False)
    def verify_password(self, **kwargs):
        # Logic for verifying email and password, # generating OTP, storing it, and sending it via email. 

    @http.route('/web/login/confirm_otp', type='http', 
        auth='public', website=True, csrf=False)
    def confirm_otp(self, **kwargs):
        # Logic for verifying the OTP and authenticating the user.

    @http.route('/web/login/request_otp', type='http', auth='public', website=True, csrf=False)
    def request_otp(self, **kwargs):
        email = kwargs.get('email')
        # Logic for generating OTP and sending it via email return "OTP sent"
7
  • can you add the full route definition (method signature and decorators, logic irrelevant if you don't want to share it)? Do you have 1 or more databases in your test evironment? Commented Jul 8 at 14:50
  • Sure! Here's the full route definition I'm using in my custom controller: Commented Jul 9 at 14:00
  • from odoo import http from odoo.http import request class AuthOtpController(http.Controller): @http.route('/web/login/verify_password', type='http', auth='public', website=True, csrf=False) def verify_password(self, **kwargs): # Logic for verifying email and password, # generating OTP, storing it, and sending it via email. @http.route('/web/login/confirm_otp', type='http', auth='public', website=True, csrf=False) def confirm_otp(self, **kwargs): # Logic for verifying the OTP and authenticating the user. Commented Jul 9 at 14:01
  • Regarding your question about databases: 👉 I’m using only one database in my local development environment (e.g., TestDB). Let me know if having a single DB vs. multiple DBs could affect routing or session handling during login. Commented Jul 9 at 14:02
  • i've added the code to the question. But i don't see a route for "/web/login/request_otp" which is mentioned in "Issue". Commented Jul 9 at 14:56

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.