legate 0.1.0

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 (317) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +345 -0
  4. data/bin/legate +13 -0
  5. data/examples/00_quickstart.rb +51 -0
  6. data/examples/01_simple_agent.rb +105 -0
  7. data/examples/02_multi_tool_agent.rb +140 -0
  8. data/examples/03_custom_tool.rb +93 -0
  9. data/examples/04_agent_instructions.rb +84 -0
  10. data/examples/05_state_and_sessions.rb +91 -0
  11. data/examples/06_callbacks.rb +186 -0
  12. data/examples/07_async_jobs.rb +112 -0
  13. data/examples/08_loop_agent.rb +197 -0
  14. data/examples/09_sequential_workflow.rb +40 -0
  15. data/examples/10_parallel_workflow.rb +34 -0
  16. data/examples/11_agent_delegation.rb +24 -0
  17. data/examples/12_http_client_tool.rb +156 -0
  18. data/examples/13_authentication.rb +220 -0
  19. data/examples/14_mcp_client.rb +154 -0
  20. data/examples/15_mcp_server.rb +79 -0
  21. data/examples/16_webhooks.rb +91 -0
  22. data/examples/README_sequential_agents.md +164 -0
  23. data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
  24. data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
  25. data/examples/advanced/auth/excon_middleware.rb +317 -0
  26. data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
  27. data/examples/advanced/auth/fiber_auth_example.rb +281 -0
  28. data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
  29. data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
  30. data/examples/advanced/auth/oauth2_auth.rb +419 -0
  31. data/examples/advanced/auth/oidc_auth.rb +514 -0
  32. data/examples/advanced/auth/openweather_api.rb +251 -0
  33. data/examples/advanced/auth/openweather_tool.rb +153 -0
  34. data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
  35. data/examples/advanced/auth/service_account.rb +135 -0
  36. data/examples/advanced/auth/test_with_httpbin.rb +202 -0
  37. data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
  38. data/examples/advanced/callback_monitoring.rb +679 -0
  39. data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
  40. data/examples/advanced/mas/loop_workflow.rb +28 -0
  41. data/examples/advanced/mas/mock_planner.rb +77 -0
  42. data/examples/advanced/mas/proper_delegation_example.rb +276 -0
  43. data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
  44. data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
  45. data/examples/advanced/mcp/mcp_server_async.rb +76 -0
  46. data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
  47. data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
  48. data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
  49. data/examples/advanced/random_calculator.rb +104 -0
  50. data/examples/advanced/sleep_agent.rb +153 -0
  51. data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
  52. data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
  53. data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
  54. data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
  55. data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
  56. data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
  57. data/examples/tools/oauth2_example.rb +136 -0
  58. data/examples/tools/sleepy_tool.rb +42 -0
  59. data/lib/legate/activity_log.rb +71 -0
  60. data/lib/legate/agent.rb +959 -0
  61. data/lib/legate/agent_code_generator.rb +185 -0
  62. data/lib/legate/agent_definition.rb +812 -0
  63. data/lib/legate/agentic/decision.rb +49 -0
  64. data/lib/legate/agentic/loop.rb +134 -0
  65. data/lib/legate/agentic.rb +5 -0
  66. data/lib/legate/agents/loop_agent.rb +248 -0
  67. data/lib/legate/agents/parallel_agent.rb +163 -0
  68. data/lib/legate/agents/sequential_agent.rb +190 -0
  69. data/lib/legate/agents.rb +14 -0
  70. data/lib/legate/auth/config.rb +148 -0
  71. data/lib/legate/auth/coordinator.rb +218 -0
  72. data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
  73. data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
  74. data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
  75. data/lib/legate/auth/credential.rb +157 -0
  76. data/lib/legate/auth/encryption.rb +108 -0
  77. data/lib/legate/auth/error.rb +94 -0
  78. data/lib/legate/auth/exchanged_credential.rb +180 -0
  79. data/lib/legate/auth/excon_middleware.rb +285 -0
  80. data/lib/legate/auth/http_client_utils.rb +364 -0
  81. data/lib/legate/auth/manager.rb +531 -0
  82. data/lib/legate/auth/manager_store.rb +394 -0
  83. data/lib/legate/auth/middleware_factory.rb +290 -0
  84. data/lib/legate/auth/runner.rb +279 -0
  85. data/lib/legate/auth/scheme.rb +125 -0
  86. data/lib/legate/auth/schemes/api_key.rb +212 -0
  87. data/lib/legate/auth/schemes/google_service_account.rb +108 -0
  88. data/lib/legate/auth/schemes/http_bearer.rb +98 -0
  89. data/lib/legate/auth/schemes/oauth2.rb +396 -0
  90. data/lib/legate/auth/schemes/openid_connect.rb +346 -0
  91. data/lib/legate/auth/schemes/service_account.rb +388 -0
  92. data/lib/legate/auth/schemes.rb +40 -0
  93. data/lib/legate/auth/token_manager.rb +362 -0
  94. data/lib/legate/auth/token_store.rb +86 -0
  95. data/lib/legate/auth/tool_context_extension.rb +97 -0
  96. data/lib/legate/auth/tool_integration.rb +188 -0
  97. data/lib/legate/auth/url_guard.rb +81 -0
  98. data/lib/legate/auth.rb +453 -0
  99. data/lib/legate/callbacks/callback_context.rb +71 -0
  100. data/lib/legate/cli/agent_commands.rb +950 -0
  101. data/lib/legate/cli/auth_commands.rb +520 -0
  102. data/lib/legate/cli/base_command.rb +24 -0
  103. data/lib/legate/cli/deployment_commands.rb +934 -0
  104. data/lib/legate/cli/output_helper.rb +108 -0
  105. data/lib/legate/cli/session_commands.rb +138 -0
  106. data/lib/legate/cli/skaffold_commands.rb +223 -0
  107. data/lib/legate/cli/tool_commands.rb +261 -0
  108. data/lib/legate/cli/web_commands.rb +182 -0
  109. data/lib/legate/cli.rb +40 -0
  110. data/lib/legate/configuration/webhooks.rb +113 -0
  111. data/lib/legate/configuration.rb +39 -0
  112. data/lib/legate/definition_store.rb +23 -0
  113. data/lib/legate/errors.rb +118 -0
  114. data/lib/legate/event.rb +161 -0
  115. data/lib/legate/gemini_ai_beta_patch.rb +39 -0
  116. data/lib/legate/generators/agent_generator.rb +412 -0
  117. data/lib/legate/generators/code_validator.rb +48 -0
  118. data/lib/legate/generators/legate/install_generator.rb +35 -0
  119. data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
  120. data/lib/legate/generators/legate/templates/initializer.rb +18 -0
  121. data/lib/legate/generators/runtime_tool_loader.rb +76 -0
  122. data/lib/legate/generators/tool_generator.rb +408 -0
  123. data/lib/legate/generators.rb +11 -0
  124. data/lib/legate/global_definition_registry.rb +506 -0
  125. data/lib/legate/global_tool_manager.rb +135 -0
  126. data/lib/legate/llm/adapter.rb +69 -0
  127. data/lib/legate/llm/gemini.rb +172 -0
  128. data/lib/legate/llm/ollama.rb +80 -0
  129. data/lib/legate/llm.rb +34 -0
  130. data/lib/legate/mcp/client.rb +320 -0
  131. data/lib/legate/mcp/connection/sse.rb +292 -0
  132. data/lib/legate/mcp/connection/stdio.rb +273 -0
  133. data/lib/legate/mcp/connection_manager.rb +103 -0
  134. data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
  135. data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
  136. data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
  137. data/lib/legate/mcp/tool_wrapper.rb +138 -0
  138. data/lib/legate/mcp/util/schema_converter.rb +134 -0
  139. data/lib/legate/mcp.rb +23 -0
  140. data/lib/legate/plan_executor.rb +375 -0
  141. data/lib/legate/planner.rb +839 -0
  142. data/lib/legate/rails/railtie.rb +43 -0
  143. data/lib/legate/rails.rb +9 -0
  144. data/lib/legate/redaction.rb +32 -0
  145. data/lib/legate/session.rb +299 -0
  146. data/lib/legate/session_service/active_record.rb +300 -0
  147. data/lib/legate/session_service/base.rb +68 -0
  148. data/lib/legate/session_service/event_broadcast.rb +74 -0
  149. data/lib/legate/session_service/in_memory.rb +188 -0
  150. data/lib/legate/tool/metadata_dsl.rb +122 -0
  151. data/lib/legate/tool.rb +276 -0
  152. data/lib/legate/tool_code_generator.rb +103 -0
  153. data/lib/legate/tool_context.rb +350 -0
  154. data/lib/legate/tool_loader.rb +39 -0
  155. data/lib/legate/tool_registry.rb +73 -0
  156. data/lib/legate/tool_result.rb +61 -0
  157. data/lib/legate/tools/agent_tool.rb +187 -0
  158. data/lib/legate/tools/base/http_client.rb +319 -0
  159. data/lib/legate/tools/base/safe_url.rb +56 -0
  160. data/lib/legate/tools/base_async_job_tool.rb +91 -0
  161. data/lib/legate/tools/calculator.rb +89 -0
  162. data/lib/legate/tools/cat_facts.rb +81 -0
  163. data/lib/legate/tools/check_job_status_tool.rb +48 -0
  164. data/lib/legate/tools/current_time_tool.rb +64 -0
  165. data/lib/legate/tools/echo.rb +43 -0
  166. data/lib/legate/tools/http_request_tool.rb +105 -0
  167. data/lib/legate/tools/random_number_tool.rb +64 -0
  168. data/lib/legate/tools/read_webpage_tool.rb +92 -0
  169. data/lib/legate/tools/sleepy_tool.rb +74 -0
  170. data/lib/legate/tools/webhook_tool.rb +146 -0
  171. data/lib/legate/version.rb +5 -0
  172. data/lib/legate/web/app.rb +984 -0
  173. data/lib/legate/web/public/css/main.css +4980 -0
  174. data/lib/legate/web/public/images/favicon-256.png +0 -0
  175. data/lib/legate/web/public/images/favicon-32.png +0 -0
  176. data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
  177. data/lib/legate/web/public/images/legate-logo-light.png +0 -0
  178. data/lib/legate/web/public/js/legate.js +616 -0
  179. data/lib/legate/web/public/styles/main.scss +4402 -0
  180. data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
  181. data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
  182. data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
  183. data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
  184. data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
  185. data/lib/legate/web/routes/api_routes.rb +56 -0
  186. data/lib/legate/web/routes/authentication_routes.rb +1541 -0
  187. data/lib/legate/web/routes/core_routes.rb +111 -0
  188. data/lib/legate/web/routes/documentation_routes.rb +220 -0
  189. data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
  190. data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
  191. data/lib/legate/web/sass_compiler.rb +73 -0
  192. data/lib/legate/web/views/_active_session_info.slim +25 -0
  193. data/lib/legate/web/views/_activity_list.slim +55 -0
  194. data/lib/legate/web/views/_agent_card.slim +56 -0
  195. data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
  196. data/lib/legate/web/views/_agent_status_controls.slim +71 -0
  197. data/lib/legate/web/views/_agent_tool_table.slim +74 -0
  198. data/lib/legate/web/views/_chat_message.slim +95 -0
  199. data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
  200. data/lib/legate/web/views/_display_agent_description.slim +11 -0
  201. data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
  202. data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
  203. data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
  204. data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
  205. data/lib/legate/web/views/_display_agent_model.slim +17 -0
  206. data/lib/legate/web/views/_display_agent_name.slim +42 -0
  207. data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
  208. data/lib/legate/web/views/_display_agent_type.slim +65 -0
  209. data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
  210. data/lib/legate/web/views/_edit_agent_description.slim +16 -0
  211. data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
  212. data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
  213. data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
  214. data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
  215. data/lib/legate/web/views/_edit_agent_model.slim +23 -0
  216. data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
  217. data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
  218. data/lib/legate/web/views/_edit_agent_type.slim +67 -0
  219. data/lib/legate/web/views/_session_error.slim +4 -0
  220. data/lib/legate/web/views/_skeleton.slim +69 -0
  221. data/lib/legate/web/views/_tool_card.slim +9 -0
  222. data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
  223. data/lib/legate/web/views/agent.slim +436 -0
  224. data/lib/legate/web/views/agent_auth.slim +562 -0
  225. data/lib/legate/web/views/agents.slim +369 -0
  226. data/lib/legate/web/views/auth.slim +112 -0
  227. data/lib/legate/web/views/auth_credential_detail.slim +327 -0
  228. data/lib/legate/web/views/auth_credentials.slim +261 -0
  229. data/lib/legate/web/views/auth_debug.slim +94 -0
  230. data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
  231. data/lib/legate/web/views/auth_mapping_new.slim +123 -0
  232. data/lib/legate/web/views/auth_mappings.slim +120 -0
  233. data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
  234. data/lib/legate/web/views/auth_schemes.slim +259 -0
  235. data/lib/legate/web/views/auth_test.slim +418 -0
  236. data/lib/legate/web/views/chat.slim +192 -0
  237. data/lib/legate/web/views/docs_index.slim +105 -0
  238. data/lib/legate/web/views/docs_show.slim +105 -0
  239. data/lib/legate/web/views/error_404.slim +5 -0
  240. data/lib/legate/web/views/index.slim +148 -0
  241. data/lib/legate/web/views/layout.slim +144 -0
  242. data/lib/legate/web/views/tool_detail.slim +87 -0
  243. data/lib/legate/web/views/tools.slim +50 -0
  244. data/lib/legate/web/webhook_listener.rb +367 -0
  245. data/lib/legate/web.rb +9 -0
  246. data/lib/legate.rb +220 -0
  247. data/public/docs/advanced/callbacks.md +828 -0
  248. data/public/docs/advanced/mcp_schema_conversion.md +59 -0
  249. data/public/docs/authentication/api_reference/config.md +210 -0
  250. data/public/docs/authentication/api_reference/credential.md +246 -0
  251. data/public/docs/authentication/api_reference/encryption.md +218 -0
  252. data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
  253. data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
  254. data/public/docs/authentication/api_reference/index.md +30 -0
  255. data/public/docs/authentication/api_reference/scheme.md +250 -0
  256. data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
  257. data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
  258. data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
  259. data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
  260. data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
  261. data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
  262. data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
  263. data/public/docs/authentication/api_reference/token_manager.md +221 -0
  264. data/public/docs/authentication/api_reference/token_store.md +146 -0
  265. data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
  266. data/public/docs/authentication/guides/api_key.md +190 -0
  267. data/public/docs/authentication/guides/bearer.md +172 -0
  268. data/public/docs/authentication/guides/configuration.md +255 -0
  269. data/public/docs/authentication/guides/custom_flow.md +523 -0
  270. data/public/docs/authentication/guides/index.md +24 -0
  271. data/public/docs/authentication/guides/migration.md +435 -0
  272. data/public/docs/authentication/guides/oauth2.md +252 -0
  273. data/public/docs/authentication/guides/oidc.md +241 -0
  274. data/public/docs/authentication/guides/overview.md +155 -0
  275. data/public/docs/authentication/guides/secure_storage.md +301 -0
  276. data/public/docs/authentication/guides/service_account.md +228 -0
  277. data/public/docs/authentication/guides/token_lifecycle.md +295 -0
  278. data/public/docs/authentication/guides/web_ui_integration.md +504 -0
  279. data/public/docs/authentication/index.md +58 -0
  280. data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
  281. data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
  282. data/public/docs/authentication/troubleshooting/index.md +11 -0
  283. data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
  284. data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
  285. data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
  286. data/public/docs/cli/legate_cli_usage.md +363 -0
  287. data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
  288. data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
  289. data/public/docs/core_concepts/legate_configuration.md +116 -0
  290. data/public/docs/core_concepts/legate_definition_store.md +102 -0
  291. data/public/docs/core_concepts/legate_planner.md +94 -0
  292. data/public/docs/core_concepts/legate_session_service.md +104 -0
  293. data/public/docs/error_handling/legate_error_handling.md +122 -0
  294. data/public/docs/examples.md +199 -0
  295. data/public/docs/getting_started.md +111 -0
  296. data/public/docs/guides/agentic_agents.md +137 -0
  297. data/public/docs/guides/ai_code_generators.md +437 -0
  298. data/public/docs/guides/auto_loading.md +326 -0
  299. data/public/docs/guides/configuring_agent_webhooks.md +219 -0
  300. data/public/docs/guides/http_client_usage.md +264 -0
  301. data/public/docs/guides/llm_providers.md +137 -0
  302. data/public/docs/guides/mcp_client_integration.md +232 -0
  303. data/public/docs/guides/mcp_server_exposure.md +206 -0
  304. data/public/docs/guides/rails_integration.md +128 -0
  305. data/public/docs/guides/sending_outbound_webhooks.md +227 -0
  306. data/public/docs/guides/streaming.md +112 -0
  307. data/public/docs/guides/webhooks.md +288 -0
  308. data/public/docs/introduction.md +51 -0
  309. data/public/docs/multi_agent_systems/advanced_features.md +57 -0
  310. data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
  311. data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
  312. data/public/docs/multi_agent_systems/state_management.md +47 -0
  313. data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
  314. data/public/docs/tools/legate_built_in_tools.md +332 -0
  315. data/public/docs/tools/legate_tools_and_registry.md +263 -0
  316. data/public/docs/web_ui/legate_web_ui.md +137 -0
  317. metadata +823 -0
@@ -0,0 +1,504 @@
1
+ # Authentication Web UI Integration
2
+
3
+ ## Overview
4
+
5
+ The Legate Ruby library provides integration between the authentication system and the Web UI, enabling interactive authentication flows directly from the web interface. This guide explains how to integrate authentication with the Web UI and implement visual flows for authentication schemes like OAuth2 and OpenID Connect.
6
+
7
+ ## Key Features
8
+
9
+ - Authentication status indicators in the Web UI
10
+ - Interactive login flows for OAuth2 and OIDC
11
+ - Token management interface for viewing and revoking tokens
12
+ - Secure credential storage in the browser
13
+ - Authentication debugging panels
14
+
15
+ ## Web UI Authentication Components
16
+
17
+ ### Authentication Status Indicator
18
+
19
+ The Legate Web UI includes an authentication status indicator that shows the current authentication state for tools requiring authentication:
20
+
21
+ ```html
22
+ <!-- Authentication status indicator component -->
23
+ <div class="auth-status">
24
+ <span class="auth-status-icon authenticated"></span>
25
+ <span class="auth-status-text">Authenticated</span>
26
+ </div>
27
+ ```
28
+
29
+ ### Login Interface
30
+
31
+ The Web UI provides a login interface for initiating authentication flows:
32
+
33
+ ```html
34
+ <!-- Login button for OAuth2 authentication -->
35
+ <button class="login-button" data-auth-scheme="oauth2">
36
+ Log in with OAuth2
37
+ </button>
38
+ ```
39
+
40
+ ### Token Information Display
41
+
42
+ The Web UI includes a token information display for viewing active tokens:
43
+
44
+ ```html
45
+ <!-- Token information display -->
46
+ <div class="token-info">
47
+ <div class="token-status">
48
+ <span class="label">Status:</span>
49
+ <span class="value">Valid</span>
50
+ </div>
51
+ <div class="token-expiry">
52
+ <span class="label">Expires:</span>
53
+ <span class="value">2023-12-31 23:59:59 UTC</span>
54
+ </div>
55
+ <div class="token-scopes">
56
+ <span class="label">Scopes:</span>
57
+ <span class="value">read write</span>
58
+ </div>
59
+ </div>
60
+ ```
61
+
62
+ ## Interactive Authentication Flows
63
+
64
+ ### OAuth2 Authentication Flow
65
+
66
+ The Web UI implements the OAuth2 authorization code flow with the following steps:
67
+
68
+ 1. User clicks the login button for a tool requiring OAuth2 authentication
69
+ 2. The Web UI displays a login popup or redirects to the OAuth2 provider
70
+ 3. User completes authentication on the provider's site
71
+ 4. The provider redirects back to the Legate callback URL
72
+ 5. The Web UI captures the authorization code and exchanges it for tokens
73
+ 6. The Web UI resumes the tool execution with the obtained tokens
74
+
75
+ ```javascript
76
+ // JavaScript for handling OAuth2 authentication flow
77
+ function initiateOAuth2Flow(authConfig) {
78
+ // Generate and store state parameter to prevent CSRF attacks
79
+ const state = generateSecureRandomString();
80
+ sessionStorage.setItem('oauth2_state', state);
81
+
82
+ // Construct the authorization URL
83
+ const authUrl = new URL(authConfig.authorizationUrl);
84
+ authUrl.searchParams.append('client_id', authConfig.clientId);
85
+ authUrl.searchParams.append('redirect_uri', authConfig.redirectUri);
86
+ authUrl.searchParams.append('response_type', 'code');
87
+ authUrl.searchParams.append('state', state);
88
+ if (authConfig.scopes) {
89
+ authUrl.searchParams.append('scope', authConfig.scopes.join(' '));
90
+ }
91
+
92
+ // Open the authorization URL in a popup window
93
+ window.open(authUrl.toString(), 'oauth2_popup', 'width=600,height=700');
94
+ }
95
+ ```
96
+
97
+ ### OAuth2 Callback Handling
98
+
99
+ The Web UI includes a callback endpoint for handling OAuth2 redirects:
100
+
101
+ ```ruby
102
+ # Ruby route for handling OAuth2 callbacks
103
+ get '/auth/callback' do
104
+ # Verify state parameter to prevent CSRF attacks
105
+ client_state = request.params['state']
106
+ server_state = session[:oauth2_state]
107
+ halt 403, 'Invalid state parameter' unless client_state && client_state == server_state
108
+
109
+ # Get the authorization code from the callback
110
+ code = request.params['code']
111
+ halt 400, 'Missing authorization code' unless code
112
+
113
+ # Store the authorization code in the session
114
+ session[:auth_code] = code
115
+ session[:auth_response_uri] = request.url
116
+
117
+ # Close the popup window and notify the parent window
118
+ <<-HTML
119
+ <script>
120
+ window.opener.postMessage({ type: 'auth_callback', code: '#{code}' }, window.location.origin);
121
+ window.close();
122
+ </script>
123
+ HTML
124
+ end
125
+ ```
126
+
127
+ ## Token Management
128
+
129
+ ### Token Management Interface
130
+
131
+ The Web UI provides a token management interface for viewing and managing active tokens:
132
+
133
+ ```html
134
+ <!-- Token management interface -->
135
+ <div class="token-management">
136
+ <h2>Active Tokens</h2>
137
+ <table class="token-table">
138
+ <thead>
139
+ <tr>
140
+ <th>API</th>
141
+ <th>Status</th>
142
+ <th>Expires</th>
143
+ <th>Actions</th>
144
+ </tr>
145
+ </thead>
146
+ <tbody>
147
+ <tr>
148
+ <td>Google Drive API</td>
149
+ <td>Valid</td>
150
+ <td>2023-12-31 23:59:59 UTC</td>
151
+ <td>
152
+ <button class="refresh-token-button">Refresh</button>
153
+ <button class="revoke-token-button">Revoke</button>
154
+ </td>
155
+ </tr>
156
+ </tbody>
157
+ </table>
158
+ </div>
159
+ ```
160
+
161
+ ### Token Refresh
162
+
163
+ The Web UI allows users to manually refresh tokens:
164
+
165
+ ```javascript
166
+ // JavaScript for handling token refresh
167
+ async function refreshToken(credentialId) {
168
+ try {
169
+ const response = await fetch('/api/auth/refresh', {
170
+ method: 'POST',
171
+ headers: {
172
+ 'Content-Type': 'application/json'
173
+ },
174
+ body: JSON.stringify({ credential_id: credentialId })
175
+ });
176
+
177
+ if (!response.ok) {
178
+ throw new Error('Failed to refresh token');
179
+ }
180
+
181
+ const result = await response.json();
182
+ updateTokenDisplay(result.tokens);
183
+ showNotification('Token refreshed successfully');
184
+ } catch (error) {
185
+ showErrorNotification('Failed to refresh token: ' + error.message);
186
+ }
187
+ }
188
+ ```
189
+
190
+ ### Token Revocation
191
+
192
+ The Web UI allows users to revoke tokens:
193
+
194
+ ```javascript
195
+ // JavaScript for handling token revocation
196
+ async function revokeToken(credentialId) {
197
+ if (!confirm('Are you sure you want to revoke this token? You will need to authenticate again.')) {
198
+ return;
199
+ }
200
+
201
+ try {
202
+ const response = await fetch('/api/auth/revoke', {
203
+ method: 'POST',
204
+ headers: {
205
+ 'Content-Type': 'application/json'
206
+ },
207
+ body: JSON.stringify({ credential_id: credentialId })
208
+ });
209
+
210
+ if (!response.ok) {
211
+ throw new Error('Failed to revoke token');
212
+ }
213
+
214
+ updateTokenDisplay(null);
215
+ showNotification('Token revoked successfully');
216
+ } catch (error) {
217
+ showErrorNotification('Failed to revoke token: ' + error.message);
218
+ }
219
+ }
220
+ ```
221
+
222
+ ## Security Features
223
+
224
+ ### Secure Credential Storage
225
+
226
+ The Web UI securely stores authentication credentials in the browser:
227
+
228
+ ```javascript
229
+ // JavaScript for secure credential storage
230
+ class SecureStorage {
231
+ constructor() {
232
+ // Initialize secure storage
233
+ }
234
+
235
+ // Store sensitive data securely
236
+ async store(key, value) {
237
+ // Use browser's Web Crypto API to encrypt data
238
+ const encryptedData = await this.encrypt(JSON.stringify(value));
239
+ localStorage.setItem(key, encryptedData);
240
+ }
241
+
242
+ // Retrieve and decrypt sensitive data
243
+ async retrieve(key) {
244
+ const encryptedData = localStorage.getItem(key);
245
+ if (!encryptedData) return null;
246
+
247
+ try {
248
+ const decryptedData = await this.decrypt(encryptedData);
249
+ return JSON.parse(decryptedData);
250
+ } catch (error) {
251
+ console.error('Failed to decrypt data:', error);
252
+ return null;
253
+ }
254
+ }
255
+
256
+ // Encryption/decryption methods
257
+ // ...
258
+ }
259
+ ```
260
+
261
+ ### CSRF Protection
262
+
263
+ The Web UI implements CSRF protection for authentication flows:
264
+
265
+ ```javascript
266
+ // JavaScript for CSRF protection
267
+ function generateSecureRandomString(length = 32) {
268
+ const array = new Uint8Array(length);
269
+ window.crypto.getRandomValues(array);
270
+ return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
271
+ }
272
+ ```
273
+
274
+ ## Developer Tools
275
+
276
+ ### Authentication Debugging Panel
277
+
278
+ The Web UI includes an authentication debugging panel for troubleshooting:
279
+
280
+ ```html
281
+ <!-- Authentication debugging panel -->
282
+ <div class="auth-debugging-panel">
283
+ <h2>Authentication Debugging</h2>
284
+ <div class="debug-section">
285
+ <h3>Current Authentication State</h3>
286
+ <pre id="auth-state-debug"></pre>
287
+ </div>
288
+ <div class="debug-section">
289
+ <h3>Authentication Logs</h3>
290
+ <pre id="auth-logs-debug"></pre>
291
+ </div>
292
+ <div class="debug-actions">
293
+ <button id="clear-auth-logs">Clear Logs</button>
294
+ <button id="copy-auth-logs">Copy Logs</button>
295
+ <button id="clear-auth-tokens">Clear All Tokens</button>
296
+ </div>
297
+ </div>
298
+ ```
299
+
300
+ ### Authentication Flow Visualization
301
+
302
+ The Web UI provides a visualization of the authentication flow:
303
+
304
+ ```html
305
+ <!-- Authentication flow visualization -->
306
+ <div class="auth-flow-visualization">
307
+ <div class="flow-step" data-step="1">
308
+ <div class="step-number">1</div>
309
+ <div class="step-description">Client requests protected resource</div>
310
+ </div>
311
+ <div class="flow-arrow">→</div>
312
+ <div class="flow-step" data-step="2">
313
+ <div class="step-number">2</div>
314
+ <div class="step-description">Legate yields for authentication</div>
315
+ </div>
316
+ <div class="flow-arrow">→</div>
317
+ <div class="flow-step active" data-step="3">
318
+ <div class="step-number">3</div>
319
+ <div class="step-description">User authenticates with provider</div>
320
+ </div>
321
+ <div class="flow-arrow">→</div>
322
+ <div class="flow-step" data-step="4">
323
+ <div class="step-number">4</div>
324
+ <div class="step-description">Legate exchanges code for tokens</div>
325
+ </div>
326
+ <div class="flow-arrow">→</div>
327
+ <div class="flow-step" data-step="5">
328
+ <div class="step-number">5</div>
329
+ <div class="step-description">Legate resumes with valid tokens</div>
330
+ </div>
331
+ </div>
332
+ ```
333
+
334
+ ## Integration with Legate Core
335
+
336
+ ### A Web UI Authentication Coordinator (illustrative)
337
+
338
+ Legate does not ship a `WebUIAuthenticationCoordinator` class. The pattern below
339
+ is an **illustrative coordinator you implement yourself** to bridge your web app
340
+ and the core `Legate::Auth::Config` flow. It uses the real `Config` API:
341
+ `config.auth_request_id`, `config.build_authorization_uri(redirect_uri, state)`,
342
+ `config.scheme.scheme_type`, and setting `config.response_uri` on the callback.
343
+
344
+ ```ruby
345
+ # Your own coordinator class (not provided by Legate)
346
+ class WebUIAuthenticationCoordinator
347
+ def initialize(app)
348
+ @app = app
349
+ end
350
+
351
+ def handle_auth_request(auth_config)
352
+ # Build the authorization URI (this generates and returns the state)
353
+ state = SecureRandom.hex(16)
354
+ auth_uri = auth_config.build_authorization_uri(@app.url('/auth/callback'), state)
355
+ @app.session[:oauth2_state] = auth_config.state
356
+
357
+ {
358
+ auth_request_id: auth_config.auth_request_id,
359
+ auth_type: auth_config.scheme.scheme_type,
360
+ authorization_url: auth_uri,
361
+ redirect_uri: @app.url('/auth/callback'),
362
+ scopes: auth_config.scheme.scopes,
363
+ state: auth_config.state
364
+ }
365
+ end
366
+
367
+ def handle_auth_response(auth_config, params)
368
+ # Set the response URI on the original request config, then exchange
369
+ auth_config.response_uri = params[:auth_response_uri]
370
+ auth_config
371
+ end
372
+ end
373
+ ```
374
+
375
+ ## Complete Example: OAuth2 Authentication in Web UI
376
+
377
+ Here's a complete example of implementing OAuth2 authentication in the Legate Web UI:
378
+
379
+ ```ruby
380
+ # Server-side route for handling authentication requests
381
+ post '/api/auth/request' do
382
+ content_type :json
383
+
384
+ # Get the authentication configuration from the request
385
+ auth_config = session[:auth_config]
386
+ halt 400, { error: 'No authentication request pending' }.to_json unless auth_config
387
+
388
+ # Prepare client-side configuration using your own coordinator
389
+ coordinator = WebUIAuthenticationCoordinator.new(self)
390
+ client_config = coordinator.handle_auth_request(auth_config)
391
+
392
+ client_config.to_json
393
+ end
394
+
395
+ # Server-side route for handling authentication responses
396
+ post '/api/auth/response' do
397
+ content_type :json
398
+
399
+ # Get parameters from the request
400
+ params = JSON.parse(request.body.read, symbolize_names: true)
401
+
402
+ # Validate the parameters
403
+ halt 400, { error: 'Missing auth_request_id' }.to_json unless params[:auth_request_id]
404
+ halt 400, { error: 'Missing auth_response_uri' }.to_json unless params[:auth_response_uri]
405
+
406
+ # Handle the authentication response using your own coordinator
407
+ coordinator = WebUIAuthenticationCoordinator.new(self)
408
+ auth_config = session[:auth_config]
409
+ auth_response = coordinator.handle_auth_response(auth_config, params)
410
+
411
+ # Store the response in the session for the next step in your flow
412
+ session[:auth_response] = auth_response
413
+
414
+ { success: true }.to_json
415
+ end
416
+ ```
417
+
418
+ With corresponding client-side JavaScript:
419
+
420
+ ```javascript
421
+ // Function to handle authentication requests from the server
422
+ async function handleAuthRequest() {
423
+ try {
424
+ const response = await fetch('/api/auth/request', {
425
+ method: 'POST',
426
+ headers: {
427
+ 'Content-Type': 'application/json'
428
+ }
429
+ });
430
+
431
+ if (!response.ok) {
432
+ throw new Error('Failed to get authentication configuration');
433
+ }
434
+
435
+ const authConfig = await response.json();
436
+
437
+ // Open the authorization popup
438
+ initiateOAuth2Flow(authConfig);
439
+ } catch (error) {
440
+ showErrorNotification('Authentication error: ' + error.message);
441
+ }
442
+ }
443
+
444
+ // Function to handle authentication callbacks
445
+ async function handleAuthCallback(code, state) {
446
+ // Get the stored auth config
447
+ const authConfig = JSON.parse(sessionStorage.getItem('auth_config'));
448
+ if (!authConfig) {
449
+ showErrorNotification('No authentication in progress');
450
+ return;
451
+ }
452
+
453
+ // Verify state parameter
454
+ if (state !== authConfig.state) {
455
+ showErrorNotification('Invalid state parameter');
456
+ return;
457
+ }
458
+
459
+ // Send the authentication response to the server
460
+ try {
461
+ const response = await fetch('/api/auth/response', {
462
+ method: 'POST',
463
+ headers: {
464
+ 'Content-Type': 'application/json'
465
+ },
466
+ body: JSON.stringify({
467
+ auth_request_id: authConfig.auth_request_id,
468
+ auth_response_uri: `${authConfig.redirect_uri}?code=${code}&state=${state}`,
469
+ redirect_uri: authConfig.redirect_uri
470
+ })
471
+ });
472
+
473
+ if (!response.ok) {
474
+ throw new Error('Failed to send authentication response');
475
+ }
476
+
477
+ showNotification('Authentication successful');
478
+
479
+ // Clear the stored auth config
480
+ sessionStorage.removeItem('auth_config');
481
+
482
+ // Reload the tools to reflect the authenticated state
483
+ loadTools();
484
+ } catch (error) {
485
+ showErrorNotification('Authentication error: ' + error.message);
486
+ }
487
+ }
488
+
489
+ // Event listener for authentication callbacks from popup window
490
+ window.addEventListener('message', function(event) {
491
+ if (event.origin !== window.location.origin) return;
492
+
493
+ if (event.data.type === 'auth_callback' && event.data.code) {
494
+ handleAuthCallback(event.data.code, event.data.state);
495
+ }
496
+ });
497
+ ```
498
+
499
+ ## Related Topics
500
+
501
+ - [OAuth2 Authentication Guide](./oauth2)
502
+ - [OpenID Connect Guide](./oidc)
503
+ - [Token Lifecycle Management](./token_lifecycle)
504
+ - [Legate Web UI Documentation](../../web_ui/legate_web_ui)
@@ -0,0 +1,58 @@
1
+ # Authentication in Legate Ruby
2
+
3
+ ## Overview
4
+
5
+ The Legate Ruby library provides a comprehensive framework for handling various authentication schemes required by external APIs. It supports common authentication methods including API Keys, OAuth2, OpenID Connect (OIDC), and Service Accounts, with a unified interface for both interactive and non-interactive flows.
6
+
7
+ ## Key Features
8
+
9
+ - **Multiple Authentication Schemes**: Support for API Keys, HTTP Bearer tokens, OAuth2, OpenID Connect, and Service Account authentication
10
+ - **Interactive Flows**: Fiber-based control flow for OAuth2 and OIDC authentication requiring user interaction
11
+ - **Non-Interactive Flows**: Streamlined handling of API Keys, Bearer tokens, and Service Accounts
12
+ - **Scoped Storage**: Tokens cached in scoped session state, with opt-in at-rest encryption via `Legate::Auth::Encryption`
13
+ - **Token Lifecycle**: Automatic management of token expiration, refresh, and invalidation
14
+ - **Middleware Integration**: Seamless integration with HTTP clients (Excon) for attaching auth to tool requests
15
+ - **Middleware Support**: Excon middleware for automatic authentication header injection
16
+
17
+ ## Core Components
18
+
19
+ - **`Legate::Auth::Scheme`**: Abstract base class defining how APIs expect credentials
20
+ - **`Legate::Auth::Credential`**: Container for initial authentication information
21
+ - **`Legate::Auth::Config`**: Configuration for the authentication flow
22
+ - **`Legate::Auth::ExchangedCredential`**: Container for exchanged tokens and state
23
+ - **`Legate::Auth::TokenManager`**: Handles token lifecycle management
24
+ - **`Legate::Auth::Encryption`**: Optional, opt-in module for encrypting sensitive credential data at rest
25
+
26
+ ## Authentication Flows
27
+
28
+ 1. **Interactive Flow** (OAuth2/OIDC)
29
+ - Tool requires authentication → Legate detects missing credentials
30
+ - Legate yields control to client application with auth URL
31
+ - User completes authentication in browser
32
+ - Client application resumes Legate execution with auth code
33
+ - Legate exchanges code for tokens and retries the original request
34
+
35
+ 2. **Non-Interactive Flow** (API Key/Bearer Token)
36
+ - Tool is configured with credentials upfront
37
+ - Legate automatically includes credentials in API requests
38
+ - No user interaction required
39
+
40
+ 3. **Service Account Flow**
41
+ - Tool is configured with service account credentials
42
+ - Legate automatically exchanges for access tokens
43
+ - Legate handles token refresh when needed
44
+
45
+ ## Documentation Sections
46
+
47
+ - [Guides](./guides/index): Detailed guides for implementing authentication
48
+ - [API Reference](./api_reference/index): Documentation of all authentication classes and methods
49
+ - [Troubleshooting](./troubleshooting/index): Solutions for common authentication issues
50
+
51
+ ## Getting Started
52
+
53
+ For most cases, you'll want to start with the [Authentication Overview Guide](./guides/overview) to understand the basic concepts, then follow the specific guide for your authentication needs:
54
+
55
+ - [API Key Authentication](./guides/api_key)
56
+ - [OAuth2 Authentication](./guides/oauth2)
57
+ - [OpenID Connect](./guides/oidc)
58
+ - [Service Account Authentication](./guides/service_account)