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,241 @@
1
+ # OpenID Connect Authentication
2
+
3
+ OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 that allows clients to verify the identity of end-users. The Legate Ruby library provides comprehensive support for OpenID Connect authentication.
4
+
5
+ ## Overview
6
+
7
+ OpenID Connect extends OAuth 2.0 with identity verification functionality, allowing applications to:
8
+
9
+ - Authenticate users with an identity provider
10
+ - Obtain basic profile information about the user
11
+ - Receive verified identity information via a JWT (JSON Web Token) called an ID token
12
+ - Access additional user information via standardized endpoints
13
+
14
+ ## Configuration
15
+
16
+ ### Creating an OpenID Connect Scheme
17
+
18
+ There are two main ways to configure an OpenID Connect scheme:
19
+
20
+ #### Using Discovery
21
+
22
+ The simplest approach is to use OpenID Connect Discovery, which automatically fetches configuration:
23
+
24
+ ```ruby
25
+ # Configure using the provider's discovery URL
26
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
27
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration'
28
+ )
29
+
30
+ # Alternatively, specify the provider URI
31
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
32
+ provider_uri: 'https://accounts.google.com'
33
+ )
34
+ ```
35
+
36
+ #### Manual Configuration
37
+
38
+ You can also manually specify all the necessary endpoints:
39
+
40
+ ```ruby
41
+ # Configure by explicitly providing all endpoints
42
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
43
+ authorization_url: 'https://accounts.google.com/o/oauth2/auth',
44
+ token_url: 'https://oauth2.googleapis.com/token',
45
+ userinfo_url: 'https://openidconnect.googleapis.com/v1/userinfo',
46
+ jwks_url: 'https://www.googleapis.com/oauth2/v3/certs',
47
+ scopes: ['openid', 'profile', 'email']
48
+ )
49
+ ```
50
+
51
+ ### Creating an OpenID Connect Credential
52
+
53
+ ```ruby
54
+ # Basic OpenID Connect credential (use :oidc — :openid_connect is not a
55
+ # valid credential auth_type and would raise CredentialError)
56
+ credential = Legate::Auth::Credential.new(
57
+ auth_type: :oidc,
58
+ client_id: ENV['CLIENT_ID'],
59
+ client_secret: ENV['CLIENT_SECRET']
60
+ )
61
+
62
+ # With additional options
63
+ credential = Legate::Auth::Credential.new(
64
+ auth_type: :oidc,
65
+ client_id: ENV['CLIENT_ID'],
66
+ client_secret: ENV['CLIENT_SECRET'],
67
+ additional_params: {
68
+ 'prompt' => 'login' # Force user to re-authenticate
69
+ }
70
+ )
71
+ ```
72
+
73
+ ## Authentication Flow
74
+
75
+ The OpenID Connect authentication flow is similar to the OAuth 2.0 authorization code flow, with added identity verification:
76
+
77
+ ```ruby
78
+ # 1. Configure the OpenID Connect scheme using discovery
79
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
80
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration',
81
+ scopes: ['openid', 'profile', 'email']
82
+ )
83
+
84
+ # 2. Configure the credential (use :oidc — :openid_connect is not a valid
85
+ # credential auth_type and would raise CredentialError)
86
+ credential = Legate::Auth::Credential.new(
87
+ auth_type: :oidc,
88
+ client_id: ENV['CLIENT_ID'],
89
+ client_secret: ENV['CLIENT_SECRET']
90
+ )
91
+
92
+ # 3. Build the authorization URI via a Config and redirect the user
93
+ config = Legate::Auth::Config.new(scheme: scheme, credential: credential)
94
+ state = SecureRandom.hex(16)
95
+ auth_url = config.build_authorization_uri('https://your-app.com/callback', state)
96
+ # redirect_to auth_url
97
+
98
+ # 4. On the callback, set the response URI on the config
99
+ config.response_uri = 'https://your-app.com/callback?code=12345&state=abcde'
100
+
101
+ # 5. Exchange the authorization code for tokens (includes an ID token)
102
+ token = scheme.exchange_token(config, credential)
103
+ puts token[:access_token]
104
+ puts token[:id_token]
105
+ ```
106
+
107
+ > This shows the direct `Config`/scheme flow. Tools can also drive OIDC
108
+ > interactively via `context.with_authentication` (see
109
+ > [`ToolContextExtension`](../api_reference/tool_context_extension)).
110
+
111
+ ## Key OpenID Connect Features
112
+
113
+ ### ID Token
114
+
115
+ The ID token is a JWT containing verified information about the user:
116
+
117
+ ```ruby
118
+ # The token exchange process returns an ID token automatically
119
+ # In an ExchangedCredential, you can access it as:
120
+ id_token = exchanged_credential[:id_token]
121
+
122
+ # To decode and verify the token
123
+ require 'jwt'
124
+ decoded_token = JWT.decode(id_token, nil, false)[0]
125
+
126
+ # To access claims
127
+ user_email = decoded_token['email']
128
+ name = decoded_token['name']
129
+ ```
130
+
131
+ ### UserInfo Endpoint
132
+
133
+ For more detailed user information, you can call the UserInfo endpoint:
134
+
135
+ ```ruby
136
+ # Get an access token
137
+ access_token = exchanged_credential[:access_token]
138
+
139
+ # Create the scheme (or use existing one)
140
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
141
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration'
142
+ )
143
+
144
+ # Fetch user information
145
+ user_info = scheme.get_userinfo(access_token)
146
+
147
+ # Access user data
148
+ email = user_info['email']
149
+ name = user_info['name']
150
+ picture = user_info['picture']
151
+ ```
152
+
153
+ ## Provider-Specific Configurations
154
+
155
+ ### Google OpenID Connect
156
+
157
+ ```ruby
158
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
159
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration',
160
+ scopes: ['openid', 'profile', 'email'],
161
+ additional_params: {
162
+ 'prompt' => 'consent',
163
+ 'access_type' => 'offline'
164
+ }
165
+ )
166
+ ```
167
+
168
+ ### Microsoft Azure OpenID Connect
169
+
170
+ ```ruby
171
+ tenant_id = 'common' # Use 'common' for multi-tenant, or a specific tenant ID
172
+
173
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
174
+ discovery_url: "https://login.microsoftonline.com/#{tenant_id}/v2.0/.well-known/openid-configuration",
175
+ scopes: ['openid', 'profile', 'email', 'offline_access']
176
+ )
177
+ ```
178
+
179
+ ### Auth0
180
+
181
+ ```ruby
182
+ domain = 'your-domain.auth0.com'
183
+
184
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
185
+ discovery_url: "https://#{domain}/.well-known/openid-configuration",
186
+ scopes: ['openid', 'profile', 'email']
187
+ )
188
+ ```
189
+
190
+ ## Security Considerations
191
+
192
+ - **Nonce Verification**: The library automatically adds a nonce parameter to prevent replay attacks
193
+ - **ID Token Validation**: Always verify the ID token signature, issuer, audience, and expiration
194
+ - **Scopes**: Request only the scopes your application needs
195
+ - **Secure Storage**: Tokens are cached in scoped session state as plaintext; for at-rest encryption, apply the opt-in `Legate::Auth::Encryption` module yourself
196
+
197
+ ## Advanced Features
198
+
199
+ ### PKCE (Proof Key for Code Exchange)
200
+
201
+ ```ruby
202
+ # PKCE is enabled by default
203
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
204
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration',
205
+ use_pkce: true # This is the default
206
+ )
207
+ ```
208
+
209
+ ### Prompt Parameter
210
+
211
+ Control the authentication experience using the prompt parameter:
212
+
213
+ ```ruby
214
+ scheme = Legate::Auth::Schemes::OpenIDConnect.new(
215
+ discovery_url: 'https://accounts.google.com/.well-known/openid-configuration',
216
+ additional_params: {
217
+ 'prompt' => 'login' # Options: none, login, consent, select_account
218
+ }
219
+ )
220
+ ```
221
+
222
+ ## Troubleshooting
223
+
224
+ If you encounter issues with OpenID Connect authentication:
225
+
226
+ - Ensure 'openid' is included in the requested scopes
227
+ - Verify that your client is properly registered with the identity provider
228
+ - Check that redirect URIs exactly match those registered with the provider
229
+ - See the [OpenID Connect Troubleshooting Guide](../troubleshooting/oidc_issues) for detailed solutions
230
+
231
+ ## Related Topics
232
+
233
+ - [OAuth2 Authentication](./oauth2) - Learn more about the underlying OAuth2 protocol
234
+ - [Service Account Authentication](./service_account) - Use service accounts for server-to-server authentication
235
+ - [Token Lifecycle Management](./token_lifecycle) - Advanced token management techniques
236
+
237
+ ## Next Steps
238
+
239
+ - [OAuth2 Authentication](./oauth2): Learn more about the underlying OAuth2 protocol
240
+ - [Service Account Authentication](./service_account): Use service accounts for server-to-server authentication
241
+ - [Token Lifecycle Management](./token_lifecycle): Advanced token management techniques
@@ -0,0 +1,155 @@
1
+ # Authentication Overview
2
+
3
+ ## Introduction
4
+
5
+ The Legate Ruby authentication system provides a comprehensive framework for handling authentication with external APIs. It supports various authentication methods including:
6
+
7
+ - API Key authentication
8
+ - HTTP Bearer token authentication
9
+ - OAuth2 authentication
10
+ - OpenID Connect (OIDC) authentication
11
+ - Service Account authentication
12
+
13
+ The system is designed to handle both interactive authentication flows (like OAuth2, which requires user consent) and non-interactive flows (like API Keys), with a unified interface.
14
+
15
+ ## Core Concepts
16
+
17
+ ### Authentication Schemes
18
+
19
+ An authentication scheme (`Legate::Auth::Scheme`) defines how an API expects credentials to be provided. Each scheme implements:
20
+
21
+ - How to apply authentication to requests
22
+ - How to exchange initial credentials for tokens (if applicable)
23
+ - How to refresh tokens (if applicable)
24
+ - How to build authorization URIs for interactive flows
25
+
26
+ The Legate Ruby library includes the following authentication schemes:
27
+
28
+ - `Legate::Auth::Schemes::ApiKey`: For API key authentication (in header, query, or cookie)
29
+ - `Legate::Auth::Schemes::HTTPBearer`: For Bearer token authentication
30
+ - `Legate::Auth::Schemes::OAuth2`: For OAuth2 authentication flows
31
+ - `Legate::Auth::Schemes::OpenIDConnect`: For OpenID Connect authentication
32
+ - `Legate::Auth::Schemes::ServiceAccount`: For service account authentication
33
+ - `Legate::Auth::Schemes::GoogleServiceAccount`: For Google Cloud service accounts
34
+
35
+ ### Credentials
36
+
37
+ A credential (`Legate::Auth::Credential`) contains the initial information needed to start authentication:
38
+
39
+ - API Keys
40
+ - OAuth2 client ID and client secret
41
+ - Bearer tokens
42
+ - Service account keys
43
+
44
+ Credentials can be provided directly or through environment variables, which is recommended for sensitive information.
45
+
46
+ ### Token Exchange
47
+
48
+ For authentication methods like OAuth2, the initial credential must be exchanged for a token:
49
+
50
+ 1. The initial credential (e.g., client ID and secret) is used to start the authentication flow
51
+ 2. The flow results in an exchanged credential (`Legate::Auth::ExchangedCredential`)
52
+ 3. The exchanged credential contains access tokens, refresh tokens, and expiry information
53
+
54
+ ### Authentication Flows
55
+
56
+ #### Non-Interactive Flow (API Key, Bearer Token)
57
+
58
+ ```ruby
59
+ # Create an API Key scheme (no constructor arguments)
60
+ scheme = Legate::Auth::Schemes::ApiKey.new
61
+
62
+ # Create a credential with the API key. The key's location ('header',
63
+ # 'query', or 'cookie') and name live on the credential, not the scheme.
64
+ credential = Legate::Auth::Credential.new(
65
+ auth_type: :api_key,
66
+ api_key: ENV['API_KEY'],
67
+ location: 'header', # default
68
+ name: 'X-API-Key' # default
69
+ )
70
+
71
+ # Attach the scheme/credential to your outbound HTTP client. The simplest
72
+ # path is the Excon connection helper, which applies the API key for you:
73
+ connection = Legate::Auth.create_connection('https://api.example.com',
74
+ scheme: scheme,
75
+ credential: credential
76
+ )
77
+ response = connection.get(path: '/protected-resource')
78
+ ```
79
+
80
+ #### Interactive Flow (OAuth2, OIDC)
81
+
82
+ ```ruby
83
+ # Create an OAuth2 scheme
84
+ scheme = Legate::Auth::Schemes::OAuth2.new(
85
+ authorization_url: 'https://auth.example.com/authorize',
86
+ token_url: 'https://auth.example.com/token',
87
+ scopes: ['profile', 'email']
88
+ )
89
+
90
+ # Create a credential with client ID and secret
91
+ credential = Legate::Auth::Credential.new(
92
+ auth_type: :oauth2,
93
+ client_id: ENV['CLIENT_ID'],
94
+ client_secret: ENV['CLIENT_SECRET']
95
+ )
96
+
97
+ # Drive the interactive flow via Config:
98
+ # 1. Build the authorization URI and redirect the user to it
99
+ config = Legate::Auth::Config.new(scheme: scheme, credential: credential)
100
+ state = SecureRandom.hex(16)
101
+ auth_uri = config.build_authorization_uri('https://your-app.com/callback', state)
102
+ # redirect_to auth_uri
103
+
104
+ # 2. When the user is redirected back, set the response URI on the config
105
+ config.response_uri = 'https://your-app.com/callback?code=12345&state=abcde'
106
+
107
+ # 3. Exchange the authorization code for tokens
108
+ token = scheme.exchange_token(config, credential)
109
+
110
+ # `token` is an ExchangedCredential you can store and apply to requests.
111
+ ```
112
+
113
+ > The fiber-based, tool-driven flow (where a tool's `with_authentication`
114
+ > block yields an auth request to the caller) is also supported; see
115
+ > [`Legate::Auth::ToolContextExtension`](../api_reference/tool_context_extension).
116
+
117
+ #### Service Account Flow
118
+
119
+ ```ruby
120
+ # Create a Service Account scheme
121
+ scheme = Legate::Auth::Schemes::GoogleServiceAccount.new(
122
+ scopes: ['https://www.googleapis.com/auth/cloud-platform']
123
+ )
124
+
125
+ # Create a credential with the service account key (raw JSON string)
126
+ credential = Legate::Auth::Credential.new(
127
+ auth_type: :google_service_account,
128
+ service_account_key: File.read('service-account.json')
129
+ )
130
+
131
+ # Exchange for an access token and apply it to outbound requests
132
+ token = scheme.exchange_token(credential)
133
+ connection = Legate::Auth.create_connection('https://api.example.com',
134
+ scheme: scheme,
135
+ credential: token
136
+ )
137
+ result = connection.get(path: '/resource')
138
+ ```
139
+
140
+ ## Security Considerations
141
+
142
+ The Legate Ruby library implements several security measures:
143
+
144
+ - Tokens are cached in scoped session state; for at-rest encryption, the opt-in `Legate::Auth::Encryption` module is available (it is not applied automatically)
145
+ - Access tokens have limited lifetimes, with automatic expiry checks
146
+ - Refresh tokens are handled by the `TokenManager`
147
+ - Environment variable resolution (the `ENV:` prefix) keeps sensitive values out of source code
148
+ - Outbound auth/token URLs are validated by `Legate::Auth::UrlGuard` to block SSRF to private/loopback addresses
149
+
150
+ ## Next Steps
151
+
152
+ - [Authentication Configuration](./configuration) - How to configure authentication for different scenarios
153
+ - [API Key Authentication](./api_key) - Detailed guide for API key authentication
154
+ - [OAuth2 Authentication](./oauth2) - Complete guide for implementing OAuth2 flows
155
+ - [Token Lifecycle Management](./token_lifecycle) - Managing token expiration and refresh
@@ -0,0 +1,301 @@
1
+ # Secure Credential Storage
2
+
3
+ ## Overview
4
+
5
+ Secure storage of authentication credentials and tokens is critical for maintaining the security of your Legate Ruby applications. This guide explains best practices for storing and handling sensitive authentication data.
6
+
7
+ ## Security Considerations
8
+
9
+ When working with authentication, you need to protect several types of sensitive information:
10
+
11
+ - **API Keys**: Direct access tokens that grant API access
12
+ - **Client Secrets**: OAuth2/OIDC secrets used to authenticate your application
13
+ - **Bearer Tokens**: Tokens that provide access to protected resources
14
+ - **Access Tokens**: Short-lived tokens obtained through authentication flows
15
+ - **Refresh Tokens**: Long-lived tokens used to obtain new access tokens
16
+ - **Service Account Keys**: JSON credentials that authenticate as a service account
17
+
18
+ ## Legate Security Architecture
19
+
20
+ The Legate Ruby library provides several measures to help protect sensitive authentication data:
21
+
22
+ 1. **Optional Encryption**: An opt-in `Legate::Auth::Encryption` module is available for encrypting data at rest
23
+ 2. **Scoped Storage**: Tokens are cached in scoped session state via the token store
24
+ 3. **Environment Variables**: Credential values can be sourced from environment variables (the `ENV:` prefix)
25
+ 4. **Minimal Exposure**: Access tokens are short-lived and refreshed automatically by the `TokenManager`
26
+
27
+ ## Encryption in Legate
28
+
29
+ > **Important:** Encryption is **opt-in** and is **not** wired into `TokenStore`. `TokenStore#store` persists plaintext token data (`token.to_h`) in scoped state. To encrypt at rest, call the `Legate::Auth::Encryption` module yourself.
30
+
31
+ The `Legate::Auth::Encryption` module uses the `rbnacl` gem (libsodium SecretBox) for authenticated encryption. `rbnacl` is an optional dependency: the module lazily requires it and raises `LoadError` if it (or libsodium) is missing.
32
+
33
+ ### Using the Encryption Module
34
+
35
+ `Encryption` is a module (not instantiable). Call its module methods directly. Keys are Base64-encoded; with no key argument it reads `LEGATE_AUTH_ENCRYPTION_KEY`.
36
+
37
+ ```ruby
38
+ require 'legate/auth/encryption'
39
+
40
+ # Generate a Base64 key once and store it securely
41
+ key = Legate::Auth::Encryption.generate_key
42
+
43
+ # Encrypt / decrypt (output is "LGTAUTH" + Base64)
44
+ ciphertext = Legate::Auth::Encryption.encrypt(JSON.dump(token.to_h), key)
45
+ plaintext = Legate::Auth::Encryption.decrypt(ciphertext, key)
46
+ ```
47
+
48
+ ### Applying Encryption to Stored Tokens
49
+
50
+ Because `TokenStore` does not encrypt, apply encryption in your own storage layer:
51
+
52
+ ```ruby
53
+ key = ENV['LEGATE_AUTH_ENCRYPTION_KEY']
54
+
55
+ # Encrypt before persisting through storage you control
56
+ ciphertext = Legate::Auth::Encryption.encrypt(JSON.dump(token.to_h), key)
57
+
58
+ # Decrypt on read, then rebuild the token
59
+ data = JSON.parse(Legate::Auth::Encryption.decrypt(ciphertext, key), symbolize_names: true)
60
+ token = Legate::Auth::ExchangedCredential.from_h(data)
61
+ ```
62
+
63
+ ## Environment Variable Handling
64
+
65
+ The Legate Ruby library supports sourcing credential values from environment variables, which is a security best practice.
66
+
67
+ ### Direct Environment Variable Usage
68
+
69
+ ```ruby
70
+ # Read environment variables at construction time
71
+ api_key_credential = Legate::Auth::Credential.new(
72
+ auth_type: :api_key,
73
+ api_key: ENV['API_KEY']
74
+ )
75
+
76
+ oauth2_credential = Legate::Auth::Credential.new(
77
+ auth_type: :oauth2,
78
+ client_id: ENV['OAUTH2_CLIENT_ID'],
79
+ client_secret: ENV['OAUTH2_CLIENT_SECRET']
80
+ )
81
+ ```
82
+
83
+ ### Environment Variable References
84
+
85
+ The only reference mechanism is the `ENV:` prefix inside a string value
86
+ (resolved lazily when the attribute is read). There are no `*_env` attributes.
87
+
88
+ ```ruby
89
+ api_key_credential = Legate::Auth::Credential.new(
90
+ auth_type: :api_key,
91
+ api_key: 'ENV:API_KEY'
92
+ )
93
+
94
+ oauth2_credential = Legate::Auth::Credential.new(
95
+ auth_type: :oauth2,
96
+ client_id: 'ENV:OAUTH2_CLIENT_ID',
97
+ client_secret: 'ENV:OAUTH2_CLIENT_SECRET'
98
+ )
99
+ ```
100
+
101
+ ## Secure Token Storage
102
+
103
+ The Legate Ruby library provides the `TokenStore` class for secure storage of authentication tokens.
104
+
105
+ ### Creating a Token Store
106
+
107
+ ```ruby
108
+ # Create a token store with the session service (positional argument)
109
+ token_store = Legate::Auth::TokenStore.new(session_service)
110
+ ```
111
+
112
+ ### Storing Tokens
113
+
114
+ `store(key, token)` accepts a string key and an `ExchangedCredential` (it
115
+ serializes `token.to_h` into scoped state; it does not encrypt):
116
+
117
+ ```ruby
118
+ token = Legate::Auth::ExchangedCredential.new(
119
+ auth_type: :oauth2,
120
+ access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
121
+ refresh_token: 'rtok_abc123...',
122
+ expires_in: 3600
123
+ )
124
+
125
+ token_store.store('client123', token)
126
+ ```
127
+
128
+ ### Retrieving Tokens
129
+
130
+ ```ruby
131
+ # Returns an ExchangedCredential, or nil if missing/expired
132
+ token = token_store.get('client123')
133
+ ```
134
+
135
+ ## Service Account Key Security
136
+
137
+ Service account keys (especially Google Service Account JSON keys) require special security consideration.
138
+
139
+ ### Store Service Account Keys Securely
140
+
141
+ ```ruby
142
+ # Option 1: Store the JSON in an environment variable (recommended).
143
+ # service_account_key takes the raw JSON string.
144
+ ENV['GOOGLE_SERVICE_ACCOUNT_JSON'] = '{"type":"service_account","project_id":"..."}'
145
+
146
+ credential = Legate::Auth::Credential.new(
147
+ auth_type: :google_service_account,
148
+ service_account_key: ENV['GOOGLE_SERVICE_ACCOUNT_JSON']
149
+ )
150
+
151
+ # Option 2: Reference the env var lazily with the ENV: prefix
152
+ credential = Legate::Auth::Credential.new(
153
+ auth_type: :google_service_account,
154
+ service_account_key: 'ENV:GOOGLE_SERVICE_ACCOUNT_JSON'
155
+ )
156
+
157
+ # Option 3: Reference a file path with service_account_key_file
158
+ credential = Legate::Auth::Credential.new(
159
+ auth_type: :google_service_account,
160
+ service_account_key_file: '/secure/path/to/service-account.json'
161
+ )
162
+ ```
163
+
164
+ ## Deployment Security Best Practices
165
+
166
+ ### Environment Variables in Production
167
+
168
+ For production environments, consider these best practices for handling environment variables:
169
+
170
+ 1. **Use a secrets manager**: Store secrets in a dedicated secrets manager like HashiCorp Vault, AWS Secrets Manager, or Google Secret Manager
171
+ 2. **Inject at runtime**: Inject secrets into your application at runtime rather than storing them in configuration files
172
+ 3. **Use minimal permissions**: For service accounts, use the principle of least privilege
173
+ 4. **Rotate credentials**: Regularly rotate credentials and tokens
174
+
175
+ ### Example with Docker Compose
176
+
177
+ ```yaml
178
+ # docker-compose.yml
179
+ version: '3'
180
+ services:
181
+ app:
182
+ build: .
183
+ environment:
184
+ - OAUTH2_CLIENT_ID=${OAUTH2_CLIENT_ID}
185
+ - OAUTH2_CLIENT_SECRET=${OAUTH2_CLIENT_SECRET}
186
+ - API_KEY=${API_KEY}
187
+ env_file:
188
+ - .env.production
189
+ ```
190
+
191
+ ### Example with Kubernetes
192
+
193
+ ```yaml
194
+ # deployment.yaml
195
+ apiVersion: v1
196
+ kind: Secret
197
+ metadata:
198
+ name: auth-credentials
199
+ type: Opaque
200
+ data:
201
+ oauth2-client-id: <base64-encoded-client-id>
202
+ oauth2-client-secret: <base64-encoded-client-secret>
203
+ api-key: <base64-encoded-api-key>
204
+ ---
205
+ apiVersion: apps/v1
206
+ kind: Deployment
207
+ metadata:
208
+ name: legate-app
209
+ spec:
210
+ template:
211
+ spec:
212
+ containers:
213
+ - name: legate-app
214
+ image: legate-app:latest
215
+ env:
216
+ - name: OAUTH2_CLIENT_ID
217
+ valueFrom:
218
+ secretKeyRef:
219
+ name: auth-credentials
220
+ key: oauth2-client-id
221
+ - name: OAUTH2_CLIENT_SECRET
222
+ valueFrom:
223
+ secretKeyRef:
224
+ name: auth-credentials
225
+ key: oauth2-client-secret
226
+ - name: API_KEY
227
+ valueFrom:
228
+ secretKeyRef:
229
+ name: auth-credentials
230
+ key: api-key
231
+ ```
232
+
233
+ ## Development Security Best Practices
234
+
235
+ ### Local Environment Variables
236
+
237
+ For development environments, consider these approaches:
238
+
239
+ 1. **Use a .env file**: Store environment variables in a .env file that is not committed to source control
240
+ 2. **Use a development-only secrets manager**: Set up a development instance of your secrets manager
241
+ 3. **Use dummy credentials for development**: Use separate credentials for development environments
242
+
243
+ ### Example .env File
244
+
245
+ ```
246
+ # .env (add to .gitignore)
247
+ OAUTH2_CLIENT_ID=dev-client-id
248
+ OAUTH2_CLIENT_SECRET=dev-client-secret
249
+ API_KEY=dev-api-key
250
+ GOOGLE_SERVICE_ACCOUNT_JSON={"type":"service_account","project_id":"..."}
251
+ ```
252
+
253
+ ### Loading Environment Variables
254
+
255
+ ```ruby
256
+ # Load environment variables
257
+ require 'dotenv'
258
+ Dotenv.load
259
+
260
+ # Use in credential creation
261
+ oauth2_credential = Legate::Auth::Credential.new(
262
+ auth_type: :oauth2,
263
+ client_id: ENV['OAUTH2_CLIENT_ID'],
264
+ client_secret: ENV['OAUTH2_CLIENT_SECRET']
265
+ )
266
+ ```
267
+
268
+ ## Session Service Security
269
+
270
+ The Legate session service stores authentication tokens in memory as plaintext (unless you apply opt-in encryption yourself). Ensure proper security:
271
+
272
+ 1. **Use HTTPS**: Ensure all communication is over HTTPS
273
+ 2. **Session isolation**: Use proper session management practices
274
+ 3. **Process lifecycle**: Be aware that in-memory sessions are lost on process restart
275
+
276
+ ```ruby
277
+ # Create the in-memory session service
278
+ session_service = Legate::SessionService::InMemory.new
279
+ ```
280
+
281
+ ## Security Checklist
282
+
283
+ Use this checklist to ensure you're following security best practices:
284
+
285
+ - [ ] Store credentials in environment variables, not in code
286
+ - [ ] Use HTTPS for all API and authentication endpoints
287
+ - [ ] Configure proper token expiration and refresh thresholds
288
+ - [ ] Implement proper error handling for authentication failures
289
+ - [ ] Ensure session service is properly configured
290
+ - [ ] Rotate credentials regularly
291
+ - [ ] Use the principle of least privilege for service accounts
292
+ - [ ] Implement proper logging for authentication events (but don't log sensitive data)
293
+ - [ ] Keep the Legate Ruby library updated to get security fixes
294
+
295
+ ## Related Topics
296
+ - [Authentication Configuration](./configuration)
297
+ - [Token Lifecycle Management](./token_lifecycle)
298
+ - [OAuth2 Authentication](./oauth2)
299
+ - [Service Account Authentication](./service_account)
300
+ - [`Legate::Auth::TokenStore` API Reference](../api_reference/token_store)
301
+ - [`Legate::Auth::Encryption` API Reference](../api_reference/encryption)