I wanted to have signed URL everywhere.For that, I added user_signature=True to all my URL(). The grid has that as a default.At this point everything worked with @requires_login() except one special case (I believe this special case may be related to the same issue I'm facing with this I describe here).Then I added a var called sid (for session id) to every URL() which I use to identify the session (this way I'm able to distinguish ebetween 2 browser tabs).At this point everything worked with @requires_login() except the special case I mentioned above.Then I replaced @auth.requires_login() with @auth.requires_signature() and I'm able to access the grid but not the edit form. I receive a Not Authorized message.In all these tests I'm logged in.If I remove the sid var and keep the @auth.requires_signature() everything works.If I replace t...@auth.requires_signature() with @auth.requires_login() and keep the sid var everything works.Only the combination of both doesn't work.
#@auth.requires_signature()
@auth.requires_login()
def index():
    # type: () -> Dict[str, gluon.DIV]
    """Index page.
    :return: Dict with grid.
    """
    if session.return_to:
        del session.return_to
    session.table = 'opt_cat'
    # Hidden fields in grid and edit/view form.
    db.opt_cat.id.readable = False
    db.opt_cat.one_opt_only.show_if = db.opt_cat.mandatory == False
    if SUPERVISOR_ROLE_ID in auth.user_groups:
        # Uses covering index opt_cat_is_active_name_en.
        # Uses auto index sqlite_autoindex_opt_cat_1.
        grid = SQLFORM.grid(
            db.opt_cat,
            csv=False,
            details=False,
            # Disable delete checkbox in edit form.
            editargs=dict(deletable=False),
            maxtextlength=GRID_COL_LEN_FOR_TEXT,
            ondelete=on_delete,  # Grid only.
            onvalidation=on_validation,  # And onupdate are form only.
            orderby=db.opt_cat.name,
            paginate=session.auth.user.pagination,
            # represent_none='',  # Grid and view form only.
        )  # type: gluon.DIV
    else:
        # Hidden fields in grid and edit/view form.
        db.opt_cat.canceled_on.readable = False
        db.opt_cat.canceled_by.readable = False
        db.opt_cat.cancel_approved_by.readable = False
        # Uses covering index opt_cat_is_active_name_en (is_active=?).
        # Uses index opt_cat_is_active_name (is_active=?).
        grid = SQLFORM.grid(
            db.opt_cat.is_active == True,
            create=False,
            csv=False,
            deletable=False,
            details=False,
            editable=False,
            maxtextlength=GRID_COL_LEN_FOR_TEXT,
            orderby=db.opt_cat.name,
            paginate=session.auth.user.pagination,
            # represent_none='',  # Grid and view form only.
        )
    # Remove icons from default buttons.
    grid.elements('span.icon', replace=None)
    if request.args:
        # Remove delete button.
        grid.element('#delete_with_approval', replace=None)
    if not request.args:
        # Sort grid's search fields list.
        grid.element('#w2p_query_fields').components = sort_grid_search_fields_list(grid)
        if session.opt_cat_modified_on:
            del session.opt_cat_modified_on
    elif 'edit' in request.args:
        # Edit uses opt_cat Pk.
        form = grid.update_form  # type: gluon.sqlhtml.SQLFORM
        # form['hidden'].update(mon=form.record.modified_on)
        # Solves the record changed while editing, but doesn't solve it
        # if the user 1st tries something that returns form.errors (eg.
        # changing a unique field to something that already exists) and
        # only after that he tries to save the record (which was changed
        # by another user). For this the only solution I've found was
        # using a session var.
        if not session.opt_cat_modified_on:
            session.opt_cat_modified_on = form.record.modified_on
        if not form.record.is_active and not SUPERVISOR_ROLE_ID in auth.user_groups:
            session.flash = T('Record was deleted while you were viewing the grid.')
            redirect(URL(user_signature=True))
    return dict(grid=grid)
...
if auth.is_logged_in():
    response.menu = [
        (T('Home'), False, URL('default', 'index', user_signature=True)),
        (T('Open work orders'), False, URL('open_wo', 'index', user_signature=True)),
        (T('Tables'),
         False,
         None,
         [
            (db.opt_cat._plural, False, URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True)),
...
It is called from the menu (models\menu.py). This is the code:
if auth.is_logged_in():
response.menu = [
(T('Home'), False, URL('default', 'index', user_signature=True)),
(T('Open work orders'), False, URL('open_wo', 'index', user_signature=True)),
(T('Tables'),
False,
None,
[
(db.opt_cat._plural, False, URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True)),
...Didn't test the sorting or search then, but I tested now and they also don't work, returning the same Not Authorized message.
@auth.requires_signature(hash_vars=False)URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True, hash_vars=False)My though in replacing the @auth.requires_login() with @auth.requires_signature() (I believe @auth.requires_signature() also requires login, correct?) was adding another security layer, but with the limitation you explained, I think I will not do it.What is your opinion on this?With this severe limitation to @auth.requires_signature(), in what situation do you recommend using it?