Open ShaunHide17 opened 4 months ago
Hi @ShaunHide17, thank you for reaching out. Instead of using this custom function, can you try to add an authenticator.login(location='unrendered')
widget to each other page to see if it will solve your problem?
Hi @mkhorasani , thanks for the quick reply and the help!
Sadly adding in the authenticator.login(location='unrendered')
into each of the headers generates an error (below)
I think the new routing causes a multipage visit on the first streamlit run
call and in doing so generates a DupliecateWidgetID error:
DuplicateWidgetID(streamlit.errors.DuplicateWidgetID: There are multiple widgets with the same `key='init'`.
I supply the key parameter to authenticator.login()
with it being different for each of the pages, but it seems to error out further upstream in the stx.CookieManager()
call
Full error log below:
Traceback (most recent call last):
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/exec_code.py", line 75, in exec_func_with_error_handling
result = func()
^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 574, in code_to_exec
exec(code, module.__dict__)
File "/Users/shaunhide/Desktop/st_example/example.py", line 29, in <module>
pg.run()
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/navigation/page.py", line 291, in run
exec(code, module.__dict__)
File "/Users/shaunhide/Desktop/st_example/views/view.py", line 5, in <module>
instantiate_authenticator(key="view")
File "/Users/shaunhide/Desktop/st_example/helpers/authentication.py", line 22, in instantiate_authenticator
authenticator = auth.Authenticate(
^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit_authenticator/views/authentication_view.py", line 51, in __init__
self.cookie_controller = CookieController(cookie_name,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit_authenticator/controllers/cookie_controller.py", line 27, in __init__
self.cookie_model = CookieModel(cookie_name,
^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit_authenticator/models/cookie_model.py", line 40, in __init__
self.cookie_manager = stx.CookieManager()
^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/extra_streamlit_components/CookieManager/__init__.py", line 22, in __init__
self.cookies = self.cookie_manager(method="getAll", key=key, default={})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/components/v1/custom_component.py", line 58, in __call__
return self.create_instance(
^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/runtime/metrics_util.py", line 408, in wrapped_func
result = non_optional_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/components/v1/custom_component.py", line 228, in create_instance
return_value = marshall_component(dg, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/components/v1/custom_component.py", line 202, in marshall_component
component_state = register_widget(
^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/runtime/state/widgets.py", line 169, in register_widget
return register_widget_from_metadata(metadata, ctx, widget_func_name, element_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/shaunhide/Desktop/st_example/.venv/lib/python3.12/site-packages/streamlit/runtime/state/widgets.py", line 202, in register_widget_from_metadata
raise DuplicateWidgetID(
streamlit.errors.DuplicateWidgetID: There are multiple widgets with the same `key='init'`.
To fix this, please make sure that the `key` argument is unique for each
widget you create.
It seems that you are recreating several stauth.Authenticate
objects, probably one for each page. If this is indeed the case, you will face a DuplicateWidgetID
error since the cookie manager does not use a unique key for each object. Instead, you should save the authenticator object to the session state once on your home page and access it from the session state from other pages.
can you help me understand a little bit here. when authenticator object is saved to the session state, and when user refreshes the page, wouldn't it loose the state? st.session_state
is not persisted when page refreshes. So we loose the state and forces user to login. I'm having a similar issue in my app.
Hi @smboy, session_state will only be lost if the user does a hard refresh. A normal refresh will not remove the session_state. But even if the user does a hard refresh the re-authentication cookie will log them in automatically. I hope this answers your question.
Thanks for the details. Couple of followup questions:
Thanks again!
Thanks for the details. Couple of followup questions:
- Just to clarify, this works seamlessly for a multipage application?
- also multi-user application without any issues?
- does this work across browsers too? seen case where Safari was not storing the cookie and when I refreshed (simple refresh) the page, it forced me to login.
Thanks again!
Hi @smboy, can you verify that the issue you had was resolved after adding the authenticate
object to session state? As for your questions, yes, yes, and yes. I've had no problems on my end.
It seems to be working on a standalone code. I will add it to my application and will update you (I was using a different authentication module which was having similar issues of persistence during page refresh).
meanwhile, anyway to customize the login? I would like to only display email and pwd..username is not required for my application. Thanks much again for your quick response!
Yes, as of the latest version, users can now register their email as their username too. Feel free to change the name of the username field to email if you wish, you can do so using the fields={'Username':'Email'}
argument.
Yes, as of the latest version, users can now register their email as their username too. Feel free to change the name of the username field to email if you wish, you can do so using the
fields={'Username':'Email'}
argument.
@mkhorasani this is a great new feature! I am trying to keep things simple for my users and just have email and password, so this helps.
I have this working on the login widget, however, can't get it working on register_user. When running authenticator.register_user(pre_authorization=True, fields={'Username':'Email'})
I get errors "Missing submit button" and "DuplicateWidgetID" from line 347 in register_user 'Username' if 'Username' not in fields
. Not sure if this is jusr a me issue, or a feature request!
Yes, as of the latest version, users can now register their email as their username too. Feel free to change the name of the username field to email if you wish, you can do so using the
fields={'Username':'Email'}
argument.@mkhorasani this is a great new feature! I am trying to keep things simple for my users and just have email and password, so this helps.
I have this working on the login widget, however, can't get it working on register_user. When running
authenticator.register_user(pre_authorization=True, fields={'Username':'Email'})
I get errors "Missing submit button" and "DuplicateWidgetID" from line 347 in register_user'Username' if 'Username' not in fields
. Not sure if this is jusr a me issue, or a feature request!
Since the register_user
widget has both username
and email
fields in the form, if you rename the username
field to email
you will indeed get a DuplicatWidgetID error since both text fields now have the same name. I will try to modify this widget in the next release to remove the username field if the user wants to combine both fields into one. Please stay tuned!
If I may suggest, what would be appropriate is to take input fields as config parameter for registration and login. For instance, for registration, I want to use {user_email, pwd, company_name} and for login {username, password}.
In fact, what I was thinking is to even isolate further. If there is any clean way where I can come up with my own login screen and simply pass the values to your application, that would be even ideal. That way, we are separating the front end with that of the backend. Its upto user on what and how they customize the login screen with. Currently its tightly coupled with the login screen.
If I may suggest, what would be appropriate is to take input fields as config parameter for registration and login. For instance, for registration, I want to use {user_email, pwd, company_name} and for login {username, password}.
In fact, what I was thinking is to even isolate further. If there is any clean way where I can come up with my own login screen and simply pass the values to your application, that would be even ideal. That way, we are separating the front end with that of the backend. Its upto user on what and how they customize the login screen with. Currently its tightly coupled with the login screen.
I definitely see a use case for this, but it would require major refactoring of the codebase and that is something that I can only commit to for the long term.
i am still having the case where my page reloads to the default page, i have updated to the last version, provided authentication on the entry file, added the authenticator = st.session_state.authenticator and authenticator.login("unrendered") to every page, my app still reloads to default or main page
Hi,
I am using the latest version of streamlit-authenticator (0.3.3) with the latest version of streamlit (1.37.0)
I am using the new multipage routing mechanism that streamlit recently released: https://docs.streamlit.io/develop/concepts/multipage-apps/page-and-navigation
If I navigate away from the default page (View) to View2 then do a hard refresh (i.e. F5), it refreshes back to the default page (View) rather than the page I refreshed on. This behaviour does not occur without the
instantiate_authenticator()
function call so cant seem to work out what is driving the return to default behaviourCan you offer any guidance?
Here is a sample of the main file from which the application is started with
streamlit run
With the instantiate_authenticator() function being: