supertokens/supertokens-python

Dashboard Change Password Error

mulac opened this issue · 3 comments

mulac commented

I get a 500 error when trying to change any user's password through the dashboard. Below is the stack trace from the python SDK when the call to PUT /auth/dashboard/api/user/password returns 500.

I am using the python SDK version 0.12.5 and a managed core on version 4.4

Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 2528, in wsgi_app 
response = self.full_dispatch_request()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 1825, in full_dispatch_request
rv = self.handle_user_exception(e)
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/flask_cors/extension.py", line 165, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
                                            ^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 1821, in full_dispatch_request
rv = self.preprocess_request()
     ^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 2312, in preprocess_request
rv = self.ensure_sync(before_func)()
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/framework/flask/flask_middleware.py", line 54, in _
result: Union[BaseResponse, None] = sync(st.middleware(request_, response_))
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/async_to_sync_wrapper.py", line 33, in sync
return loop.run_until_complete(co)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
return future.result()
       ^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/supertokens.py", line 515, in middleware
api_resp = await matched_recipe.handle_api_request(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/recipe/dashboard/recipe.py", line 191, in handle_api_request
return await api_key_protector(
    ^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/recipe/dashboard/api/api_key_protector.py", line 49, in api_key_protector
response = await api_function(api_implementation, api_options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py", line 131, in handle_user_password_put
return await reset_password(
       ^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py", line 92, in reset_password
form_fields: List[NormalisedFormField] = recipe.get_instance().config.sign_up_feature.form_fields # type: ignore # FIXME?
                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

AttributeError: 'NoneType' object has no attribute 'form_fields'

And for reference my init call:

init(
    app_info=InputAppInfo(
        app_name="PROSPECT 100",
        api_domain=settings.auth.API_DOMAIN,
        website_domain=settings.auth.WEBSITE_DOMAIN,
        api_base_path="/api/v1/auth",
        website_base_path="/auth"
    ),
    supertokens_config=SupertokensConfig(
        connection_uri=settings.supertokens.CONNECTION_URI,
        api_key=settings.supertokens.API_KEY,
    ),
    framework='flask',
    recipe_list=[
        emailverification.init(mode='REQUIRED'),
        session.init(),
        dashboard.init(settings.supertokens.DASHBOARD_KEY),
        thirdpartyemailpassword.init(
            providers=[
                Google(
                    client_id=settings.supertokens.GOOGLE_CLIENT_ID,
                    client_secret=settings.supertokens.GOOGLE_CLIENT_SECRET
                )
            ],
            override=thirdpartyemailpassword.InputOverrideConfig(
                apis=apis_override,
                functions=functions_override,
            ),
        ),
    ]
)

Can you give us some insights on what functions and apis you are overriding ?

mulac commented

I am overriding emailpassword_sign_up and thirdparty_sign_in_up to implement a white list, very similar to what is described at https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/disable-sign-up/thirdparty-changes

def functions_override(recipe: RecipeInterface):
    original_emailpassword_sign_in_up = recipe.emailpassword_sign_up
    original_thirdparty_sign_in_up = recipe.thirdparty_sign_in_up

    async def emailpassword_sign_up(
        email: str, 
        password: str, 
        user_context: Dict[str, Any]
    ) -> Union[EmailPasswordSignUpOkResult, EmailPasswordSignUpEmailAlreadyExistsError]:
        existing_users = await get_users_by_email(email, user_context)
        if existing_users or email_whitelisted(email):
            return await original_emailpassword_sign_in_up(email, password, user_context)
        raise WhitelistException(email)

    async def thirdparty_sign_in_up(
        third_party_id: str, 
        third_party_user_id: str, 
        email: str,
        user_context: Dict[str, Any],
    ) -> ThirdPartySignInUpOkResult:
        existing_users = await get_users_by_email(email, user_context)
        if existing_users or email_whitelisted(email):
            return await original_thirdparty_sign_in_up(third_party_id, third_party_user_id, email, user_context)
        raise WhitelistException(email)

    recipe.emailpassword_sign_up = emailpassword_sign_up
    recipe.thirdparty_sign_in_up = thirdparty_sign_in_up
    return recipe


def apis_override(auth_api: APIInterface):
    auth_api.emailpassword_sign_up_post = WhitelistException.handle(auth_api.emailpassword_sign_up_post)
    auth_api.thirdparty_sign_in_up_post = WhitelistException.handle(auth_api.thirdparty_sign_in_up_post)
    return auth_api

This should have been fixed in version >= 0.12.8.

Closing this issue for now, but feel free to reopen in case it persistss