@macaw-ai/client 0.0.0-stage → 0.9.11

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 (142) hide show
  1. package/LICENSE.md +339 -0
  2. package/bin/install.js +422 -0
  3. package/package.json +37 -4
  4. package/payload/README.md +56 -0
  5. package/payload/secureAI/LICENSE +190 -0
  6. package/payload/secureAI/NOTICE +5 -0
  7. package/payload/secureAI/demos/policy-controls/1_uncontrolled.py +139 -0
  8. package/payload/secureAI/demos/policy-controls/2_with_macaw.py +139 -0
  9. package/payload/secureAI/demos/policy-controls/3_with_user_policies.py +162 -0
  10. package/payload/secureAI/demos/policy-controls/credentials.txt +12 -0
  11. package/payload/secureAI/demos/policy-controls/malicious_report.txt +21 -0
  12. package/payload/secureAI/demos/policy-controls/sales_report.txt +20 -0
  13. package/payload/secureAI/demos/tutorial-1-rbac/README.md +143 -0
  14. package/payload/secureAI/demos/tutorial-1-rbac/app.py +147 -0
  15. package/payload/secureAI/demos/tutorial-1-rbac/authprompts_demo.py +306 -0
  16. package/payload/secureAI/demos/tutorial-1-rbac/config/claims-config.yaml +152 -0
  17. package/payload/secureAI/demos/tutorial-1-rbac/demo_secureopenai_with_policies.py +150 -0
  18. package/payload/secureAI/demos/tutorial-1-rbac/policies/bu_Analytics.json +8 -0
  19. package/payload/secureAI/demos/tutorial-1-rbac/policies/company_FinTech_Corp.json +70 -0
  20. package/payload/secureAI/demos/tutorial-1-rbac/policies/llm-base.json +69 -0
  21. package/payload/secureAI/demos/tutorial-1-rbac/policies/team_Reporting.json +8 -0
  22. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_alice.json +32 -0
  23. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_bob.json +28 -0
  24. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_carol.json +34 -0
  25. package/payload/secureAI/demos/tutorial-1-rbac/requirements.txt +6 -0
  26. package/payload/secureAI/demos/tutorial-1-rbac/setup/auth0_complete_setup.sh +392 -0
  27. package/payload/secureAI/demos/tutorial-1-rbac/setup/keycloak_complete_setup.sh +320 -0
  28. package/payload/secureAI/demos/tutorial-2-intent/Policies/alation-remote-proxy.json +155 -0
  29. package/payload/secureAI/demos/tutorial-2-intent/Policies/bu.json +22 -0
  30. package/payload/secureAI/demos/tutorial-2-intent/Policies/company.json +17 -0
  31. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_alice.json +48 -0
  32. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_bob.json +83 -0
  33. package/payload/secureAI/demos/tutorial-2-intent/README.md +213 -0
  34. package/payload/secureAI/demos/tutorial-2-intent/script.py +188 -0
  35. package/payload/secureAI/demos/tutorial-2-intent/setup/alation_verifier.py +177 -0
  36. package/payload/secureAI/demos/tutorial-2-intent/setup/get_alation_user_token.py +180 -0
  37. package/payload/secureAI/examples/README.md +244 -0
  38. package/payload/secureAI/examples/anthropic/anthropic_1a_dropin_simple.py +103 -0
  39. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind.py +190 -0
  40. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind_streaming.py +190 -0
  41. package/payload/secureAI/examples/anthropic/anthropic_1c_a2a_invoke.py +156 -0
  42. package/payload/secureAI/examples/attestations/1a_trade_alice.py +215 -0
  43. package/payload/secureAI/examples/attestations/1a_trade_bob.py +164 -0
  44. package/payload/secureAI/examples/attestations/1b_grant_admin.py +170 -0
  45. package/payload/secureAI/examples/attestations/1b_grant_researcher.py +231 -0
  46. package/payload/secureAI/examples/attestations/README.md +128 -0
  47. package/payload/secureAI/examples/langchain/langchain_1a_dropin_simple.py +199 -0
  48. package/payload/secureAI/examples/langchain/langchain_1b_multiuser.py +262 -0
  49. package/payload/secureAI/examples/langchain/langchain_1c_orchestration.py +332 -0
  50. package/payload/secureAI/examples/langchain/langchain_1d_llm_openai.py +130 -0
  51. package/payload/secureAI/examples/langchain/langchain_1e_llm_anthropic.py +130 -0
  52. package/payload/secureAI/examples/langchain/langchain_1f_memory.py +214 -0
  53. package/payload/secureAI/examples/litellm/litellm_1a_dropin_simple.py +131 -0
  54. package/payload/secureAI/examples/mcp/1a_simple_invocation.py +115 -0
  55. package/payload/secureAI/examples/mcp/1b_discovery_and_resources.py +142 -0
  56. package/payload/secureAI/examples/mcp/1c_logging_client.py +100 -0
  57. package/payload/secureAI/examples/mcp/1d_progress_client.py +100 -0
  58. package/payload/secureAI/examples/mcp/1e_sampling_client.py +150 -0
  59. package/payload/secureAI/examples/mcp/1e_sampling_server.py +90 -0
  60. package/payload/secureAI/examples/mcp/1f_elicitation_client.py +127 -0
  61. package/payload/secureAI/examples/mcp/1f_elicitation_server.py +73 -0
  62. package/payload/secureAI/examples/mcp/1g_roots_client.py +122 -0
  63. package/payload/secureAI/examples/mcp/1g_roots_server.py +85 -0
  64. package/payload/secureAI/examples/mcp/2a_proxy_snowflake.py +212 -0
  65. package/payload/secureAI/examples/mcp/2b_proxy_databricks.py +299 -0
  66. package/payload/secureAI/examples/mcp/2c_proxy_stdio_fetch.py +91 -0
  67. package/payload/secureAI/examples/mcp/2d_proxy_stdio_salesforce.py +119 -0
  68. package/payload/secureAI/examples/mcp/2e_proxy_multiuser.py +136 -0
  69. package/payload/secureAI/examples/mcp/2f_proxy_stdio_databricks.py +144 -0
  70. package/payload/secureAI/examples/mcp/3a_native_mcp_client.py +104 -0
  71. package/payload/secureAI/examples/mcp/3b_native_mcp_proxy.py +114 -0
  72. package/payload/secureAI/examples/mcp/3c_native_mcp_sampling.py +180 -0
  73. package/payload/secureAI/examples/mcp/3d_native_mcp_2026.py +135 -0
  74. package/payload/secureAI/examples/mcp/securemcp_calculator.py +248 -0
  75. package/payload/secureAI/examples/mcp/securemcp_server.py +75 -0
  76. package/payload/secureAI/examples/openai/openai_1a_dropin_simple.py +102 -0
  77. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind.py +193 -0
  78. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind_streaming.py +199 -0
  79. package/payload/secureAI/examples/openai/openai_1c_a2a_invoke.py +156 -0
  80. package/payload/secureAI/examples/openai/openai_1d_invocation_patterns.py +337 -0
  81. package/payload/secureAI/examples/phishing-resistance/1a_login_alice.py +180 -0
  82. package/payload/secureAI/examples/phishing-resistance/1b_trade_alice.py +241 -0
  83. package/payload/secureAI/examples/phishing-resistance/1b_trade_bob.py +164 -0
  84. package/payload/secureAI/examples/phishing-resistance/README.md +124 -0
  85. package/payload/secureAI/examples/phishing-resistance/get_token.py +114 -0
  86. package/payload/secureAI/examples/pydantic_ai/README.md +88 -0
  87. package/payload/secureAI/examples/pydantic_ai/policies/app_pydantic-agent.json +10 -0
  88. package/payload/secureAI/examples/pydantic_ai/pydanticai_1a_dropin_simple.py +90 -0
  89. package/payload/secureAI/examples/pydantic_ai/pydanticai_1b_model_routing.py +85 -0
  90. package/payload/secureAI/examples/pydantic_ai/pydanticai_1c_native_tools.py +83 -0
  91. package/payload/secureAI/examples/pydantic_ai/pydanticai_1d_multiuser_bind.py +104 -0
  92. package/payload/secureAI/examples/pydantic_ai/pydanticai_1e_mcp_compose.py +92 -0
  93. package/payload/secureAI/macaw_adapters/__init__.py +55 -0
  94. package/payload/secureAI/macaw_adapters/anthropic/REFERENCE.md +374 -0
  95. package/payload/secureAI/macaw_adapters/anthropic/__init__.py +22 -0
  96. package/payload/secureAI/macaw_adapters/anthropic/secure_anthropic.py +792 -0
  97. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/__init__.py +25 -0
  98. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/secure_anthropic.py +840 -0
  99. package/payload/secureAI/macaw_adapters/langchain/REFERENCE.md +234 -0
  100. package/payload/secureAI/macaw_adapters/langchain/__init__.py +100 -0
  101. package/payload/secureAI/macaw_adapters/langchain/_utils.py +83 -0
  102. package/payload/secureAI/macaw_adapters/langchain/agents.py +296 -0
  103. package/payload/secureAI/macaw_adapters/langchain/anthropic.py +456 -0
  104. package/payload/secureAI/macaw_adapters/langchain/callbacks.py +306 -0
  105. package/payload/secureAI/macaw_adapters/langchain/memory.py +352 -0
  106. package/payload/secureAI/macaw_adapters/langchain/openai.py +410 -0
  107. package/payload/secureAI/macaw_adapters/langchain/tools.py +174 -0
  108. package/payload/secureAI/macaw_adapters/litellm/README.md +216 -0
  109. package/payload/secureAI/macaw_adapters/litellm/__init__.py +143 -0
  110. package/payload/secureAI/macaw_adapters/litellm/secure_litellm.py +686 -0
  111. package/payload/secureAI/macaw_adapters/mcp/REFERENCE.md +460 -0
  112. package/payload/secureAI/macaw_adapters/mcp/__init__.py +65 -0
  113. package/payload/secureAI/macaw_adapters/mcp/_endpoint.py +193 -0
  114. package/payload/secureAI/macaw_adapters/mcp/_endpoint2.py +225 -0
  115. package/payload/secureAI/macaw_adapters/mcp/_serve.py +25 -0
  116. package/payload/secureAI/macaw_adapters/mcp/client.py +721 -0
  117. package/payload/secureAI/macaw_adapters/mcp/decorators.py +228 -0
  118. package/payload/secureAI/macaw_adapters/mcp/fastmcp_compat.py +353 -0
  119. package/payload/secureAI/macaw_adapters/mcp/mcp.py +785 -0
  120. package/payload/secureAI/macaw_adapters/mcp/proxy.py +626 -0
  121. package/payload/secureAI/macaw_adapters/mcp/server.py +317 -0
  122. package/payload/secureAI/macaw_adapters/mcp/subscriptions.py +450 -0
  123. package/payload/secureAI/macaw_adapters/openai/REFERENCE.md +368 -0
  124. package/payload/secureAI/macaw_adapters/openai/__init__.py +22 -0
  125. package/payload/secureAI/macaw_adapters/openai/secure_openai.py +833 -0
  126. package/payload/secureAI/macaw_adapters/openai_ext_tools/REFERENCE.md +368 -0
  127. package/payload/secureAI/macaw_adapters/openai_ext_tools/__init__.py +25 -0
  128. package/payload/secureAI/macaw_adapters/openai_ext_tools/secure_openai.py +876 -0
  129. package/payload/secureAI/macaw_adapters/pydantic_ai/__init__.py +36 -0
  130. package/payload/secureAI/macaw_adapters/pydantic_ai/_core.py +257 -0
  131. package/payload/secureAI/macaw_adapters/pydantic_ai/agent.py +218 -0
  132. package/payload/secureAI/macaw_adapters/pydantic_ai/model.py +99 -0
  133. package/payload/secureAI/macaw_adapters/pydantic_ai/toolset.py +86 -0
  134. package/payload/secureAI/test_harness_quick.py +296 -0
  135. package/wheels/macaw_adapters-0.9.10.1-py3-none-any.whl +0 -0
  136. package/wheels/macaw_client-0.9.10.1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  137. package/wheels/macaw_client-0.9.10.1-cp312-cp312-manylinux_2_17_x86_64.whl +0 -0
  138. package/wheels/macaw_client-0.9.10.1-cp314-cp314-macosx_11_0_arm64.whl +0 -0
  139. package/wheels/macaw_client-0.9.10.1-cp314-cp314-manylinux_2_17_x86_64.whl +0 -0
  140. package/wheels/macaw_client-0.9.10.1-cp314-cp314-win_amd64.whl +0 -0
  141. package/wheels/macaw_client-0.9.10.1-cp39-cp39-macosx_11_0_arm64.whl +0 -0
  142. package/README.md +0 -3
@@ -0,0 +1,392 @@
1
+ #!/bin/bash
2
+ #
3
+ # Complete Auth0 Setup - Creates application, API, users, and custom claims action
4
+ #
5
+ # PREREQUISITES:
6
+ # 1. Create an Auth0 account at https://auth0.com
7
+ # 2. Create a Machine-to-Machine application for this script:
8
+ # - Go to Applications -> Create Application -> Machine to Machine
9
+ # - Name it: "MACAW Setup Script"
10
+ # - Select the "Auth0 Management API"
11
+ # - Grant these permissions:
12
+ # * create:users, read:users, update:users, delete:users
13
+ # * create:clients, read:clients, update:clients
14
+ # * create:resource_servers, read:resource_servers
15
+ # * create:actions, read:actions, update:actions
16
+ # * read:client_grants, create:client_grants, update:client_grants
17
+ # 3. Set the environment variables below with your M2M app credentials
18
+ #
19
+
20
+ set -e
21
+
22
+ # ============================================================
23
+ # CONFIGURATION - Set these before running!
24
+ # ============================================================
25
+ AUTH0_DOMAIN="${AUTH0_DOMAIN:-your-tenant.auth0.com}"
26
+ AUTH0_M2M_CLIENT_ID="${AUTH0_M2M_CLIENT_ID:-}"
27
+ AUTH0_M2M_CLIENT_SECRET="${AUTH0_M2M_CLIENT_SECRET:-}"
28
+
29
+ # Application settings (these will be created)
30
+ APP_NAME="financial-analyzer"
31
+ APP_CLIENT_SECRET="macaw-secret-$(openssl rand -hex 8)"
32
+ API_IDENTIFIER="https://api.macaw.local"
33
+ API_NAME="MACAW API"
34
+
35
+ # Colors
36
+ RED='\033[0;31m'
37
+ GREEN='\033[0;32m'
38
+ YELLOW='\033[1;33m'
39
+ BLUE='\033[0;34m'
40
+ NC='\033[0m'
41
+
42
+ echo "=========================================="
43
+ echo "Complete Auth0 Configuration for MACAW"
44
+ echo "=========================================="
45
+
46
+ # ============================================================
47
+ # Validation
48
+ # ============================================================
49
+ if [ -z "$AUTH0_DOMAIN" ] || [ "$AUTH0_DOMAIN" = "your-tenant.auth0.com" ]; then
50
+ echo -e "${RED}Error: AUTH0_DOMAIN not set${NC}"
51
+ echo "Usage: AUTH0_DOMAIN=your-tenant.auth0.com AUTH0_M2M_CLIENT_ID=xxx AUTH0_M2M_CLIENT_SECRET=yyy ./auth0_complete_setup.sh"
52
+ exit 1
53
+ fi
54
+
55
+ if [ -z "$AUTH0_M2M_CLIENT_ID" ] || [ -z "$AUTH0_M2M_CLIENT_SECRET" ]; then
56
+ echo -e "${RED}Error: AUTH0_M2M_CLIENT_ID and AUTH0_M2M_CLIENT_SECRET must be set${NC}"
57
+ echo ""
58
+ echo "To get these credentials:"
59
+ echo "1. Go to Auth0 Dashboard -> Applications -> Create Application"
60
+ echo "2. Choose 'Machine to Machine Applications'"
61
+ echo "3. Select 'Auth0 Management API'"
62
+ echo "4. Grant permissions: create:users, read:users, create:clients, etc."
63
+ echo "5. Copy the Client ID and Client Secret"
64
+ exit 1
65
+ fi
66
+
67
+ # Check dependencies
68
+ if ! command -v jq &> /dev/null; then
69
+ echo -e "${RED}jq is required but not installed.${NC}"
70
+ echo "Install with: brew install jq (macOS) or apt install jq (Linux)"
71
+ exit 1
72
+ fi
73
+
74
+ # ============================================================
75
+ # Step 1: Get Management API Token
76
+ # ============================================================
77
+ echo -e "${YELLOW}Step 1: Obtaining Management API token...${NC}"
78
+
79
+ MGMT_TOKEN_RESPONSE=$(curl -s -X POST "https://${AUTH0_DOMAIN}/oauth/token" \
80
+ -H "Content-Type: application/json" \
81
+ -d '{
82
+ "client_id": "'"${AUTH0_M2M_CLIENT_ID}"'",
83
+ "client_secret": "'"${AUTH0_M2M_CLIENT_SECRET}"'",
84
+ "audience": "https://'"${AUTH0_DOMAIN}"'/api/v2/",
85
+ "grant_type": "client_credentials"
86
+ }')
87
+
88
+ MGMT_TOKEN=$(echo "$MGMT_TOKEN_RESPONSE" | jq -r '.access_token')
89
+
90
+ if [ -z "$MGMT_TOKEN" ] || [ "$MGMT_TOKEN" = "null" ]; then
91
+ echo -e "${RED}Failed to get Management API token${NC}"
92
+ echo "Make sure your M2M application has the correct permissions"
93
+ exit 1
94
+ fi
95
+
96
+ echo -e "${GREEN}OK Management API token obtained${NC}"
97
+
98
+ # ============================================================
99
+ # Step 2: Create API (Resource Server)
100
+ # ============================================================
101
+ echo -e "${YELLOW}Step 2: Creating API (Resource Server)...${NC}"
102
+
103
+ EXISTING_API=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/resource-servers" \
104
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.[] | select(.identifier == "'"${API_IDENTIFIER}"'") | .id')
105
+
106
+ if [ -n "$EXISTING_API" ] && [ "$EXISTING_API" != "null" ]; then
107
+ echo -e "${BLUE} API already exists, updating...${NC}"
108
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/resource-servers/${EXISTING_API}" \
109
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
110
+ -H "Content-Type: application/json" \
111
+ -d '{
112
+ "name": "'"${API_NAME}"'",
113
+ "signing_alg": "RS256",
114
+ "allow_offline_access": true,
115
+ "token_lifetime": 86400
116
+ }' > /dev/null
117
+ else
118
+ curl -s -X POST "https://${AUTH0_DOMAIN}/api/v2/resource-servers" \
119
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
120
+ -H "Content-Type: application/json" \
121
+ -d '{
122
+ "name": "'"${API_NAME}"'",
123
+ "identifier": "'"${API_IDENTIFIER}"'",
124
+ "signing_alg": "RS256",
125
+ "allow_offline_access": true,
126
+ "token_lifetime": 86400
127
+ }' > /dev/null
128
+ fi
129
+
130
+ echo -e "${GREEN}OK API created: ${API_IDENTIFIER}${NC}"
131
+
132
+ # ============================================================
133
+ # Step 3: Create Application (Client)
134
+ # ============================================================
135
+ echo -e "${YELLOW}Step 3: Creating application...${NC}"
136
+
137
+ EXISTING_APP=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/clients" \
138
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.[] | select(.name == "'"${APP_NAME}"'") | .client_id')
139
+
140
+ if [ -n "$EXISTING_APP" ] && [ "$EXISTING_APP" != "null" ]; then
141
+ echo -e "${BLUE} Application already exists, updating...${NC}"
142
+ APP_CLIENT_ID="$EXISTING_APP"
143
+
144
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/clients/${APP_CLIENT_ID}" \
145
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
146
+ -H "Content-Type: application/json" \
147
+ -d '{
148
+ "app_type": "regular_web",
149
+ "grant_types": ["password", "authorization_code", "refresh_token", "client_credentials"],
150
+ "callbacks": ["http://localhost:3000/callback", "http://localhost:8000/callback"],
151
+ "allowed_origins": ["http://localhost:3000", "http://localhost:8000"],
152
+ "web_origins": ["http://localhost:3000", "http://localhost:8000"],
153
+ "token_endpoint_auth_method": "client_secret_post"
154
+ }' > /dev/null
155
+
156
+ APP_CLIENT_SECRET=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/clients/${APP_CLIENT_ID}" \
157
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.client_secret')
158
+ else
159
+ APP_RESPONSE=$(curl -s -X POST "https://${AUTH0_DOMAIN}/api/v2/clients" \
160
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
161
+ -H "Content-Type: application/json" \
162
+ -d '{
163
+ "name": "'"${APP_NAME}"'",
164
+ "app_type": "regular_web",
165
+ "grant_types": ["password", "authorization_code", "refresh_token", "client_credentials"],
166
+ "callbacks": ["http://localhost:3000/callback", "http://localhost:8000/callback"],
167
+ "allowed_origins": ["http://localhost:3000", "http://localhost:8000"],
168
+ "web_origins": ["http://localhost:3000", "http://localhost:8000"],
169
+ "token_endpoint_auth_method": "client_secret_post"
170
+ }')
171
+
172
+ APP_CLIENT_ID=$(echo "$APP_RESPONSE" | jq -r '.client_id')
173
+ APP_CLIENT_SECRET=$(echo "$APP_RESPONSE" | jq -r '.client_secret')
174
+
175
+ if [ -z "$APP_CLIENT_ID" ] || [ "$APP_CLIENT_ID" = "null" ]; then
176
+ echo -e "${RED}Failed to create application${NC}"
177
+ exit 1
178
+ fi
179
+ fi
180
+
181
+ echo -e "${GREEN}OK Application created: ${APP_NAME}${NC}"
182
+
183
+ # ============================================================
184
+ # Step 4: Enable ROPC (Password Grant)
185
+ # ============================================================
186
+ echo -e "${YELLOW}Step 4: Enabling Password Grant (ROPC)...${NC}"
187
+
188
+ TENANT_SETTINGS=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/tenants/settings" \
189
+ -H "Authorization: Bearer ${MGMT_TOKEN}")
190
+
191
+ if echo "$TENANT_SETTINGS" | jq -e '.default_directory' > /dev/null 2>&1; then
192
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/tenants/settings" \
193
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
194
+ -H "Content-Type: application/json" \
195
+ -d '{
196
+ "default_directory": "Username-Password-Authentication"
197
+ }' > /dev/null
198
+ echo -e "${GREEN}OK Password Grant enabled${NC}"
199
+ else
200
+ echo -e "${YELLOW}WARNING: Could not auto-enable ROPC. Please manually set:${NC}"
201
+ echo " Dashboard -> Settings -> API Authorization Settings -> Default Directory"
202
+ fi
203
+
204
+ # ============================================================
205
+ # Step 5: Create Users
206
+ # ============================================================
207
+ echo -e "${YELLOW}Step 5: Creating users...${NC}"
208
+
209
+ create_user() {
210
+ local username=$1
211
+ local email=$2
212
+ local password=$3
213
+ local tier=$4
214
+ local max_tokens=$5
215
+ local allowed_models=$6
216
+ local org=$7
217
+ local bu=$8
218
+ local team=$9
219
+ local roles=${10}
220
+
221
+ EXISTING_USER=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/users-by-email?email=${email}" \
222
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.[0].user_id')
223
+
224
+ if [ -n "$EXISTING_USER" ] && [ "$EXISTING_USER" != "null" ]; then
225
+ echo -e "${BLUE} User ${username} already exists, updating...${NC}"
226
+
227
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/users/${EXISTING_USER}" \
228
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
229
+ -H "Content-Type: application/json" \
230
+ -d '{
231
+ "app_metadata": {
232
+ "tier": "'"${tier}"'",
233
+ "max_tokens": '"${max_tokens}"',
234
+ "allowed_models": '"${allowed_models}"',
235
+ "organization": "'"${org}"'",
236
+ "business_unit": "'"${bu}"'",
237
+ "team": "'"${team}"'",
238
+ "roles": '"${roles}"'
239
+ }
240
+ }' > /dev/null
241
+ else
242
+ USER_RESPONSE=$(curl -s -X POST "https://${AUTH0_DOMAIN}/api/v2/users" \
243
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
244
+ -H "Content-Type: application/json" \
245
+ -d '{
246
+ "connection": "Username-Password-Authentication",
247
+ "email": "'"${email}"'",
248
+ "username": "'"${username}"'",
249
+ "password": "'"${password}"'",
250
+ "email_verified": true,
251
+ "app_metadata": {
252
+ "tier": "'"${tier}"'",
253
+ "max_tokens": '"${max_tokens}"',
254
+ "allowed_models": '"${allowed_models}"',
255
+ "organization": "'"${org}"'",
256
+ "business_unit": "'"${bu}"'",
257
+ "team": "'"${team}"'",
258
+ "roles": '"${roles}"'
259
+ }
260
+ }')
261
+
262
+ if echo "$USER_RESPONSE" | jq -e '.user_id' > /dev/null 2>&1; then
263
+ echo -e "${GREEN} OK User ${username} created${NC}"
264
+ else
265
+ echo -e "${RED} FAIL Failed to create ${username}${NC}"
266
+ fi
267
+ fi
268
+ }
269
+
270
+ # Demo users
271
+ create_user "alice" "alice@example.com" "Alice123!" \
272
+ "basic" 500 '["gpt-3.5-turbo"]' \
273
+ "FinTech Corp" "Analytics" "Reporting" '["analyst"]'
274
+
275
+ create_user "bob" "bob@example.com" "Bob@123!" \
276
+ "standard" 2000 '["gpt-3.5-turbo", "gpt-4"]' \
277
+ "FinTech Corp" "Analytics" "Management" '["analyst", "manager"]'
278
+
279
+ create_user "carol" "carol@example.com" "Carol123!" \
280
+ "premium" 4000 '["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo"]' \
281
+ "FinTech Corp" "Technology" "Infrastructure" '["analyst", "manager", "admin"]'
282
+
283
+ echo -e "${GREEN}OK Users created${NC}"
284
+
285
+ # ============================================================
286
+ # Step 6: Create Action for Custom Claims
287
+ # ============================================================
288
+ echo -e "${YELLOW}Step 6: Creating Action for custom claims...${NC}"
289
+
290
+ ACTION_NAME="Add MACAW Custom Claims"
291
+
292
+ EXISTING_ACTION=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/actions/actions?actionName=${ACTION_NAME}" \
293
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.actions[0].id // empty')
294
+
295
+ ACTION_CODE='exports.onExecutePostLogin = async (event, api) => {
296
+ const namespace = "https://macaw.local/";
297
+
298
+ if (event.user.app_metadata) {
299
+ const meta = event.user.app_metadata;
300
+
301
+ if (meta.tier) api.accessToken.setCustomClaim(namespace + "tier", meta.tier);
302
+ if (meta.max_tokens) api.accessToken.setCustomClaim(namespace + "max_tokens", meta.max_tokens);
303
+ if (meta.allowed_models) api.accessToken.setCustomClaim(namespace + "allowed_models", meta.allowed_models);
304
+ if (meta.organization) api.accessToken.setCustomClaim(namespace + "organization", meta.organization);
305
+ if (meta.business_unit) api.accessToken.setCustomClaim(namespace + "business_unit", meta.business_unit);
306
+ if (meta.team) api.accessToken.setCustomClaim(namespace + "team", meta.team);
307
+ if (meta.roles) api.accessToken.setCustomClaim(namespace + "roles", meta.roles);
308
+ api.accessToken.setCustomClaim(namespace + "app_metadata", meta);
309
+ }
310
+
311
+ if (event.user.username) {
312
+ api.accessToken.setCustomClaim(namespace + "username", event.user.username);
313
+ }
314
+ };'
315
+
316
+ if [ -n "$EXISTING_ACTION" ]; then
317
+ echo -e "${BLUE} Action already exists, updating...${NC}"
318
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/actions/actions/${EXISTING_ACTION}" \
319
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
320
+ -H "Content-Type: application/json" \
321
+ -d '{
322
+ "code": "'"$(echo "$ACTION_CODE" | sed 's/"/\\"/g' | tr '\n' ' ')"'"
323
+ }' > /dev/null
324
+ ACTION_ID="$EXISTING_ACTION"
325
+ else
326
+ ACTION_RESPONSE=$(curl -s -X POST "https://${AUTH0_DOMAIN}/api/v2/actions/actions" \
327
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
328
+ -H "Content-Type: application/json" \
329
+ -d '{
330
+ "name": "'"${ACTION_NAME}"'",
331
+ "supported_triggers": [{"id": "post-login", "version": "v3"}],
332
+ "code": "'"$(echo "$ACTION_CODE" | sed 's/"/\\"/g' | tr '\n' ' ')"'",
333
+ "runtime": "node18"
334
+ }')
335
+
336
+ ACTION_ID=$(echo "$ACTION_RESPONSE" | jq -r '.id')
337
+ fi
338
+
339
+ if [ -n "$ACTION_ID" ] && [ "$ACTION_ID" != "null" ]; then
340
+ curl -s -X POST "https://${AUTH0_DOMAIN}/api/v2/actions/actions/${ACTION_ID}/deploy" \
341
+ -H "Authorization: Bearer ${MGMT_TOKEN}" > /dev/null
342
+
343
+ CURRENT_BINDINGS=$(curl -s "https://${AUTH0_DOMAIN}/api/v2/actions/triggers/post-login/bindings" \
344
+ -H "Authorization: Bearer ${MGMT_TOKEN}" | jq -r '.bindings')
345
+
346
+ IS_BOUND=$(echo "$CURRENT_BINDINGS" | jq -r '.[] | select(.action.id == "'"${ACTION_ID}"'") | .id')
347
+
348
+ if [ -z "$IS_BOUND" ]; then
349
+ curl -s -X PATCH "https://${AUTH0_DOMAIN}/api/v2/actions/triggers/post-login/bindings" \
350
+ -H "Authorization: Bearer ${MGMT_TOKEN}" \
351
+ -H "Content-Type: application/json" \
352
+ -d '{
353
+ "bindings": [{"ref": {"type": "action_id", "value": "'"${ACTION_ID}"'"}}]
354
+ }' > /dev/null
355
+ fi
356
+ echo -e "${GREEN}OK Action deployed and bound${NC}"
357
+ fi
358
+
359
+ # ============================================================
360
+ # Summary
361
+ # ============================================================
362
+ echo ""
363
+ echo "=========================================="
364
+ echo -e "${GREEN}AUTH0 SETUP COMPLETE!${NC}"
365
+ echo "=========================================="
366
+ echo ""
367
+ echo "Auth0 Domain: ${AUTH0_DOMAIN}"
368
+ echo ""
369
+ echo "Application:"
370
+ echo " Name: ${APP_NAME}"
371
+ echo " Client ID: ${APP_CLIENT_ID}"
372
+ echo " Client Secret: ${APP_CLIENT_SECRET}"
373
+ echo ""
374
+ echo "API:"
375
+ echo " Name: ${API_NAME}"
376
+ echo " Identifier: ${API_IDENTIFIER}"
377
+ echo ""
378
+ echo "Test Users:"
379
+ echo " alice / Alice123! (Analyst)"
380
+ echo " bob / Bob@123! (Manager)"
381
+ echo " carol / Carol123! (Admin)"
382
+ echo ""
383
+ echo "Next step:"
384
+ echo " Update ~/.macaw/config.json with:"
385
+ echo " iam_provider: \"auth0\""
386
+ echo " iam_config.domain: \"${AUTH0_DOMAIN}\""
387
+ echo " iam_config.client_id: \"${APP_CLIENT_ID}\""
388
+ echo " iam_config.client_secret: \"${APP_CLIENT_SECRET}\""
389
+ echo ""
390
+ echo " Then run:"
391
+ echo " export OPENAI_API_KEY=sk-your-key"
392
+ echo " python3 app.py"