user.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import logging
  2. import os
  3. from typing import Any, Callable
  4. from descope import DescopeClient
  5. from nicegui import Client, app, ui
  6. descope_id = os.environ.get('DESCOPE_ID', '')
  7. try:
  8. descope_client = DescopeClient(project_id=descope_id)
  9. except Exception as error:
  10. print("failed to initialize. Error:")
  11. print(error)
  12. async def logout():
  13. result = await ui.run_javascript('return await sdk.logout()', respond=True)
  14. if result['code'] != 200:
  15. logging.error('Logout failed: ' + result)
  16. ui.notify('Logout failed', type='negative')
  17. ui.open('/login')
  18. def _verify(token: str):
  19. try:
  20. jwt_response = descope_client.validate_session(session_token=token)
  21. ic(jwt_response)
  22. app.storage.user['user_id'] = jwt_response['userId']
  23. return True
  24. except Exception:
  25. app.storage.user['user_id'] = None
  26. logging.exception("Could not validate user session.")
  27. ui.notify('Wrong username or password', type='negative')
  28. return False
  29. def login_form():
  30. with ui.card().classes('w-96 mx-auto'):
  31. return ui.element('descope-wc').props(f'project-id="{descope_id}" flow-id="sign-up-or-in"')
  32. class page(ui.page):
  33. def __init__(self, path):
  34. super().__init__(path)
  35. def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
  36. async def content(client: Client):
  37. ui.add_head_html('<script src="https://unpkg.com/@descope/web-component@latest/dist/index.js"></script>')
  38. ui.add_head_html('<script src="https://unpkg.com/@descope/web-js-sdk@latest/dist/index.umd.js"></script>')
  39. ui.add_body_html('''
  40. <script>
  41. const sdk = Descope({ projectId: \'''' + descope_id + '''\', persistTokens: true, autoRefresh: true });
  42. const sessionToken = sdk.getSessionToken()
  43. </script>
  44. ''')
  45. await client.connected()
  46. token = await ui.run_javascript('return sessionToken && !sdk.isJwtExpired(sessionToken) ? sessionToken : null;')
  47. if token and _verify(token):
  48. if self.path == '/login':
  49. await ui.run_javascript('sdk.refresh()', respond=False)
  50. ui.open('/')
  51. else:
  52. func()
  53. else:
  54. if self.path != '/login':
  55. ui.open('/login')
  56. else:
  57. func()
  58. return super().__call__(content)
  59. def login_page(func: Callable[..., Any]) -> Callable[..., Any]:
  60. return page('/login')(func)