csrd-utils 0.3.96__tar.gz → 0.3.98__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/PKG-INFO +1 -1
  2. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/pyproject.toml +1 -1
  3. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/presets.py +1 -0
  4. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/db.py.template +20 -2
  5. csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/dependencies/token_service.py +22 -0
  6. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/repositories/user_repository.py +5 -1
  7. csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/services/token_service.py +91 -0
  8. csrd_utils-0.3.98/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +40 -0
  9. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/jwks_view.py +2 -6
  10. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/users_view.py +1 -4
  11. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/__init__.py +1 -0
  12. csrd_utils-0.3.96/src/csrd_utils/v2/templates/augments/jwt-auth-provider/views/auth_view.py +0 -115
  13. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/.gitignore +0 -0
  14. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/README.md +0 -0
  15. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/__init__.py +0 -0
  16. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/__main__.py +0 -0
  17. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/audit.py +0 -0
  18. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/augmentor.py +0 -0
  19. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/cluster.py +0 -0
  20. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/doctor.py +0 -0
  21. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
  22. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
  23. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/manifest.yaml +0 -0
  24. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/requirements.fragment +0 -0
  25. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
  26. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
  27. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
  28. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
  29. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/manifest.yaml +0 -0
  30. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/requirements.fragment +0 -0
  31. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
  32. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
  33. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
  34. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
  35. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
  36. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
  37. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
  38. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
  39. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
  40. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
  41. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
  42. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
  43. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
  44. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
  45. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
  46. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
  47. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
  48. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
  49. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/manifest.yaml +0 -0
  50. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/requirements.fragment +0 -0
  51. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
  52. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
  53. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
  54. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
  55. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
  56. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/fragments.py +0 -0
  57. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/generator.py +0 -0
  58. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/resources.py +0 -0
  59. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
  60. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
  61. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
  62. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
  63. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  64. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  65. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  66. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  67. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
  68. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
  69. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
  70. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  71. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
  72. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
  73. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
  74. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
  75. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
  76. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
  77. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
  78. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  79. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
  80. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  81. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  82. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
  83. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
  84. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
  85. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
  86. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
  87. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
  88. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
  89. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
  90. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
  91. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
  92. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
  93. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  94. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  95. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  96. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
  97. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
  98. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
  99. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/cookiecutter.json +0 -0
  100. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  101. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  102. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  103. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  104. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
  105. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/auth_delegate.py +0 -0
  106. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/delegates/identity_delegate.py +0 -0
  107. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  108. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_passthrough.py +0 -0
  109. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/auth_service.py +0 -0
  110. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
  111. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
  112. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/auth_service.py +0 -0
  113. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/models/items.py +0 -0
  114. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  115. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
  116. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  117. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  118. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  119. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  120. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_service_view.py +0 -0
  121. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  122. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-app-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
  123. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -0
  124. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  125. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  126. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  127. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  128. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  129. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
  130. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/models/auth.py +0 -0
  131. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  132. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -0
  133. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  134. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  135. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  136. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  137. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +0 -0
  138. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  139. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -0
  140. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  141. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  142. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  143. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  144. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  145. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
  146. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/models/users.py +0 -0
  147. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  148. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -0
  149. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  150. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  151. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  152. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  153. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  154. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +0 -0
  155. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/AGENTS.md +0 -0
  156. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/__init__.py +0 -0
  157. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/__init__.py +0 -0
  158. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/augments.py +0 -0
  159. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/git.py +0 -0
  160. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/infra.py +0 -0
  161. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/loader.py +0 -0
  162. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/operations.py +0 -0
  163. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/renderer.py +0 -0
  164. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/scaffolder.py +0 -0
  165. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/service_renderers.py +0 -0
  166. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/compose/yaml_editor.py +0 -0
  167. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/__init__.py +0 -0
  168. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/handlers.py +0 -0
  169. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/helpers.py +0 -0
  170. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/generate/menu.py +0 -0
  171. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/__init__.py +0 -0
  172. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/base.py +0 -0
  173. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/spec.py +0 -0
  174. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/models/types.py +0 -0
  175. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/delegates/auth_delegate.py +0 -0
  176. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/dependencies/auth_passthrough.py +0 -0
  177. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/models/auth_passthrough.py +0 -0
  178. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/auth-passthrough/views/auth_passthrough_view.py +0 -0
  179. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/db-config/dependencies/db.py.template +0 -0
  180. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/db-config/migrations.py.template +0 -0
  181. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-consumer/dependencies/auth.py.template +0 -0
  182. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/migrations.py.template +0 -0
  183. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/auth.py +0 -0
  184. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/jwks.py +0 -0
  185. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/augments/jwt-auth-provider/models/users.py +0 -0
  186. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/cookiecutter.json +0 -0
  187. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  188. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  189. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  190. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/__init__.py +0 -0
  191. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/models/health.py +0 -0
  192. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  193. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  194. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
  195. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
  196. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/tests/test_health.py +0 -0
  197. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  198. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/csrd_utils/v2/templates/service/{{cookiecutter.__service_name_snake}}/views/health_view.py +0 -0
  199. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/__init__.py +0 -0
  200. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/exceptions.py +0 -0
  201. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/menu.py +0 -0
  202. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/models.py +0 -0
  203. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/prompts.py +0 -0
  204. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/terminal.py +0 -0
  205. {csrd_utils-0.3.96 → csrd_utils-0.3.98}/src/tui_wizard/wizard.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csrd-utils
3
- Version: 0.3.96
3
+ Version: 0.3.98
4
4
  Summary: CLI utilities for csrd service generation and feature augmentation
5
5
  Project-URL: Repository, https://github.com/csrd-api/fastapi-common
6
6
  Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csrd-utils"
3
- version = "0.3.96"
3
+ version = "0.3.98"
4
4
  description = "CLI utilities for csrd service generation and feature augmentation"
5
5
  license = { text = "MIT" }
6
6
  requires-python = ">=3.12"
@@ -33,6 +33,7 @@ PRESET_REGISTRY: dict[str, PresetDefinition] = {
33
33
  features=["database"],
34
34
  augments=[
35
35
  ServiceAugment(name="jwt-auth-consumer"),
36
+ ServiceAugment(name="auth-passthrough"),
36
37
  ServiceAugment(name="db-config"),
37
38
  ],
38
39
  ),
@@ -1,4 +1,4 @@
1
- """Database and repository dependencies for the auth service.
1
+ """Database, repository, and key ring dependencies for the auth service.
2
2
 
3
3
  This file is scaffolded once and never overwritten.
4
4
  """
@@ -7,6 +7,8 @@ from typing import Annotated
7
7
 
8
8
  from fastapi import Depends
9
9
 
10
+ from csrd.auth import KeyRingManager
11
+
10
12
  $db_adapter_import
11
13
 
12
14
  from ..repositories.user_repository import UserRepository
@@ -43,4 +45,20 @@ def _user_repository_factory(adapter: Adapter) -> UserRepository:
43
45
 
44
46
  UserRepo = Annotated[UserRepository, Depends(_user_repository_factory)]
45
47
 
46
- __all__ = ("Adapter", "UserRepo")
48
+
49
+ async def _key_ring_factory(adapter: Adapter, settings: Settings) -> KeyRingManager:
50
+ """Create and initialize a ``KeyRingManager`` for JWT signing."""
51
+ key_ring = KeyRingManager(
52
+ adapter=adapter,
53
+ key_size=settings.jwt_key_size,
54
+ rotation_interval=settings.jwt_key_rotation_interval,
55
+ retention_period=settings.jwt_key_retention_period,
56
+ token_ttl=settings.jwt_ttl_seconds,
57
+ )
58
+ await key_ring.initialize()
59
+ return key_ring
60
+
61
+
62
+ KeyRing = Annotated[KeyRingManager, Depends(_key_ring_factory)]
63
+
64
+ __all__ = ("Adapter", "KeyRing", "UserRepo")
@@ -0,0 +1,22 @@
1
+ """Token service dependency for the auth service.
2
+
3
+ This file is scaffolded once and never overwritten.
4
+ """
5
+
6
+ from typing import Annotated
7
+
8
+ from fastapi import Depends
9
+
10
+ from ..services.token_service import TokenService
11
+ from . import Settings
12
+ from .db import KeyRing
13
+
14
+
15
+ def _token_service_factory(key_ring: KeyRing, settings: Settings) -> TokenService:
16
+ """Create a ``TokenService`` with the key ring and settings."""
17
+ return TokenService(key_ring, settings)
18
+
19
+
20
+ TokenSvc = Annotated[TokenService, Depends(_token_service_factory)]
21
+
22
+ __all__ = ("TokenSvc",)
@@ -21,7 +21,11 @@ class UserRepository(BaseRepository):
21
21
  # ── User CRUD ────────────────────────────────────────────────────
22
22
 
23
23
  async def create_user(self, username: str, password: str) -> UserResponse:
24
- """Create a new user with hashed credentials."""
24
+ """Create a new user with hashed credentials. Raises 409 if exists."""
25
+ existing = await self.get_user_by_username(username)
26
+ if existing is not None:
27
+ raise HTTPException(status_code=409, detail="Username already taken")
28
+
25
29
  user_id = str(uuid.uuid4())
26
30
  await self.execute(
27
31
  "INSERT INTO users (id, username) VALUES (:id, :username)",
@@ -0,0 +1,91 @@
1
+ """Token service for JWT issuance and verification.
2
+
3
+ Encapsulates all JWT business logic: signing, verification, and
4
+ claims construction. Views call service methods and return the result.
5
+
6
+ This file is scaffolded once and never overwritten.
7
+ """
8
+
9
+ import time
10
+ from typing import Any
11
+
12
+ import jwt as pyjwt
13
+ from fastapi import HTTPException
14
+ from jwt.algorithms import RSAAlgorithm
15
+
16
+ from csrd.auth import KeyRingManager
17
+
18
+ from ..models.auth import TokenResponse, VerifyClaims, VerifyResponse
19
+
20
+
21
+ class TokenService:
22
+ """JWT token issuance and verification."""
23
+
24
+ def __init__(self, key_ring: KeyRingManager, settings: Any) -> None:
25
+ self._key_ring = key_ring
26
+ self._settings = settings
27
+
28
+ async def issue_token(
29
+ self,
30
+ *,
31
+ user_id: str,
32
+ username: str,
33
+ roles: list[str],
34
+ ) -> TokenResponse:
35
+ """Create a signed JWT for the given user."""
36
+ await self._key_ring.rotate_if_needed()
37
+ kid, private_key = await self._key_ring.active_key()
38
+
39
+ now = int(time.time())
40
+ payload: dict[str, Any] = {
41
+ "sub": user_id,
42
+ "user_name": username,
43
+ "authorities": roles,
44
+ "iat": now,
45
+ "exp": now + self._settings.jwt_ttl_seconds,
46
+ "iss": self._settings.jwt_issuer,
47
+ "aud": self._settings.jwt_audience,
48
+ }
49
+
50
+ token = pyjwt.encode(
51
+ payload,
52
+ private_key,
53
+ algorithm=self._settings.jwt_algorithm,
54
+ headers={"kid": kid},
55
+ )
56
+
57
+ return TokenResponse(access_token=token, expires_in=self._settings.jwt_ttl_seconds)
58
+
59
+ async def verify_token(self, token: str) -> VerifyResponse:
60
+ """Verify a JWT and return its claims. Raises on failure."""
61
+ jwks = await self._key_ring.jwks_dict()
62
+
63
+ try:
64
+ unverified = pyjwt.get_unverified_header(token)
65
+ kid = unverified.get("kid")
66
+
67
+ jwk_data = next(
68
+ (k for k in jwks["keys"] if k["kid"] == kid),
69
+ None,
70
+ )
71
+ if jwk_data is None:
72
+ raise HTTPException(status_code=401, detail="Unknown signing key")
73
+
74
+ public_key = RSAAlgorithm.from_jwk(jwk_data)
75
+
76
+ claims = pyjwt.decode(
77
+ token,
78
+ public_key,
79
+ algorithms=[self._settings.jwt_algorithm],
80
+ issuer=self._settings.jwt_issuer,
81
+ audience=self._settings.jwt_audience,
82
+ )
83
+ return VerifyResponse(active=True, claims=VerifyClaims(**claims))
84
+
85
+ except pyjwt.ExpiredSignatureError:
86
+ raise HTTPException(status_code=401, detail="Token has expired") from None
87
+ except pyjwt.InvalidTokenError as exc:
88
+ raise HTTPException(status_code=401, detail=f"Invalid token: {exc}") from None
89
+
90
+
91
+ __all__ = ("TokenService",)
@@ -0,0 +1,40 @@
1
+ """Token issuance and verification endpoints.
2
+
3
+ This file is scaffolded once and never overwritten.
4
+ """
5
+
6
+ from fastapi import APIRouter
7
+
8
+ from ..dependencies.db import UserRepo
9
+ from ..dependencies.token_service import TokenSvc
10
+ from ..models.auth import (
11
+ TokenRequest,
12
+ TokenResponse,
13
+ VerifyRequest,
14
+ VerifyResponse,
15
+ )
16
+
17
+ router = APIRouter(tags=["auth"])
18
+
19
+
20
+
21
+ @router.post("/api/token", response_model=TokenResponse)
22
+ async def issue_token(
23
+ body: TokenRequest,
24
+ repo: UserRepo,
25
+ token_svc: TokenSvc,
26
+ ) -> TokenResponse:
27
+ """Validate credentials and issue a JWT access token."""
28
+ user = await repo.verify_credentials(body.username, body.password)
29
+ roles_resp = await repo.get_user_roles(user.id)
30
+ return await token_svc.issue_token(
31
+ user_id=user.id,
32
+ username=user.username,
33
+ roles=roles_resp.roles,
34
+ )
35
+
36
+
37
+ @router.post("/api/verify", response_model=VerifyResponse)
38
+ async def verify_token(body: VerifyRequest, token_svc: TokenSvc) -> VerifyResponse:
39
+ """Verify a JWT and return its claims."""
40
+ return await token_svc.verify_token(body.token)
@@ -6,7 +6,7 @@ This file is scaffolded once and never overwritten.
6
6
 
7
7
  from fastapi import APIRouter
8
8
 
9
- from ..dependencies.db import Adapter
9
+ from ..dependencies.db import KeyRing
10
10
  from ..models.jwks import JWKSResponse
11
11
 
12
12
  router = APIRouter(tags=["jwks"])
@@ -14,15 +14,11 @@ router = APIRouter(tags=["jwks"])
14
14
 
15
15
 
16
16
  @router.get("/.well-known/jwks.json", response_model=JWKSResponse)
17
- async def jwks(adapter: Adapter) -> JWKSResponse:
17
+ async def jwks(key_ring: KeyRing) -> JWKSResponse:
18
18
  """Return public keys for all active signing keys in JWK format.
19
19
 
20
20
  Consumers cache this response and refresh automatically when
21
21
  they encounter an unknown ``kid`` in a token header.
22
22
  """
23
- from csrd.auth import KeyRingManager
24
-
25
- key_ring = KeyRingManager(adapter=adapter)
26
- await key_ring.initialize()
27
23
  jwks_data = await key_ring.jwks_dict()
28
24
  return JWKSResponse(keys=jwks_data["keys"])
@@ -3,7 +3,7 @@
3
3
  This file is scaffolded once and never overwritten.
4
4
  """
5
5
 
6
- from fastapi import APIRouter, HTTPException
6
+ from fastapi import APIRouter
7
7
 
8
8
  from ..dependencies.db import UserRepo
9
9
  from ..models.users import (
@@ -20,9 +20,6 @@ router = APIRouter(tags=["users"])
20
20
  @router.post("/api/signup", status_code=201, response_model=UserResponse)
21
21
  async def signup(body: SignupRequest, repo: UserRepo) -> UserResponse:
22
22
  """Create a new user account."""
23
- existing = await repo.get_user_by_username(body.username)
24
- if existing is not None:
25
- raise HTTPException(status_code=409, detail="Username already taken")
26
23
  return await repo.create_user(body.username, body.password)
27
24
 
28
25
 
@@ -16,6 +16,7 @@ def build_app() -> FastAPI:
16
16
  version_mapping={UNVERSIONED: unversioned_app},
17
17
  config=VersionedAppComposeConfig(
18
18
  title="{{ cookiecutter.service_name }}",
19
+ app_state={"settings": settings},
19
20
  api=VersionedApiConfig(
20
21
  prefix="/",
21
22
  include_actuator_endpoints=settings.include_actuator_endpoints,
@@ -1,115 +0,0 @@
1
- """Token issuance and verification endpoints.
2
-
3
- This file is scaffolded once and never overwritten.
4
- """
5
-
6
- import time
7
- from typing import Any
8
-
9
- import jwt as pyjwt
10
- from fastapi import APIRouter, HTTPException
11
-
12
- from ..dependencies import Settings
13
- from ..dependencies.db import Adapter, UserRepo
14
- from ..models.auth import (
15
- TokenRequest,
16
- TokenResponse,
17
- VerifyClaims,
18
- VerifyRequest,
19
- VerifyResponse,
20
- )
21
-
22
- router = APIRouter(tags=["auth"])
23
-
24
-
25
-
26
- @router.post("/api/token", response_model=TokenResponse)
27
- async def issue_token(
28
- body: TokenRequest,
29
- settings: Settings,
30
- adapter: Adapter,
31
- repo: UserRepo,
32
- ) -> TokenResponse:
33
- """Validate credentials and issue a JWT access token."""
34
- user = await repo.verify_credentials(body.username, body.password)
35
- roles_resp = await repo.get_user_roles(user.id)
36
-
37
- # Get the active signing key
38
- from csrd.auth import KeyRingManager
39
-
40
- key_ring = KeyRingManager(
41
- adapter=adapter,
42
- key_size=settings.jwt_key_size,
43
- rotation_interval=settings.jwt_key_rotation_interval,
44
- retention_period=settings.jwt_key_retention_period,
45
- token_ttl=settings.jwt_ttl_seconds,
46
- )
47
- await key_ring.initialize()
48
- await key_ring.rotate_if_needed()
49
- kid, private_key = await key_ring.active_key()
50
-
51
- now = int(time.time())
52
- payload: dict[str, Any] = {
53
- "sub": user.id,
54
- "user_name": user.username,
55
- "authorities": roles_resp.roles,
56
- "iat": now,
57
- "exp": now + settings.jwt_ttl_seconds,
58
- "iss": settings.jwt_issuer,
59
- "aud": settings.jwt_audience,
60
- }
61
-
62
- token = pyjwt.encode(
63
- payload,
64
- private_key,
65
- algorithm=settings.jwt_algorithm,
66
- headers={"kid": kid},
67
- )
68
-
69
- return TokenResponse(access_token=token, expires_in=settings.jwt_ttl_seconds)
70
-
71
-
72
- @router.post("/api/verify", response_model=VerifyResponse)
73
- async def verify_token(
74
- body: VerifyRequest,
75
- settings: Settings,
76
- adapter: Adapter,
77
- ) -> VerifyResponse:
78
- """Verify a JWT and return its claims."""
79
-
80
- from csrd.auth import KeyRingManager
81
-
82
- key_ring = KeyRingManager(adapter=adapter)
83
- await key_ring.initialize()
84
- jwks = await key_ring.jwks_dict()
85
-
86
- try:
87
- # Get the kid from the token header
88
- unverified = pyjwt.get_unverified_header(body.token)
89
- kid = unverified.get("kid")
90
-
91
- # Find the matching public key
92
- from jwt.algorithms import RSAAlgorithm
93
-
94
- jwk_data = next(
95
- (k for k in jwks["keys"] if k["kid"] == kid),
96
- None,
97
- )
98
- if jwk_data is None:
99
- raise HTTPException(status_code=401, detail="Unknown signing key")
100
-
101
- public_key = RSAAlgorithm.from_jwk(jwk_data)
102
-
103
- claims = pyjwt.decode(
104
- body.token,
105
- public_key,
106
- algorithms=[settings.jwt_algorithm],
107
- issuer=settings.jwt_issuer,
108
- audience=settings.jwt_audience,
109
- )
110
- return VerifyResponse(active=True, claims=VerifyClaims(**claims))
111
-
112
- except pyjwt.ExpiredSignatureError:
113
- raise HTTPException(status_code=401, detail="Token has expired") from None
114
- except pyjwt.InvalidTokenError as exc:
115
- raise HTTPException(status_code=401, detail=f"Invalid token: {exc}") from None
File without changes
File without changes