main.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env python3
  2. import logging
  3. import os
  4. from descope import REFRESH_SESSION_TOKEN_NAME, SESSION_TOKEN_NAME, AuthException, DeliveryMethod, DescopeClient
  5. from fastapi import Request
  6. from fastapi.responses import RedirectResponse
  7. from icecream import ic
  8. from starlette.middleware.base import BaseHTTPMiddleware
  9. import nicegui.globals
  10. from nicegui import Client, app, events, ui
  11. descope_id = os.environ.get('DESCOPE_ID', '')
  12. try:
  13. descope_client = DescopeClient(project_id=descope_id)
  14. except Exception as error:
  15. print("failed to initialize. Error:")
  16. print(error)
  17. def validate_session():
  18. return
  19. # Fetch session token from HTTP Authorization Header
  20. session_token = "xxxx"
  21. try:
  22. jwt_response = descope_client.validate_session(session_token=session_token)
  23. print("Successfully validated user session:")
  24. print(jwt_response)
  25. except Exception:
  26. logging.exception("Could not validate user session.")
  27. class AuthMiddleware(BaseHTTPMiddleware):
  28. """This middleware restricts access to all NiceGUI pages.
  29. It redirects the user to the login page if they are not authenticated.
  30. """
  31. async def dispatch(self, request: Request, call_next):
  32. if not app.storage.user.get('authenticated', False):
  33. if request.url.path in nicegui.globals.page_routes.values() and request.url.path not in unrestricted_page_routes:
  34. app.storage.user['referrer_path'] = request.url.path # remember where the user wanted to go
  35. return RedirectResponse('/login')
  36. return await call_next(request)
  37. app.add_middleware(AuthMiddleware)
  38. unrestricted_page_routes = {'/login'}
  39. def verify(token: str):
  40. ic()
  41. try:
  42. jwt_response = descope_client.validate_session(session_token=token)
  43. ic(jwt_response)
  44. return True
  45. except Exception:
  46. logging.exception("Could not validate user session.")
  47. ui.notify('Wrong username or password', type='negative')
  48. return False
  49. @ui.page('/login')
  50. async def login(client: Client):
  51. ui.add_head_html('<script src="https://unpkg.com/@descope/web-js-sdk/dist/index.umd.js"></script>')
  52. ui.add_body_html('''
  53. <script>
  54. const sdk = Descope({ projectId: \'''' + descope_id + '''\', persistTokens: true, autoRefresh: true });
  55. const sessionToken = sdk.getSessionToken()
  56. </script>
  57. ''')
  58. await client.connected()
  59. token = await ui.run_javascript('''
  60. if (sessionToken && !sdk.isJwtExpired(sessionToken)) {
  61. return sessionToken;
  62. } else {
  63. return null;
  64. }
  65. ''')
  66. with ui.card().classes('w-96 mx-auto'):
  67. if token and verify(token):
  68. app.storage.user['authenticated'] = True
  69. ui.open('/')
  70. else:
  71. ui.add_head_html('<script src="https://unpkg.com/@descope/web-component/dist/index.js"></script>')
  72. ui.element('descope-wc').props(f'project-id="{descope_id}" flow-id="sign-up-or-in"') \
  73. .on('success', lambda: ui.open('/'))
  74. @ui.page('/')
  75. def home():
  76. ui.add_body_html('''
  77. <script src="https://unpkg.com/@descope/web-js-sdk/dist/index.umd.js"></script>
  78. <script>
  79. sdk.refresh()
  80. </script>
  81. ''')
  82. ui.label('Welcome!')
  83. ui.run(storage_secret='THIS_NEEDS_TO_BE_CHANGED')