Getting error message when add in the route for the 2fa

Hi,

Getting error message when add in the @server.route('/2fa', methods=['GET', 'POST']).

The page isn’t redirecting properly

Firefox has detected that the server is redirecting the request for this address in a way that will never complete.

    This problem can sometimes be caused by disabling or refusing to accept cookies.


server.py

@server.route('/2fa', methods=['GET', 'POST'])
# @login_required
def two_factor_authentication():   
    user_id = current_user.id
    
    
    if request.method == 'POST':
        entered_token = request.form['token']
        stored_token = get_token(user_id)  

        if entered_token == stored_token:
            return redirect('/')
        else:
            # Failed verification
            return html.Div("Invalid verification code. Please try again.")

    return redirect ('/2fa')




@server.route('/login', methods=['POST'])
def login_button_click():
    if request.form:
        username = request.form['username']
        password = request.form['password']
        
        if not is_valid_password(password):
            return """Password does not meet policy requirements <a href='/login'>login here</a>"""
        

        if VALID_USERNAME_PASSWORD.get(username) is None:
   
            return """Invalid username and/or password <a href='/login'>login here</a>"""
        
        stored_pwd = VALID_USERNAME_PASSWORD.get(username)['password']
        hashed_pwd = hashlib.sha256(password.encode()).hexdigest()

            
        if stored_pwd == hashed_pwd:
        
            login_user(User(username))
                       
            if 'url' in session:
                if session['url']:
                    url = session['url']
                    session['url'] = None
                    return redirect(url) ## redirect to target url
            
            
            return redirect('/2fa')
               
        
        return """Invalid username and/or password <a href='/login'>login here</a>"""





app = dash.Dash(
    __name__, server=server, use_pages=True, suppress_callback_exceptions=True,
    external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.BOOTSTRAP, 
                           # "/assets/display.css"
                           ],
    meta_tags=[{'name': 'viewport',
                'content': 'width=device-width, initial-scale=1.0'}] #, maximum-scale=1.0, minimum-scale=0.5
)



df = masteruser()
VALID_USERNAME_PASSWORD = df.set_index('username').transpose().to_dict()


server.secret_key = SECRET_KEY



# Login manager object will be used to login / logout users
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = "/login"


class User(UserMixin):
    # User data model. It has to have at least self.id as a minimum
    def __init__(self, username):
        self.id = username
        self.role_id = VALID_USERNAME_PASSWORD[username]['role_id']



@login_manager.user_loader
def load_user(username):
    """This function loads the user by user id. Typically this looks up the user from a user database.
    We won't be registering or looking up users in this example, since we'll just login using LDAP server.
    So we'll simply return a User object with the passed in username.
    """
    return User(username)



2fa.py

dash.register_page(__name__,
                   path='/2fa', 
                   name=' 2FA', 
                   title='2FA', 

)


def layout():
    if not current_user.is_authenticated:
        return html.Div(["Please ", dcc.Link("login", href="/login"), " to continue"])
    
    
    return html.Div ([
               
        html.Div([
            html.Div([
                
                dbc.Row([
                        html.H1('Two Factor Authentication'),
                    
                    ]),
                
                dbc.Row ([
                    html.Ol([
                        html.Li(["Install the Google Authenticator."])

                        ]),
                    ]),
                    
                dbc.Row ([   
                    html.H3('Verification code'),
                    
                    
                    dcc.Input( type="text", id="token-box", name='token', pattern=r"^[0-9]*$"
                              ), 
                    
                    ]),
                
                
                dbc.Row ([
                
                    html.Button('Submit',n_clicks=0, type="submit", id = "login-button"),
                    
                    ]),
                
                
                ]),
            
                        
            html.Div ([
                
                html.Button('Generate',
                           n_clicks=0, type="submit", id="generate-button"),
                
                html.Div(id="qrcode"),
                
                
                
                ]),
            
            ],')
        
       ])
               
               





@callback(
    Output("qrcode", "children"),
    Input("generate-button", "n_clicks"),
    prevent_initial_call=True
)



def update_qr_code(n_clicks):
    user_account = current_user.id
    service_name = "web"
    qr_code_data = update_token(service_name, user_account)
      
    
    if n_clicks and n_clicks % 2 != 0:
        return html.Img(src=qr_code_data, style={"display": "block"})
    
    return html.Img(style={"display": "none"})

Hello @beginof,

You can’t have dash and flask sharing the same route.

You need to alter one or the other.

@server.route('/2fa', methods=['GET', 'POST']) ...
dash.register_page(__name__, ...

Is it this two part?
How can I adjust to enable the function? Kindly advise.



But my change_password also using the same theory :joy: :joy:


`server.py`
@server.route('/change-password', methods=['GET', 'POST'])
def change_password():
    if not current_user.is_authenticated:
        return redirect('/login')
        
    # Store user ID
    user_id = current_user.id
    
    if request.method == 'POST':
        new_password = request.form['new_password']
        confirm_password = request.form['confirm_password']
        
        
        if not is_valid_password(new_password):
            return """Password does not meet policy requirements. <a href='/change-password'>Reset again</a>"""
        
        # Check if both passwords match
        if new_password != confirm_password:
            return """Passwords do not match! <a href='/change-password'>Reset again</a>"""
        
        # Hash the new password
        hashed_pwd = hashlib.sha256(new_password.encode()).hexdigest()
        
        # Update password in database
        cursor.execute(update_exist_password, (hashed_pwd, user_id))

        conn.commit()
        
        # Update stored password for authentication
        VALID_USERNAME_PASSWORD[user_id]['password'] = hashed_pwd

        # flash('Password updated successfully!', 'success')
        return redirect('/')
        # return """Password updated successfully! """
    
    return redirect ('/')



change_password.py

dash.register_page(__name__,
                    path='/change-password',  
                    name=' Reset password',
                    title='Reset password',  

)



def layout():
    if not current_user.is_authenticated:
        return html.Div(["Please ", dcc.Link("login", href="/login"), " to continue"])

    return html.Div([
        html.Form([
            html.Div([
                html.H1('Reset Password'),
                
                html.H3('New Password'), 
                dcc.Input(id="new_password",
                          placeholder="new password", 
                          type="password", 
                          name='new_password', 
                          ), 
                
                html.H3('Confirm Password'),
                dcc.Input(id="confirm_password",
                          placeholder="confirm password", 
                          type="password", 
                          name='confirm_password', 

                          ),
                
                html.Br(),

                html.Button('Submit',
                            id="change-button", 
                            n_clicks=0, 
                            type="submit",
                             ),
                
                html.Button(
                    dcc.Link('Cancel', href='/'), 
                    ),

                ]), 
                
               
            html.Div(children="", id="reset-output"),
            
            
            ], method='POST' ),
        
        
        html.Div([
            html.P('Password required:'),  
            html.Ul([
                html.Li(["8-20 characters"]),

                ]),
            ],id="list",
            ),
        
        
        ])

Interesting.

Then at the end of your 2FA, to redirect to 2FA again.

It looks like an endless loop when you do a get request.

How should I amend then only able to perform?

This is going into an endless loop:

@server.route('/2fa', methods=['GET', 'POST'])
# @login_required
def two_factor_authentication():   
    user_id = current_user.id
    
    
    if request.method == 'POST':
        entered_token = request.form['token']
        stored_token = get_token(user_id)  

        if entered_token == stored_token:
            return redirect('/')
        else:
            # Failed verification
            return html.Div("Invalid verification code. Please try again.")

    return redirect ('/2fa')

Maybe try removing the 'GET' method.

@server.route('/2fa', methods=['POST'])
# @login_required
def two_factor_authentication():   
    user_id = current_user.id
    
    
    if request.method == 'POST':
        entered_token = request.form['token']
        stored_token = get_token(user_id)  

        if entered_token == stored_token:
            return redirect('/')
        else:
            # Failed verification
            return html.Div("Invalid verification code. Please try again.")

This should send you to the page layout from the dash app when punched in. :slight_smile:

Thank @jinnyzor.

Now it can go to the/2fa.

However, the submit still unable to perform. :rofl:
When the input token same as the stored token, the /2fa is unable to perform the verify and direct to thehome page.

Which part should I amend to enable to function?

To get the other portion of your code working, you need to place those fields into a form with a submit button.

You should be able to emulate the login form that I am guessing you are using, or the change password form that you created.

1 Like

Thanks @jinnyzor of your advise.

1 Like