secure_page.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import logging
  2. import os
  3. from typing import Any, Callable
  4. from descope import REFRESH_SESSION_TOKEN_NAME, SESSION_TOKEN_NAME, AuthException, DeliveryMethod, 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. ic(await ui.run_javascript('return await sdk.logout()', respond=True))
  14. ui.open('/login')
  15. def verify(token: str):
  16. try:
  17. jwt_response = descope_client.validate_session(session_token=token)
  18. app.storage.user['session_token'] = token
  19. return True
  20. except Exception:
  21. app.storage.user['session_token'] = None
  22. logging.exception("Could not validate user session.")
  23. ui.notify('Wrong username or password', type='negative')
  24. return False
  25. class secure_page(ui.page):
  26. def __init__(self, path):
  27. super().__init__(path)
  28. def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
  29. async def content(client: Client):
  30. ui.add_head_html('<script src="https://unpkg.com/@descope/web-component@latest/dist/index.js"></script>')
  31. ui.add_head_html('<script src="https://unpkg.com/@descope/web-js-sdk@latest/dist/index.umd.js"></script>')
  32. ui.add_body_html('''
  33. <script>
  34. const sdk = Descope({ projectId: \'''' + descope_id + '''\', persistTokens: true, autoRefresh: true });
  35. const sessionToken = sdk.getSessionToken()
  36. </script>
  37. ''')
  38. await client.connected()
  39. token = await ui.run_javascript('return sessionToken && !sdk.isJwtExpired(sessionToken) ? sessionToken : null;')
  40. if token and verify(token):
  41. if self.path == '/login':
  42. await ui.run_javascript('sdk.refresh()', respond=False)
  43. ui.open('/')
  44. else:
  45. func()
  46. else:
  47. if self.path != '/login':
  48. ui.open('/login')
  49. else:
  50. func()
  51. return super().__call__(content)