matimo 0.1.0-alpha.2 → 0.1.0-alpha.4
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.
- package/README.md +128 -548
- package/package.json +24 -28
- package/packages/cli/bin/matimo.cjs +26 -0
- package/packages/cli/dist/cli.d.ts +6 -0
- package/packages/cli/dist/cli.d.ts.map +1 -0
- package/packages/cli/dist/cli.js +95 -0
- package/packages/cli/dist/cli.js.map +1 -0
- package/packages/cli/dist/commands/install.d.ts +6 -0
- package/packages/cli/dist/commands/install.d.ts.map +1 -0
- package/packages/cli/dist/commands/install.js +48 -0
- package/packages/cli/dist/commands/install.js.map +1 -0
- package/packages/cli/dist/commands/list.d.ts +9 -0
- package/packages/cli/dist/commands/list.d.ts.map +1 -0
- package/packages/cli/dist/commands/list.js +70 -0
- package/packages/cli/dist/commands/list.js.map +1 -0
- package/packages/cli/dist/commands/search.d.ts +2 -0
- package/packages/cli/dist/commands/search.d.ts.map +1 -0
- package/packages/cli/dist/commands/search.js +148 -0
- package/packages/cli/dist/commands/search.js.map +1 -0
- package/packages/core/dist/src/auth/oauth2-config.d.ts.map +1 -0
- package/packages/core/dist/src/auth/oauth2-config.js.map +1 -0
- package/packages/core/dist/src/auth/oauth2-handler.d.ts.map +1 -0
- package/packages/core/dist/src/auth/oauth2-handler.js.map +1 -0
- package/packages/core/dist/src/auth/oauth2-provider-loader.d.ts.map +1 -0
- package/packages/core/dist/src/auth/oauth2-provider-loader.js.map +1 -0
- package/{dist → packages/core/dist/src}/core/schema.d.ts +12 -2
- package/packages/core/dist/src/core/schema.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/core/schema.js +20 -6
- package/packages/core/dist/src/core/schema.js.map +1 -0
- package/{dist → packages/core/dist/src}/core/tool-loader.d.ts +16 -0
- package/packages/core/dist/src/core/tool-loader.d.ts.map +1 -0
- package/packages/core/dist/src/core/tool-loader.js +205 -0
- package/packages/core/dist/src/core/tool-loader.js.map +1 -0
- package/packages/core/dist/src/core/tool-registry.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/core/tool-registry.js +5 -1
- package/packages/core/dist/src/core/tool-registry.js.map +1 -0
- package/{dist → packages/core/dist/src}/core/types.d.ts +15 -1
- package/packages/core/dist/src/core/types.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/core/types.js.map +1 -1
- package/packages/core/dist/src/decorators/index.d.ts.map +1 -0
- package/packages/core/dist/src/decorators/index.js.map +1 -0
- package/packages/core/dist/src/decorators/tool-decorator.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/decorators/tool-decorator.js +7 -4
- package/packages/core/dist/src/decorators/tool-decorator.js.map +1 -0
- package/packages/core/dist/src/encodings/parameter-encoding.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/encodings/parameter-encoding.js +9 -2
- package/packages/core/dist/src/encodings/parameter-encoding.js.map +1 -0
- package/packages/core/dist/src/errors/matimo-error.d.ts.map +1 -0
- package/packages/core/dist/src/errors/matimo-error.js.map +1 -0
- package/packages/core/dist/src/executors/command-executor.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/executors/command-executor.js +5 -1
- package/packages/core/dist/src/executors/command-executor.js.map +1 -0
- package/packages/core/dist/src/executors/function-executor.d.ts +23 -0
- package/packages/core/dist/src/executors/function-executor.d.ts.map +1 -0
- package/packages/core/dist/src/executors/function-executor.js +164 -0
- package/packages/core/dist/src/executors/function-executor.js.map +1 -0
- package/packages/core/dist/src/executors/http-executor.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/executors/http-executor.js +5 -1
- package/packages/core/dist/src/executors/http-executor.js.map +1 -0
- package/{dist → packages/core/dist/src}/index.d.ts +5 -1
- package/packages/core/dist/src/index.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/index.js +3 -0
- package/packages/core/dist/src/index.js.map +1 -0
- package/packages/core/dist/src/integrations/langchain.d.ts +46 -0
- package/packages/core/dist/src/integrations/langchain.d.ts.map +1 -0
- package/packages/core/dist/src/integrations/langchain.js +197 -0
- package/packages/core/dist/src/integrations/langchain.js.map +1 -0
- package/{dist → packages/core/dist/src}/matimo-instance.d.ts +30 -4
- package/packages/core/dist/src/matimo-instance.d.ts.map +1 -0
- package/{dist → packages/core/dist/src}/matimo-instance.js +63 -10
- package/packages/core/dist/src/matimo-instance.js.map +1 -0
- package/packages/core/dist/tools/calculator/calculator.d.ts +26 -0
- package/packages/core/dist/tools/calculator/calculator.d.ts.map +1 -0
- package/packages/core/dist/tools/calculator/calculator.js +104 -0
- package/packages/core/dist/tools/calculator/calculator.js.map +1 -0
- package/packages/core/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/auth/oauth2-config.d.ts.map +0 -1
- package/dist/auth/oauth2-config.js.map +0 -1
- package/dist/auth/oauth2-handler.d.ts.map +0 -1
- package/dist/auth/oauth2-handler.js.map +0 -1
- package/dist/auth/oauth2-provider-loader.d.ts.map +0 -1
- package/dist/auth/oauth2-provider-loader.js.map +0 -1
- package/dist/core/schema.d.ts.map +0 -1
- package/dist/core/schema.js.map +0 -1
- package/dist/core/tool-loader.d.ts.map +0 -1
- package/dist/core/tool-loader.js +0 -98
- package/dist/core/tool-loader.js.map +0 -1
- package/dist/core/tool-registry.d.ts.map +0 -1
- package/dist/core/tool-registry.js.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/decorators/index.d.ts.map +0 -1
- package/dist/decorators/index.js.map +0 -1
- package/dist/decorators/tool-decorator.d.ts.map +0 -1
- package/dist/decorators/tool-decorator.js.map +0 -1
- package/dist/encodings/parameter-encoding.d.ts.map +0 -1
- package/dist/encodings/parameter-encoding.js.map +0 -1
- package/dist/errors/matimo-error.d.ts.map +0 -1
- package/dist/errors/matimo-error.js.map +0 -1
- package/dist/executors/command-executor.d.ts.map +0 -1
- package/dist/executors/command-executor.js.map +0 -1
- package/dist/executors/http-executor.d.ts.map +0 -1
- package/dist/executors/http-executor.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/matimo-instance.d.ts.map +0 -1
- package/dist/matimo-instance.js.map +0 -1
- package/docs/Gemfile +0 -5
- package/docs/RELEASES.md +0 -90
- package/docs/ROADMAP.md +0 -138
- package/docs/_config.yml +0 -27
- package/docs/api-reference/ERRORS.md +0 -445
- package/docs/api-reference/SDK.md +0 -582
- package/docs/api-reference/TYPES.md +0 -415
- package/docs/architecture/OAUTH.md +0 -1366
- package/docs/architecture/OVERVIEW.md +0 -564
- package/docs/assets/logo.png +0 -0
- package/docs/community/COMMIT_GUIDELINES.md +0 -552
- package/docs/framework-integrations/LANGCHAIN.md +0 -286
- package/docs/getting-started/QUICK_START.md +0 -212
- package/docs/getting-started/YOUR_FIRST_TOOL.md +0 -217
- package/docs/getting-started/installation.md +0 -124
- package/docs/index.md +0 -289
- package/docs/tool-development/DECORATOR_GUIDE.md +0 -633
- package/docs/tool-development/OAUTH_LINK.md +0 -5
- package/docs/tool-development/PROVIDER_CONFIGURATION.md +0 -458
- package/docs/tool-development/TESTING.md +0 -412
- package/docs/tool-development/TOOL_SPECIFICATION.md +0 -793
- package/docs/tool-development/YAML_TOOLS.md +0 -65
- package/docs/troubleshooting/FAQ.md +0 -391
- package/docs/user-guide/AUTHENTICATION.md +0 -255
- package/docs/user-guide/DEVELOPMENT_STANDARDS.md +0 -698
- package/docs/user-guide/SDK_PATTERNS.md +0 -316
- package/docs/user-guide/TOOL_DISCOVERY.md +0 -209
- /package/{dist → packages/core/dist/src}/auth/oauth2-config.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/auth/oauth2-config.js +0 -0
- /package/{dist → packages/core/dist/src}/auth/oauth2-handler.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/auth/oauth2-handler.js +0 -0
- /package/{dist → packages/core/dist/src}/auth/oauth2-provider-loader.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/auth/oauth2-provider-loader.js +0 -0
- /package/{dist → packages/core/dist/src}/core/tool-registry.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/core/types.js +0 -0
- /package/{dist → packages/core/dist/src}/decorators/index.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/decorators/index.js +0 -0
- /package/{dist → packages/core/dist/src}/decorators/tool-decorator.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/encodings/parameter-encoding.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/errors/matimo-error.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/errors/matimo-error.js +0 -0
- /package/{dist → packages/core/dist/src}/executors/command-executor.d.ts +0 -0
- /package/{dist → packages/core/dist/src}/executors/http-executor.d.ts +0 -0
|
@@ -1,1366 +0,0 @@
|
|
|
1
|
-
# Matimo OAuth2 Implementation Guide
|
|
2
|
-
|
|
3
|
-
Complete reference for OAuth2 in Matimo: architecture, token injection, provider configuration, troubleshooting, and best practices.
|
|
4
|
-
|
|
5
|
-
## 📋 Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Overview](#overview)
|
|
8
|
-
- [Architecture](#architecture)
|
|
9
|
-
- [OAuth2 Flow](#oauth2-flow)
|
|
10
|
-
- [Provider YAML Configuration](#provider-yaml-configuration)
|
|
11
|
-
- [Token Injection System](#token-injection-system)
|
|
12
|
-
- [Implementation Details](#implementation-details)
|
|
13
|
-
- [Security Considerations](#security-considerations)
|
|
14
|
-
- [Multi-Provider Support](#multi-provider-support)
|
|
15
|
-
- [Examples](#examples)
|
|
16
|
-
- [Troubleshooting](#troubleshooting)
|
|
17
|
-
|
|
18
|
-
## Overview
|
|
19
|
-
|
|
20
|
-
### Design Principles
|
|
21
|
-
|
|
22
|
-
Matimo's OAuth2 implementation follows these core principles:
|
|
23
|
-
|
|
24
|
-
1. **Stateless Design**: Matimo does NOT store tokens. Users provide tokens via environment variables.
|
|
25
|
-
2. **YAML-Driven Configuration**: Provider OAuth endpoints and settings are defined in YAML, not hardcoded.
|
|
26
|
-
3. **Generic Parameter Injection**: Works for ANY provider (Gmail, GitHub, Slack) without hardcoding provider-specific logic.
|
|
27
|
-
4. **Framework-Agnostic**: OAuth flows happen outside Matimo; Matimo handles token injection and usage.
|
|
28
|
-
5. **Scalable**: Supports unlimited providers by adding YAML files only.
|
|
29
|
-
|
|
30
|
-
### Why This Approach?
|
|
31
|
-
|
|
32
|
-
Traditional OAuth implementations are monolithic and provider-specific. Matimo separates concerns:
|
|
33
|
-
|
|
34
|
-
- **OAuth Flows** (user authentication, token refresh) → Handled outside Matimo
|
|
35
|
-
- **Token Storage** → User's responsibility (environment variables, secure vaults)
|
|
36
|
-
- **Token Usage** → Matimo's responsibility (auto-inject into tool execution)
|
|
37
|
-
|
|
38
|
-
This keeps Matimo lightweight and lets users manage OAuth however they prefer.
|
|
39
|
-
|
|
40
|
-
## Architecture
|
|
41
|
-
|
|
42
|
-
### System Layers
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
46
|
-
│ User Code / Framework (LangChain, CrewAI, custom) │
|
|
47
|
-
│ └─ Sets: GMAIL_ACCESS_TOKEN=token123 │
|
|
48
|
-
│ └─ Calls: matimo.execute('gmail-send-email', {to, subject}) │
|
|
49
|
-
└───────────┬────────────────────────────────────────────────────┘
|
|
50
|
-
↓
|
|
51
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
52
|
-
│ MatimoInstance (src/matimo-instance.ts) │
|
|
53
|
-
│ ├─ execute(toolName, params) │
|
|
54
|
-
│ ├─ 1. Load tool from YAML │
|
|
55
|
-
│ ├─ 2. injectAuthParameters(tool, params) ← KEY STEP │
|
|
56
|
-
│ │ └─ Pattern matching: looks for TOKEN/KEY/SECRET parameters │
|
|
57
|
-
│ │ └─ Environment lookup: PARAM_NAME │
|
|
58
|
-
│ │ └─ Merges found tokens into execution params │
|
|
59
|
-
│ ├─ 3. Call executor (HttpExecutor, CommandExecutor) │
|
|
60
|
-
│ └─ 4. Return result │
|
|
61
|
-
└───────────┬────────────────────────────────────────────────────┘
|
|
62
|
-
↓
|
|
63
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
64
|
-
│ Tool YAML Definition (tools/provider/tool-name.yaml) │
|
|
65
|
-
│ ├─ execution: │
|
|
66
|
-
│ │ ├─ type: http │
|
|
67
|
-
│ │ ├─ url: https://gmail.googleapis.com/gmail/v1/users/me/... │
|
|
68
|
-
│ │ ├─ headers: │
|
|
69
|
-
│ │ │ └─ Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" │
|
|
70
|
-
│ │ ├─ query_params: {...} │
|
|
71
|
-
│ │ └─ parameter_encoding: {...} │
|
|
72
|
-
│ ├─ authentication: │
|
|
73
|
-
│ │ ├─ type: oauth2 │
|
|
74
|
-
│ │ ├─ provider: gmail │
|
|
75
|
-
│ │ └─ required_scopes: [...] │
|
|
76
|
-
│ └─ parameters: {...} │
|
|
77
|
-
└───────────┬────────────────────────────────────────────────────┘
|
|
78
|
-
↓
|
|
79
|
-
┌────────────────────────────────────────────────────────────────┐
|
|
80
|
-
│ Provider Config YAML (tools/provider/definition.yaml) │
|
|
81
|
-
│ ├─ Centralized OAuth2 endpoints │
|
|
82
|
-
│ ├─ Example for Gmail: │
|
|
83
|
-
│ │ ├─ token_url: https://oauth2.googleapis.com/token │
|
|
84
|
-
│ │ ├─ auth_url: https://accounts.google.com/o/oauth2/auth │
|
|
85
|
-
│ │ ├─ scopes: {gmail: [...], drive: [...]} │
|
|
86
|
-
│ │ └─ redirect_uri: https://localhost:3000/callback │
|
|
87
|
-
│ └─ Used by OAuth2ProviderLoader │
|
|
88
|
-
└────────────────────────────────────────────────────────────────┘
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Core Components
|
|
92
|
-
|
|
93
|
-
| Component | Purpose | Location |
|
|
94
|
-
|-----------|---------|----------|
|
|
95
|
-
| **MatimoInstance** | Main SDK class; orchestrates execution | `src/matimo-instance.ts` |
|
|
96
|
-
| **injectAuthParameters()** | Pattern-based token injection | `src/matimo-instance.ts` |
|
|
97
|
-
| **OAuth2ProviderLoader** | Loads provider config from YAML | `src/auth/oauth2-provider-loader.ts` |
|
|
98
|
-
| **OAuth2ProviderConfig** | In-memory provider configuration | `src/auth/oauth2-provider-config.ts` |
|
|
99
|
-
| **ToolDefinition** | Type for tool schemas | `src/core/types.ts` |
|
|
100
|
-
| **HttpExecutor** | Executes HTTP requests | `src/executors/http-executor.ts` |
|
|
101
|
-
|
|
102
|
-
## OAuth2 Flow
|
|
103
|
-
|
|
104
|
-
### Standard OAuth2 Authorization Flow
|
|
105
|
-
|
|
106
|
-
Matimo supports the **Authorization Code Flow** (most common for web apps and CLI tools):
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
User Application Google OAuth Server
|
|
110
|
-
↓ ↑
|
|
111
|
-
1. Redirect to Google │
|
|
112
|
-
GET https://accounts.google.com/o/oauth2/auth
|
|
113
|
-
?client_id=YOUR_CLIENT_ID
|
|
114
|
-
&redirect_uri=http://localhost:3000/callback
|
|
115
|
-
&scope=https://www.googleapis.com/auth/gmail.send
|
|
116
|
-
&response_type=code
|
|
117
|
-
└───────────────────────────────────────────→
|
|
118
|
-
│
|
|
119
|
-
2. User clicks "Allow"
|
|
120
|
-
│
|
|
121
|
-
3. Browser redirected to callback ←──────┘
|
|
122
|
-
with authorization code (auth_code)
|
|
123
|
-
↓
|
|
124
|
-
4. Exchange code for token (backend)
|
|
125
|
-
POST https://oauth2.googleapis.com/token
|
|
126
|
-
{
|
|
127
|
-
code: auth_code,
|
|
128
|
-
client_id: YOUR_CLIENT_ID,
|
|
129
|
-
client_secret: YOUR_CLIENT_SECRET,
|
|
130
|
-
grant_type: "authorization_code"
|
|
131
|
-
}
|
|
132
|
-
└───────────────────────────────────────────→
|
|
133
|
-
│
|
|
134
|
-
5. Receive access_token + refresh_token ←───┘
|
|
135
|
-
↓
|
|
136
|
-
6. Store access_token (env var, secure vault)
|
|
137
|
-
↓
|
|
138
|
-
7. Use with Matimo:
|
|
139
|
-
process.env.GMAIL_ACCESS_TOKEN = access_token
|
|
140
|
-
await matimo.execute('gmail-send-email', {...})
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Matimo's Role in the Flow
|
|
144
|
-
|
|
145
|
-
**What Matimo DOES:**
|
|
146
|
-
- ✅ Inject tokens into tool execution (step 7)
|
|
147
|
-
- ✅ Validate token is present before execution
|
|
148
|
-
- ✅ Handle token in HTTP headers correctly
|
|
149
|
-
- ✅ Support token override at runtime
|
|
150
|
-
|
|
151
|
-
**What Matimo DOES NOT Do:**
|
|
152
|
-
- ❌ Perform OAuth authorization (steps 1-2)
|
|
153
|
-
- ❌ Exchange code for token (step 4)
|
|
154
|
-
- ❌ Store tokens (step 6)
|
|
155
|
-
- ❌ Refresh expired tokens
|
|
156
|
-
- ❌ Handle user login/logout
|
|
157
|
-
|
|
158
|
-
**Why?** Matimo is framework-agnostic and stateless. OAuth flows vary by framework and security requirements.
|
|
159
|
-
|
|
160
|
-
### Token Lifecycle in Matimo
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
164
|
-
│ 1. User obtains token (outside Matimo) │
|
|
165
|
-
│ - Via OAuth playground │
|
|
166
|
-
│ - Via OAuth library (google-auth-library, etc.) │
|
|
167
|
-
│ - Via custom OAuth flow │
|
|
168
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
169
|
-
↓
|
|
170
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
171
|
-
│ 2. Store token in environment │
|
|
172
|
-
│ export GMAIL_ACCESS_TOKEN=ya29.a0AXooCg... │
|
|
173
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
174
|
-
↓
|
|
175
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
176
|
-
│ 3. Matimo injectAuthParameters() │
|
|
177
|
-
│ - Scans tool's execution config for {PARAM} placeholders │
|
|
178
|
-
│ - Finds {GMAIL_ACCESS_TOKEN} │
|
|
179
|
-
│ - Looks up env: GMAIL_ACCESS_TOKEN │
|
|
180
|
-
│ - Injects into request headers/body │
|
|
181
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
182
|
-
↓
|
|
183
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
184
|
-
│ 4. HttpExecutor sends request with token │
|
|
185
|
-
│ Authorization: Bearer ya29.a0AXooCg... │
|
|
186
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
187
|
-
↓
|
|
188
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
189
|
-
│ 5. API validates token, executes request │
|
|
190
|
-
└─────────────────────────────────────────────────────────────┘
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## Provider YAML Configuration
|
|
194
|
-
|
|
195
|
-
### Provider Definition File Structure
|
|
196
|
-
|
|
197
|
-
Each provider has a central configuration file: `tools/{provider}/definition.yaml`
|
|
198
|
-
|
|
199
|
-
**Example: Gmail Provider** (`tools/gmail/definition.yaml`)
|
|
200
|
-
|
|
201
|
-
```yaml
|
|
202
|
-
provider:
|
|
203
|
-
name: gmail
|
|
204
|
-
description: Google Gmail API
|
|
205
|
-
documentation_url: https://developers.google.com/gmail/api
|
|
206
|
-
|
|
207
|
-
oauth2:
|
|
208
|
-
# OAuth2 endpoints
|
|
209
|
-
auth_url: https://accounts.google.com/o/oauth2/auth
|
|
210
|
-
token_url: https://oauth2.googleapis.com/token
|
|
211
|
-
revoke_url: https://oauth2.googleapis.com/revoke
|
|
212
|
-
|
|
213
|
-
# Scopes for different permission levels
|
|
214
|
-
scopes:
|
|
215
|
-
send:
|
|
216
|
-
- https://www.googleapis.com/auth/gmail.send
|
|
217
|
-
- https://www.googleapis.com/auth/gmail.readonly
|
|
218
|
-
draft:
|
|
219
|
-
- https://www.googleapis.com/auth/gmail.modify
|
|
220
|
-
full_access:
|
|
221
|
-
- https://www.googleapis.com/auth/gmail
|
|
222
|
-
|
|
223
|
-
# Default redirect URI for local dev
|
|
224
|
-
redirect_uri: http://localhost:3000/callback
|
|
225
|
-
|
|
226
|
-
# If your app needs specific settings
|
|
227
|
-
approval_prompt: force # Force consent screen
|
|
228
|
-
access_type: offline # Get refresh token
|
|
229
|
-
|
|
230
|
-
# Override mechanism (defined in tool YAML)
|
|
231
|
-
parameter_mapping:
|
|
232
|
-
# Maps parameter names to environment variable patterns
|
|
233
|
-
- parameter: GMAIL_ACCESS_TOKEN
|
|
234
|
-
env_pattern: "GMAIL_ACCESS_TOKEN"
|
|
235
|
-
required: true
|
|
236
|
-
description: "Gmail OAuth access token"
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Supported Provider Fields
|
|
240
|
-
|
|
241
|
-
| Field | Type | Required | Description |
|
|
242
|
-
|-------|------|----------|-------------|
|
|
243
|
-
| `provider.name` | string | Yes | Provider identifier (gmail, github, slack) |
|
|
244
|
-
| `provider.description` | string | No | Human-readable description |
|
|
245
|
-
| `oauth2.auth_url` | string | Yes | Authorization endpoint |
|
|
246
|
-
| `oauth2.token_url` | string | Yes | Token exchange endpoint |
|
|
247
|
-
| `oauth2.revoke_url` | string | No | Token revocation endpoint |
|
|
248
|
-
| `oauth2.scopes` | object | Yes | Available OAuth scopes (grouped by feature) |
|
|
249
|
-
| `oauth2.redirect_uri` | string | Yes | Redirect URI after user authorizes |
|
|
250
|
-
| `oauth2.approval_prompt` | string | No | "force" to always show consent screen |
|
|
251
|
-
| `oauth2.access_type` | string | No | "offline" to get refresh token |
|
|
252
|
-
|
|
253
|
-
## Token Injection System
|
|
254
|
-
|
|
255
|
-
### How Matimo Auto-Injects Tokens
|
|
256
|
-
|
|
257
|
-
The `injectAuthParameters()` method in `MatimoInstance` performs three steps:
|
|
258
|
-
|
|
259
|
-
#### Step 1: Extract Parameter Placeholders
|
|
260
|
-
|
|
261
|
-
Scan the tool's execution config for `{PARAM_NAME}` patterns:
|
|
262
|
-
|
|
263
|
-
```yaml
|
|
264
|
-
execution:
|
|
265
|
-
type: http
|
|
266
|
-
url: "https://gmail.googleapis.com/..."
|
|
267
|
-
headers:
|
|
268
|
-
Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" # ← Found!
|
|
269
|
-
body:
|
|
270
|
-
message: "{COMPOSED_MESSAGE}" # ← Found!
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Result: Array of found parameters: `["GMAIL_ACCESS_TOKEN", "COMPOSED_MESSAGE"]`
|
|
274
|
-
|
|
275
|
-
#### Step 2: Identify Auth Parameters
|
|
276
|
-
|
|
277
|
-
Filter by pattern matching (parameters are auth-related if they contain):
|
|
278
|
-
- `TOKEN`
|
|
279
|
-
- `KEY`
|
|
280
|
-
- `SECRET`
|
|
281
|
-
- `PASSWORD`
|
|
282
|
-
- `CREDENTIAL`
|
|
283
|
-
- `APIKEY`
|
|
284
|
-
|
|
285
|
-
Example:
|
|
286
|
-
- ✅ `GMAIL_ACCESS_TOKEN` → Contains "TOKEN" → Auth parameter
|
|
287
|
-
- ✅ `API_KEY` → Contains "KEY" → Auth parameter
|
|
288
|
-
- ❌ `COMPOSED_MESSAGE` → No match → User parameter (not injected)
|
|
289
|
-
|
|
290
|
-
#### Step 3: Environment Lookup & Injection
|
|
291
|
-
|
|
292
|
-
For each auth parameter, look up environment variables:
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
// Parameter: GMAIL_ACCESS_TOKEN
|
|
296
|
-
|
|
297
|
-
// Try 1: prefix (recommended)
|
|
298
|
-
process.env.GMAIL_ACCESS_TOKEN
|
|
299
|
-
// Falls back to:
|
|
300
|
-
|
|
301
|
-
// Try 2: Direct name
|
|
302
|
-
process.env.GMAIL_ACCESS_TOKEN
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
If found, inject into execution parameters.
|
|
306
|
-
|
|
307
|
-
### Code Implementation
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
// In src/matimo-instance.ts
|
|
311
|
-
|
|
312
|
-
private injectAuthParameters(
|
|
313
|
-
tool: ToolDefinition,
|
|
314
|
-
params: Record<string, any>
|
|
315
|
-
): Record<string, any> {
|
|
316
|
-
// Step 1: Extract parameter placeholders from execution config
|
|
317
|
-
const placeholders = this.extractParameterPlaceholders(
|
|
318
|
-
tool.execution
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
// Step 2 & 3: For each placeholder, attempt to inject from environment
|
|
322
|
-
const injected = { ...params };
|
|
323
|
-
|
|
324
|
-
for (const placeholder of placeholders) {
|
|
325
|
-
// Check if this looks like an auth parameter
|
|
326
|
-
if (this.isAuthParameter(placeholder)) {
|
|
327
|
-
// Try prefix first, then fallback to direct name
|
|
328
|
-
const envKey = `${placeholder}`;
|
|
329
|
-
let value = process.env[envKey] || process.env[placeholder];
|
|
330
|
-
|
|
331
|
-
if (value) {
|
|
332
|
-
injected[placeholder] = value;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return injected;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
private extractParameterPlaceholders(
|
|
341
|
-
obj: any
|
|
342
|
-
): string[] {
|
|
343
|
-
const placeholders: string[] = [];
|
|
344
|
-
const regex = /\{(\w+)\}/g;
|
|
345
|
-
|
|
346
|
-
const scan = (value: any) => {
|
|
347
|
-
if (typeof value === 'string') {
|
|
348
|
-
let match;
|
|
349
|
-
while ((match = regex.exec(value)) !== null) {
|
|
350
|
-
placeholders.push(match[1]);
|
|
351
|
-
}
|
|
352
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
353
|
-
Object.values(value).forEach(scan);
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
scan(obj);
|
|
358
|
-
return [...new Set(placeholders)]; // Deduplicate
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
private isAuthParameter(name: string): boolean {
|
|
362
|
-
const authPatterns = [
|
|
363
|
-
'TOKEN', 'KEY', 'SECRET', 'PASSWORD',
|
|
364
|
-
'CREDENTIAL', 'APIKEY', 'AUTH'
|
|
365
|
-
];
|
|
366
|
-
return authPatterns.some(pattern =>
|
|
367
|
-
name.toUpperCase().includes(pattern)
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Token Injection Examples
|
|
373
|
-
|
|
374
|
-
#### Example 1: Gmail Send Email
|
|
375
|
-
|
|
376
|
-
**Tool YAML:**
|
|
377
|
-
```yaml
|
|
378
|
-
name: send-email
|
|
379
|
-
execution:
|
|
380
|
-
type: http
|
|
381
|
-
method: post
|
|
382
|
-
url: https://gmail.googleapis.com/gmail/v1/users/me/messages/send
|
|
383
|
-
headers:
|
|
384
|
-
Authorization: "Bearer {GMAIL_ACCESS_TOKEN}"
|
|
385
|
-
body:
|
|
386
|
-
raw: "{ENCODED_MESSAGE}"
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
**User Code:**
|
|
390
|
-
```typescript
|
|
391
|
-
process.env.GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg...";
|
|
392
|
-
|
|
393
|
-
await matimo.execute('gmail-send-email', {
|
|
394
|
-
to: 'user@example.com',
|
|
395
|
-
subject: 'Hello',
|
|
396
|
-
body: 'Test message',
|
|
397
|
-
// GMAIL_ACCESS_TOKEN NOT needed - auto-injected!
|
|
398
|
-
});
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
**What Happens:**
|
|
402
|
-
1. User provides: `to`, `subject`, `body`
|
|
403
|
-
2. Matimo extracts placeholders: `GMAIL_ACCESS_TOKEN`, `ENCODED_MESSAGE`
|
|
404
|
-
3. Matimo identifies `GMAIL_ACCESS_TOKEN` as auth parameter (contains "TOKEN")
|
|
405
|
-
4. Matimo looks up `GMAIL_ACCESS_TOKEN` → found
|
|
406
|
-
5. Matimo injects: `GMAIL_ACCESS_TOKEN: "ya29.a0AXooCg..."`
|
|
407
|
-
6. Request sent with `Authorization: Bearer ya29.a0AXooCg...`
|
|
408
|
-
|
|
409
|
-
#### Example 2: GitHub Repository API
|
|
410
|
-
|
|
411
|
-
**Tool YAML:**
|
|
412
|
-
```yaml
|
|
413
|
-
name: get-repo-info
|
|
414
|
-
execution:
|
|
415
|
-
type: http
|
|
416
|
-
url: https://api.github.com/repos/{owner}/{repo}
|
|
417
|
-
headers:
|
|
418
|
-
Authorization: "Bearer {GITHUB_API_KEY}"
|
|
419
|
-
Accept: "application/vnd.github.v3+json"
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
**User Code:**
|
|
423
|
-
```typescript
|
|
424
|
-
process.env.GITHUB_API_KEY = "ghp_abc123...";
|
|
425
|
-
|
|
426
|
-
await matimo.execute('get-repo-info', {
|
|
427
|
-
owner: 'torvalds',
|
|
428
|
-
repo: 'linux',
|
|
429
|
-
// GITHUB_API_KEY auto-injected
|
|
430
|
-
});
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
## Implementation Details
|
|
434
|
-
|
|
435
|
-
### Files & Locations
|
|
436
|
-
|
|
437
|
-
| File | Purpose |
|
|
438
|
-
|------|---------|
|
|
439
|
-
| `src/matimo-instance.ts` | Main SDK class, contains `injectAuthParameters()` |
|
|
440
|
-
| `src/auth/oauth2-provider-config.ts` | OAuth2 provider configuration loader |
|
|
441
|
-
| `src/auth/oauth2-provider-loader.ts` | YAML provider file parser |
|
|
442
|
-
| `src/core/types.ts` | `ToolDefinition` interface |
|
|
443
|
-
| `src/executors/http-executor.ts` | HTTP request execution |
|
|
444
|
-
| `tools/{provider}/definition.yaml` | Provider OAuth configuration |
|
|
445
|
-
| `tools/{provider}/{tool}.yaml` | Individual tool definitions |
|
|
446
|
-
|
|
447
|
-
### OAuth2ProviderLoader
|
|
448
|
-
|
|
449
|
-
```typescript
|
|
450
|
-
// Load provider config from YAML
|
|
451
|
-
const loader = new OAuth2ProviderLoader('./tools');
|
|
452
|
-
const gmailConfig = await loader.loadProvider('gmail');
|
|
453
|
-
|
|
454
|
-
// Result:
|
|
455
|
-
{
|
|
456
|
-
name: 'gmail',
|
|
457
|
-
oauth2: {
|
|
458
|
-
auth_url: '...',
|
|
459
|
-
token_url: '...',
|
|
460
|
-
scopes: { ... }
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
### OAuth2ProviderConfig
|
|
466
|
-
|
|
467
|
-
```typescript
|
|
468
|
-
// In-memory provider config storage
|
|
469
|
-
const config = new OAuth2ProviderConfig();
|
|
470
|
-
|
|
471
|
-
// Register provider
|
|
472
|
-
await config.addProvider('gmail', gmailConfig);
|
|
473
|
-
|
|
474
|
-
// Retrieve provider
|
|
475
|
-
const provider = config.getProvider('gmail');
|
|
476
|
-
|
|
477
|
-
// List all providers
|
|
478
|
-
const all = config.getAllProviders();
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
## Security Considerations
|
|
482
|
-
|
|
483
|
-
### ✅ Security Best Practices
|
|
484
|
-
|
|
485
|
-
#### 1. Token Storage
|
|
486
|
-
|
|
487
|
-
**DON'T:**
|
|
488
|
-
```bash
|
|
489
|
-
# ❌ Bad: Token in code
|
|
490
|
-
const token = "ya29.a0AXooCg...";
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
**DO:**
|
|
494
|
-
```bash
|
|
495
|
-
# ✅ Good: Token in environment variable
|
|
496
|
-
export GMAIL_ACCESS_TOKEN="ya29.a0AXooCg..."
|
|
497
|
-
|
|
498
|
-
# ✅ Better: Use .env file with .gitignore
|
|
499
|
-
# .env (never commit)
|
|
500
|
-
GMAIL_ACCESS_TOKEN=ya29.a0AXooCg...
|
|
501
|
-
|
|
502
|
-
# .gitignore
|
|
503
|
-
.env
|
|
504
|
-
.env.local
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
**✅ BEST: Secure Vault**
|
|
508
|
-
```bash
|
|
509
|
-
# Use 1Password, LastPass, AWS Secrets Manager, etc.
|
|
510
|
-
# Retrieve at runtime:
|
|
511
|
-
const token = await vault.getSecret('matimo-gmail-token');
|
|
512
|
-
process.env.GMAIL_ACCESS_TOKEN = token;
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
#### 2. Token Permissions (Scopes)
|
|
516
|
-
|
|
517
|
-
Always request minimum required scopes:
|
|
518
|
-
|
|
519
|
-
```yaml
|
|
520
|
-
# ❌ Bad: Full access
|
|
521
|
-
scopes:
|
|
522
|
-
- https://www.googleapis.com/auth/gmail
|
|
523
|
-
|
|
524
|
-
# ✅ Good: Specific scopes
|
|
525
|
-
scopes:
|
|
526
|
-
send:
|
|
527
|
-
- https://www.googleapis.com/auth/gmail.send # Send only
|
|
528
|
-
read:
|
|
529
|
-
- https://www.googleapis.com/auth/gmail.readonly # Read only
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
#### 3. Token Expiration
|
|
533
|
-
|
|
534
|
-
Monitor token expiration and refresh:
|
|
535
|
-
|
|
536
|
-
```typescript
|
|
537
|
-
// Token expiration typically: 1 hour for access tokens
|
|
538
|
-
// What to do when expired:
|
|
539
|
-
|
|
540
|
-
// Option 1: Refresh token (Phase 2 feature)
|
|
541
|
-
const newToken = await oauth2.refreshToken(refreshToken);
|
|
542
|
-
process.env.GMAIL_ACCESS_TOKEN = newToken;
|
|
543
|
-
|
|
544
|
-
// Option 2: Re-authorize
|
|
545
|
-
console.error('Token expired. Please re-authenticate:');
|
|
546
|
-
console.log('Visit: https://oauth2.example.com/authorize');
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
#### 4. Token Revocation
|
|
550
|
-
|
|
551
|
-
Always revoke tokens when done:
|
|
552
|
-
|
|
553
|
-
```typescript
|
|
554
|
-
// After tool execution completes
|
|
555
|
-
await oauth2.revokeToken(accessToken, {
|
|
556
|
-
provider: 'gmail',
|
|
557
|
-
revoke_url: 'https://oauth2.googleapis.com/revoke'
|
|
558
|
-
});
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
#### 5. Log Sanitization
|
|
562
|
-
|
|
563
|
-
Never log tokens:
|
|
564
|
-
|
|
565
|
-
```typescript
|
|
566
|
-
// ❌ Bad: Token in logs
|
|
567
|
-
logger.info('Sending email', {
|
|
568
|
-
token: params.GMAIL_ACCESS_TOKEN, // DANGER!
|
|
569
|
-
to: 'user@example.com'
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
// ✅ Good: Sanitize sensitive data
|
|
573
|
-
const sanitized = {
|
|
574
|
-
to: params.to,
|
|
575
|
-
subject: params.subject,
|
|
576
|
-
// token: never logged
|
|
577
|
-
};
|
|
578
|
-
logger.info('Sending email', sanitized);
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### 🛡️ Attack Mitigation
|
|
582
|
-
|
|
583
|
-
#### Cross-Site Request Forgery (CSRF) Protection
|
|
584
|
-
|
|
585
|
-
When implementing OAuth flow (Phase 2):
|
|
586
|
-
|
|
587
|
-
```typescript
|
|
588
|
-
// Generate random state parameter
|
|
589
|
-
const state = crypto.randomBytes(32).toString('hex');
|
|
590
|
-
session.setState(state);
|
|
591
|
-
|
|
592
|
-
// Verify state in callback
|
|
593
|
-
if (request.query.state !== session.getState()) {
|
|
594
|
-
throw new Error('State mismatch - CSRF attack?');
|
|
595
|
-
}
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
#### Token Leakage Prevention
|
|
599
|
-
|
|
600
|
-
```typescript
|
|
601
|
-
// ❌ Never expose tokens in URLs
|
|
602
|
-
GET /api/tool?token=ya29.a0AXooCg...
|
|
603
|
-
|
|
604
|
-
// ✅ Always use headers or POST body
|
|
605
|
-
headers: {
|
|
606
|
-
Authorization: 'Bearer ya29.a0AXooCg...'
|
|
607
|
-
}
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
#### Secret Rotation
|
|
611
|
-
|
|
612
|
-
```yaml
|
|
613
|
-
# tools/gmail/definition.yaml
|
|
614
|
-
oauth2:
|
|
615
|
-
client_id: ${GMAIL_CLIENT_ID} # From env
|
|
616
|
-
client_secret: ${GMAIL_CLIENT_SECRET} # From env (rotate regularly)
|
|
617
|
-
# Schedule periodic secret rotation in your OAuth app settings
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
## Multi-Provider Support
|
|
621
|
-
|
|
622
|
-
### Adding a New Provider
|
|
623
|
-
|
|
624
|
-
Matimo supports unlimited providers without code changes.
|
|
625
|
-
|
|
626
|
-
#### Step 1: Create Provider Config
|
|
627
|
-
|
|
628
|
-
Create `tools/{provider}/definition.yaml`:
|
|
629
|
-
|
|
630
|
-
```yaml
|
|
631
|
-
# tools/github/definition.yaml
|
|
632
|
-
provider:
|
|
633
|
-
name: github
|
|
634
|
-
description: GitHub API
|
|
635
|
-
documentation_url: https://docs.github.com/en/rest
|
|
636
|
-
|
|
637
|
-
oauth2:
|
|
638
|
-
auth_url: https://github.com/login/oauth/authorize
|
|
639
|
-
token_url: https://github.com/login/oauth/access_token
|
|
640
|
-
revoke_url: https://api.github.com/applications/{client_id}/token
|
|
641
|
-
|
|
642
|
-
scopes:
|
|
643
|
-
read:
|
|
644
|
-
- repo:status
|
|
645
|
-
- public_repo
|
|
646
|
-
write:
|
|
647
|
-
- repo
|
|
648
|
-
admin:
|
|
649
|
-
- admin:repo_hook
|
|
650
|
-
- admin:user
|
|
651
|
-
|
|
652
|
-
redirect_uri: http://localhost:3000/callback
|
|
653
|
-
access_type: offline # Get refresh token
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
#### Step 2: Create Tool Definitions
|
|
657
|
-
|
|
658
|
-
Create `tools/github/{tool}.yaml` files:
|
|
659
|
-
|
|
660
|
-
```yaml
|
|
661
|
-
# tools/github/get-repo.yaml
|
|
662
|
-
name: get-repo
|
|
663
|
-
description: Get GitHub repository information
|
|
664
|
-
version: '1.0.0'
|
|
665
|
-
|
|
666
|
-
parameters:
|
|
667
|
-
owner:
|
|
668
|
-
type: string
|
|
669
|
-
required: true
|
|
670
|
-
description: Repository owner
|
|
671
|
-
repo:
|
|
672
|
-
type: string
|
|
673
|
-
required: true
|
|
674
|
-
description: Repository name
|
|
675
|
-
|
|
676
|
-
execution:
|
|
677
|
-
type: http
|
|
678
|
-
method: get
|
|
679
|
-
url: "https://api.github.com/repos/{owner}/{repo}"
|
|
680
|
-
headers:
|
|
681
|
-
Authorization: "Bearer {GITHUB_API_KEY}"
|
|
682
|
-
Accept: "application/vnd.github.v3+json"
|
|
683
|
-
|
|
684
|
-
authentication:
|
|
685
|
-
type: oauth2
|
|
686
|
-
provider: github
|
|
687
|
-
required_scopes:
|
|
688
|
-
- public_repo
|
|
689
|
-
|
|
690
|
-
output_schema:
|
|
691
|
-
type: object
|
|
692
|
-
properties:
|
|
693
|
-
name:
|
|
694
|
-
type: string
|
|
695
|
-
full_name:
|
|
696
|
-
type: string
|
|
697
|
-
stars:
|
|
698
|
-
type: integer
|
|
699
|
-
description:
|
|
700
|
-
type: string
|
|
701
|
-
```
|
|
702
|
-
|
|
703
|
-
#### Step 3: Use in Code
|
|
704
|
-
|
|
705
|
-
No code changes needed!
|
|
706
|
-
|
|
707
|
-
```typescript
|
|
708
|
-
// Matimo automatically discovers and loads tools/github/*.yaml
|
|
709
|
-
const tools = await loader.loadToolsFromDirectory('./tools');
|
|
710
|
-
|
|
711
|
-
// GitHub tools are now available
|
|
712
|
-
await matimo.execute('get-repo', {
|
|
713
|
-
owner: 'torvalds',
|
|
714
|
-
repo: 'linux'
|
|
715
|
-
// GITHUB_API_KEY auto-injected from GITHUB_API_KEY
|
|
716
|
-
});
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
### Runtime Override Example
|
|
720
|
-
|
|
721
|
-
```typescript
|
|
722
|
-
// Override provider endpoint at runtime
|
|
723
|
-
const tool = tools.find(t => t.name === 'get-repo');
|
|
724
|
-
|
|
725
|
-
// Option 1: Env variable
|
|
726
|
-
process.env.GITHUB_API_KEY = 'custom-token';
|
|
727
|
-
|
|
728
|
-
// Option 2: Runtime argument
|
|
729
|
-
const result = await matimo.execute('get-repo', {
|
|
730
|
-
owner: 'torvalds',
|
|
731
|
-
repo: 'linux',
|
|
732
|
-
GITHUB_API_KEY: 'custom-token' // Overrides env
|
|
733
|
-
});
|
|
734
|
-
```
|
|
735
|
-
|
|
736
|
-
## Token Passing Methods
|
|
737
|
-
|
|
738
|
-
### How Users Can Pass Tokens
|
|
739
|
-
|
|
740
|
-
Users have **multiple flexible options** to pass tokens to Matimo - not just environment variables:
|
|
741
|
-
|
|
742
|
-
#### Option 1: Explicit Parameter (Highest Priority)
|
|
743
|
-
|
|
744
|
-
Pass the token directly in the execute call. This is the most flexible and secure approach:
|
|
745
|
-
|
|
746
|
-
```typescript
|
|
747
|
-
const token = await getTokenFromVault('gmail'); // Get from vault, database, etc.
|
|
748
|
-
|
|
749
|
-
await matimo.execute('send-email', {
|
|
750
|
-
to: 'user@example.com',
|
|
751
|
-
subject: 'Hello',
|
|
752
|
-
body: 'Test',
|
|
753
|
-
GMAIL_ACCESS_TOKEN: token // ✅ Explicit - takes precedence!
|
|
754
|
-
});
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
**Advantages:**
|
|
758
|
-
- ✅ Most secure (tokens not stored in env)
|
|
759
|
-
- ✅ Per-request flexibility
|
|
760
|
-
- ✅ Multi-tenant support
|
|
761
|
-
- ✅ Works with secure vaults
|
|
762
|
-
|
|
763
|
-
**Use cases:** Production, microservices, multi-tenant apps
|
|
764
|
-
|
|
765
|
-
#### Option 2: Runtime Environment Variable
|
|
766
|
-
|
|
767
|
-
Set the environment variable at runtime from a vault or database:
|
|
768
|
-
|
|
769
|
-
```typescript
|
|
770
|
-
// Fetch token at startup
|
|
771
|
-
const token = await secretsManager.getSecret('matimo-gmail-token');
|
|
772
|
-
|
|
773
|
-
// Set in environment
|
|
774
|
-
process.env.GMAIL_ACCESS_TOKEN = token;
|
|
775
|
-
|
|
776
|
-
// Token auto-injected in all execute calls
|
|
777
|
-
await matimo.execute('send-email', {
|
|
778
|
-
to: 'user@example.com',
|
|
779
|
-
subject: 'Hello',
|
|
780
|
-
body: 'Test'
|
|
781
|
-
// Token auto-injected from process.env
|
|
782
|
-
});
|
|
783
|
-
```
|
|
784
|
-
|
|
785
|
-
**Advantages:**
|
|
786
|
-
- ✅ Clean code (auto-injection)
|
|
787
|
-
- ✅ Simple to implement
|
|
788
|
-
- ✅ Works across app
|
|
789
|
-
|
|
790
|
-
**Use cases:** Development, single-tenant apps, startups
|
|
791
|
-
|
|
792
|
-
#### Option 3: Combination (Best Practice)
|
|
793
|
-
|
|
794
|
-
Use both approaches together:
|
|
795
|
-
|
|
796
|
-
```typescript
|
|
797
|
-
// At app startup - set env var
|
|
798
|
-
process.env.GMAIL_ACCESS_TOKEN = initialToken;
|
|
799
|
-
|
|
800
|
-
// Later - override for specific request if needed
|
|
801
|
-
await matimo.execute('send-email', {
|
|
802
|
-
to: 'user@example.com',
|
|
803
|
-
subject: 'Hello',
|
|
804
|
-
body: 'Test',
|
|
805
|
-
GMAIL_ACCESS_TOKEN: differentToken // Override for this request
|
|
806
|
-
});
|
|
807
|
-
|
|
808
|
-
// Other requests - use env var (auto-injected)
|
|
809
|
-
await matimo.execute('send-email', {
|
|
810
|
-
to: 'other@example.com',
|
|
811
|
-
subject: 'Hello',
|
|
812
|
-
body: 'Test'
|
|
813
|
-
// Uses GMAIL_ACCESS_TOKEN from env
|
|
814
|
-
});
|
|
815
|
-
```
|
|
816
|
-
|
|
817
|
-
### Token Resolution Priority
|
|
818
|
-
|
|
819
|
-
When Matimo needs a token, it checks in this order:
|
|
820
|
-
|
|
821
|
-
```
|
|
822
|
-
1. Explicit parameter (highest priority)
|
|
823
|
-
└─ await matimo.execute('tool', { GMAIL_ACCESS_TOKEN: 'explicit' })
|
|
824
|
-
|
|
825
|
-
2. Environment variable (fallback)
|
|
826
|
-
├─ process.env.GMAIL_ACCESS_TOKEN
|
|
827
|
-
└─ process.env.GMAIL_ACCESS_TOKEN (if not found)
|
|
828
|
-
|
|
829
|
-
3. Not found (lowest priority)
|
|
830
|
-
└─ Error: "Missing required parameter: GMAIL_ACCESS_TOKEN"
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
The first match wins - others are ignored.
|
|
834
|
-
|
|
835
|
-
### Real-World Examples
|
|
836
|
-
|
|
837
|
-
#### Example: Secure Vault (AWS Secrets Manager)
|
|
838
|
-
|
|
839
|
-
```typescript
|
|
840
|
-
import AWS from 'aws-sdk';
|
|
841
|
-
|
|
842
|
-
const secretsManager = new AWS.SecretsManager();
|
|
843
|
-
|
|
844
|
-
async function executeWithVaultToken(toolName, params) {
|
|
845
|
-
// Fetch token from AWS Secrets Manager at runtime
|
|
846
|
-
const secret = await secretsManager.getSecretValue({
|
|
847
|
-
SecretId: 'matimo-gmail-token'
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
const token = JSON.parse(secret.SecretString).token;
|
|
851
|
-
|
|
852
|
-
// Pass explicitly - never stored in code or env
|
|
853
|
-
return await matimo.execute(toolName, {
|
|
854
|
-
...params,
|
|
855
|
-
GMAIL_ACCESS_TOKEN: token
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// Usage
|
|
860
|
-
await executeWithVaultToken('send-email', {
|
|
861
|
-
to: 'user@example.com',
|
|
862
|
-
subject: 'Hello',
|
|
863
|
-
body: 'Test'
|
|
864
|
-
});
|
|
865
|
-
```
|
|
866
|
-
|
|
867
|
-
#### Example: Multi-Tenant Application
|
|
868
|
-
|
|
869
|
-
```typescript
|
|
870
|
-
// Different token per user/tenant
|
|
871
|
-
async function sendEmailForUser(userId, mailParams) {
|
|
872
|
-
const user = await db.users.findById(userId);
|
|
873
|
-
const userToken = user.gmail_access_token; // From database
|
|
874
|
-
|
|
875
|
-
return await matimo.execute('send-email', {
|
|
876
|
-
...mailParams,
|
|
877
|
-
GMAIL_ACCESS_TOKEN: userToken // User-specific token
|
|
878
|
-
});
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
// Each user has their own token
|
|
882
|
-
await sendEmailForUser('user-1', {to, subject, body});
|
|
883
|
-
await sendEmailForUser('user-2', {to, subject, body});
|
|
884
|
-
```
|
|
885
|
-
|
|
886
|
-
#### Example: Token Refresh Handler
|
|
887
|
-
|
|
888
|
-
```typescript
|
|
889
|
-
class TokenManager {
|
|
890
|
-
private currentToken: string;
|
|
891
|
-
|
|
892
|
-
async ensureValidToken() {
|
|
893
|
-
// Check if token expired
|
|
894
|
-
if (this.isTokenExpired(this.currentToken)) {
|
|
895
|
-
// Refresh and update
|
|
896
|
-
this.currentToken = await this.refreshAccessToken();
|
|
897
|
-
process.env.GMAIL_ACCESS_TOKEN = this.currentToken;
|
|
898
|
-
}
|
|
899
|
-
return this.currentToken;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
async execute(toolName, params) {
|
|
903
|
-
const token = await this.ensureValidToken();
|
|
904
|
-
|
|
905
|
-
return await matimo.execute(toolName, {
|
|
906
|
-
...params,
|
|
907
|
-
GMAIL_ACCESS_TOKEN: token // Always fresh
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
// Usage
|
|
913
|
-
const tokenManager = new TokenManager();
|
|
914
|
-
await tokenManager.execute('send-email', {to, subject, body});
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
#### Example: OAuth Callback Handler (Phase 2 Preparation)
|
|
918
|
-
|
|
919
|
-
```typescript
|
|
920
|
-
async function handleOAuthCallback(code, userId) {
|
|
921
|
-
// Exchange code for token
|
|
922
|
-
const tokens = await oauth2.exchangeCode(code);
|
|
923
|
-
|
|
924
|
-
// Store tokens (choose one approach)
|
|
925
|
-
|
|
926
|
-
// Option A: Database
|
|
927
|
-
await db.users.update(userId, {
|
|
928
|
-
gmail_access_token: tokens.access_token,
|
|
929
|
-
gmail_refresh_token: tokens.refresh_token,
|
|
930
|
-
token_expires_at: Date.now() + tokens.expires_in * 1000
|
|
931
|
-
});
|
|
932
|
-
|
|
933
|
-
// Option B: Secure Vault (AWS Secrets Manager, 1Password, etc.)
|
|
934
|
-
await vault.setSecret(
|
|
935
|
-
`user-${userId}-gmail-token`,
|
|
936
|
-
tokens.access_token
|
|
937
|
-
);
|
|
938
|
-
|
|
939
|
-
// Later, when executing tools:
|
|
940
|
-
const token = await db.users.findById(userId).gmail_access_token;
|
|
941
|
-
// OR
|
|
942
|
-
const token = await vault.getSecret(`user-${userId}-gmail-token`);
|
|
943
|
-
|
|
944
|
-
// Pass to Matimo
|
|
945
|
-
await matimo.execute('send-email', {
|
|
946
|
-
to: 'user@example.com',
|
|
947
|
-
subject: 'Hello',
|
|
948
|
-
body: 'Test',
|
|
949
|
-
GMAIL_ACCESS_TOKEN: token // Explicit token
|
|
950
|
-
});
|
|
951
|
-
}
|
|
952
|
-
```
|
|
953
|
-
|
|
954
|
-
### Comparison: Which Approach to Use?
|
|
955
|
-
|
|
956
|
-
| Approach | Pros | Cons | Best For |
|
|
957
|
-
|----------|------|------|----------|
|
|
958
|
-
| **Explicit Parameter** | 🔒 Secure, flexible, per-request, no env vars | More verbose | Production, multi-tenant, microservices |
|
|
959
|
-
| **Runtime Environment** | ✨ Clean code, auto-injection, simple | Token in memory, app-wide | Development, single-tenant, startups |
|
|
960
|
-
| **Vault/Secrets Manager** | 🛡️ Enterprise-secure, auditable, centralized | Extra infrastructure, complexity | Enterprise apps, compliance-required |
|
|
961
|
-
| **OAuth Flow** | 🔑 User-authenticated, standards-based | Phase 2 (not yet) | Future production apps |
|
|
962
|
-
|
|
963
|
-
## Examples
|
|
964
|
-
|
|
965
|
-
### Example 1: Gmail with Factory Pattern
|
|
966
|
-
|
|
967
|
-
```typescript
|
|
968
|
-
// examples/langchain/gmail/gmail-factory.ts
|
|
969
|
-
|
|
970
|
-
import { MatimoInstance, ToolLoader } from '../../../src';
|
|
971
|
-
|
|
972
|
-
// Set up Matimo
|
|
973
|
-
const loader = new ToolLoader('./tools');
|
|
974
|
-
const tools = await loader.loadToolsFromDirectory();
|
|
975
|
-
const matimo = new MatimoInstance(tools);
|
|
976
|
-
|
|
977
|
-
// Gmail access token from environment
|
|
978
|
-
process.env.GMAIL_ACCESS_TOKEN = 'ya29.a0AXooCg...';
|
|
979
|
-
|
|
980
|
-
// Execute without passing token explicitly
|
|
981
|
-
const result = await matimo.execute('send-email', {
|
|
982
|
-
to: 'recipient@example.com',
|
|
983
|
-
subject: 'Hello from Matimo',
|
|
984
|
-
body: 'This is a test message'
|
|
985
|
-
// Token auto-injected!
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
console.log('Email sent:', result.id);
|
|
989
|
-
```
|
|
990
|
-
|
|
991
|
-
### Example 2: GitHub with Decorator Pattern
|
|
992
|
-
|
|
993
|
-
```typescript
|
|
994
|
-
// Example: Decorator auto-injects GITHUB_API_KEY
|
|
995
|
-
|
|
996
|
-
import { tool } from '../../../src';
|
|
997
|
-
|
|
998
|
-
@tool('get-repo')
|
|
999
|
-
async getGithubRepo(owner: string, repo: string) {
|
|
1000
|
-
return undefined; // Matimo intercepts
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
// Set token
|
|
1004
|
-
process.env.GITHUB_API_KEY = 'ghp_abc123...';
|
|
1005
|
-
|
|
1006
|
-
// Call - no token needed
|
|
1007
|
-
const repo = await getGithubRepo('torvalds', 'linux');
|
|
1008
|
-
console.log(repo.name); // 'linux'
|
|
1009
|
-
```
|
|
1010
|
-
|
|
1011
|
-
### Example 3: AI Agent Deciding Which Tool to Use
|
|
1012
|
-
|
|
1013
|
-
```typescript
|
|
1014
|
-
// examples/langchain/gmail/gmail-langchain.ts
|
|
1015
|
-
|
|
1016
|
-
import { MatimoInstance, ToolLoader } from '../../../src';
|
|
1017
|
-
import { ChatOpenAI } from '@langchain/openai';
|
|
1018
|
-
import { createToolsForAgent } from '@langchain/core/tools';
|
|
1019
|
-
|
|
1020
|
-
const loader = new ToolLoader('./tools');
|
|
1021
|
-
const tools = await loader.loadToolsFromDirectory();
|
|
1022
|
-
const matimo = new MatimoInstance(tools);
|
|
1023
|
-
|
|
1024
|
-
// Set access tokens
|
|
1025
|
-
process.env.GMAIL_ACCESS_TOKEN = 'ya29.a0AXooCg...';
|
|
1026
|
-
|
|
1027
|
-
// Create LangChain tools from YAML
|
|
1028
|
-
const langchainTools = createToolsForAgent(
|
|
1029
|
-
tools.filter(t => t.name.startsWith('gmail-'))
|
|
1030
|
-
);
|
|
1031
|
-
|
|
1032
|
-
// Agent decides which tool to use based on user request
|
|
1033
|
-
const agent = new OpenAIAgent({
|
|
1034
|
-
llm: new ChatOpenAI({ model: 'gpt-4' }),
|
|
1035
|
-
tools: langchainTools
|
|
1036
|
-
});
|
|
1037
|
-
|
|
1038
|
-
// User says what they want in natural language
|
|
1039
|
-
const result = await agent.invoke({
|
|
1040
|
-
messages: [{
|
|
1041
|
-
role: 'user',
|
|
1042
|
-
content: 'Send an email to alice@example.com saying hello'
|
|
1043
|
-
}]
|
|
1044
|
-
});
|
|
1045
|
-
|
|
1046
|
-
// Agent chooses 'send-email' tool, passes parameters,
|
|
1047
|
-
// Matimo injects GMAIL_ACCESS_TOKEN, email is sent!
|
|
1048
|
-
```
|
|
1049
|
-
|
|
1050
|
-
## Architecture Diagrams
|
|
1051
|
-
|
|
1052
|
-
### Token Injection System Flow
|
|
1053
|
-
|
|
1054
|
-
```
|
|
1055
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1056
|
-
│ User Code │
|
|
1057
|
-
│ process.env.GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
|
|
1058
|
-
│ await matimo.execute('send-email', {to, subject, body}) │
|
|
1059
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1060
|
-
│
|
|
1061
|
-
▼
|
|
1062
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1063
|
-
│ MatimoInstance.execute() │
|
|
1064
|
-
│ 1. Load tool from registry │
|
|
1065
|
-
│ name: 'send-email' │
|
|
1066
|
-
│ execution: │
|
|
1067
|
-
│ headers: │
|
|
1068
|
-
│ Authorization: "Bearer {GMAIL_ACCESS_TOKEN}" │
|
|
1069
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1070
|
-
│
|
|
1071
|
-
▼
|
|
1072
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1073
|
-
│ injectAuthParameters(tool, params) │
|
|
1074
|
-
│ Step 1: extractParameterPlaceholders(execution) │
|
|
1075
|
-
│ Result: ["GMAIL_ACCESS_TOKEN", ...] │
|
|
1076
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1077
|
-
│
|
|
1078
|
-
▼
|
|
1079
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1080
|
-
│ isAuthParameter(placeholder) │
|
|
1081
|
-
│ Check if contains: TOKEN, KEY, SECRET, PASSWORD, etc. │
|
|
1082
|
-
│ "GMAIL_ACCESS_TOKEN" contains "TOKEN" ✓ │
|
|
1083
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1084
|
-
│
|
|
1085
|
-
▼
|
|
1086
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1087
|
-
│ Environment Variable Lookup │
|
|
1088
|
-
│ Try: GMAIL_ACCESS_TOKEN ✓ Found! │
|
|
1089
|
-
│ Value: "ya29.a0AXooCg..." │
|
|
1090
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1091
|
-
│
|
|
1092
|
-
▼
|
|
1093
|
-
┌───────────────────────────────────────────────────────────────────┐
|
|
1094
|
-
│ Merge into Execution Parameters │
|
|
1095
|
-
│ { │
|
|
1096
|
-
│ GMAIL_ACCESS_TOKEN: "ya29.a0AXooCg...", │
|
|
1097
|
-
│ to: "user@example.com", │
|
|
1098
|
-
│ subject: "Hello", │
|
|
1099
|
-
│ body: "Test" │
|
|
1100
|
-
│ } │
|
|
1101
|
-
└───────────┬───────────────────────────────────────────────────────┘
|
|
1102
|
-
│
|
|
1103
|
-
▼
|
|
1104
|
-
┌──────────────────────────────────────────────────────────────────┐
|
|
1105
|
-
│ HttpExecutor.execute() │
|
|
1106
|
-
│ Replace {GMAIL_ACCESS_TOKEN} with actual token value │
|
|
1107
|
-
│ Headers: { │
|
|
1108
|
-
│ Authorization: "Bearer ya29.a0AXooCg..." │
|
|
1109
|
-
│ } │
|
|
1110
|
-
└───────────┬──────────────────────────────────────────────────────┘
|
|
1111
|
-
│
|
|
1112
|
-
▼
|
|
1113
|
-
┌────────────────────────────────────────────────────────────────────┐
|
|
1114
|
-
│ Send HTTP Request to Gmail API │
|
|
1115
|
-
│ POST https://gmail.googleapis.com/gmail/v1/users/me/messages/send │
|
|
1116
|
-
│ Headers: {Authorization: "Bearer ya29.a0AXooCg..."} │
|
|
1117
|
-
└───────────┬────────────────────────────────────────────────────────┘
|
|
1118
|
-
│
|
|
1119
|
-
▼
|
|
1120
|
-
┌───────────────────────────────────────────────────────────────────┐
|
|
1121
|
-
│ Return Result to User │
|
|
1122
|
-
│ { │
|
|
1123
|
-
│ id: "thread123", │
|
|
1124
|
-
│ threadId: "abc456", │
|
|
1125
|
-
│ labelIds: ["SENT"] │
|
|
1126
|
-
│ } │
|
|
1127
|
-
└───────────────────────────────────────────────────────────────────┘
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
### OAuth2 Standard Authorization Code Flow
|
|
1131
|
-
|
|
1132
|
-
```
|
|
1133
|
-
┌────────────────────┐ ┌──────────────────────┐
|
|
1134
|
-
│ User's Browser │ │ Google Auth Server │
|
|
1135
|
-
└────────┬───────────┘ └──────────┬───────────┘
|
|
1136
|
-
│ │
|
|
1137
|
-
│ 1. User clicks "Sign in with Google" │
|
|
1138
|
-
├──────────────────────────────────────────────────────────>
|
|
1139
|
-
│ GET /oauth2/auth?client_id=...&scope=... │
|
|
1140
|
-
│ │
|
|
1141
|
-
│ 2. Google shows consent │
|
|
1142
|
-
│ screen │
|
|
1143
|
-
│ <─────────────────────────────────────────────────────
|
|
1144
|
-
│ (User sees: "Allow app to send emails?") │
|
|
1145
|
-
│ │
|
|
1146
|
-
│ 3. User clicks "Allow" │
|
|
1147
|
-
│ │
|
|
1148
|
-
│ Redirect to callback with code │
|
|
1149
|
-
│ <─────────────────────────────────────────────────────
|
|
1150
|
-
│ Location: http://localhost:3000/callback?code=abc123
|
|
1151
|
-
│
|
|
1152
|
-
┌────────┴───────────┐
|
|
1153
|
-
│ Your Backend │ 4. Exchange code for token
|
|
1154
|
-
│ /callback handler │ POST https://oauth2.googleapis.com/token
|
|
1155
|
-
└────────┬───────────┘ body: {code, client_id, client_secret}
|
|
1156
|
-
│ │
|
|
1157
|
-
│ │
|
|
1158
|
-
│──────────────────────────────────────────────────────────>
|
|
1159
|
-
│ Google
|
|
1160
|
-
│ exchanges
|
|
1161
|
-
│ code
|
|
1162
|
-
│ │
|
|
1163
|
-
│ 5. Receive tokens │
|
|
1164
|
-
│ { │
|
|
1165
|
-
│ access_token: "ya29.a0AXooCg...", │
|
|
1166
|
-
│ refresh_token: "1//0gXKJV...", │
|
|
1167
|
-
│ expires_in: 3600 │
|
|
1168
|
-
│ } │
|
|
1169
|
-
│ <─────────────────────────────────────────────────────
|
|
1170
|
-
│
|
|
1171
|
-
└─ 6. Store tokens securely
|
|
1172
|
-
(database, secure vault, env var)
|
|
1173
|
-
│
|
|
1174
|
-
└─ 7. Use with Matimo
|
|
1175
|
-
process.env.GMAIL_ACCESS_TOKEN = token
|
|
1176
|
-
matimo.execute('send-email', {...})
|
|
1177
|
-
```
|
|
1178
|
-
|
|
1179
|
-
### Environment Variable Resolution
|
|
1180
|
-
|
|
1181
|
-
```
|
|
1182
|
-
Parameter Name: GMAIL_ACCESS_TOKEN
|
|
1183
|
-
|
|
1184
|
-
┌──────────────────────────────────────────────────────────┐
|
|
1185
|
-
│ Check 1: Prefixed (Recommended) │
|
|
1186
|
-
│ │
|
|
1187
|
-
│ process.env.GMAIL_ACCESS_TOKEN │
|
|
1188
|
-
│ │
|
|
1189
|
-
│ ✓ If found → Use it │
|
|
1190
|
-
│ │ │
|
|
1191
|
-
│ └─> GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
|
|
1192
|
-
│ │
|
|
1193
|
-
└──────────────────────────────────────────────────────────┘
|
|
1194
|
-
│
|
|
1195
|
-
│ NOT FOUND
|
|
1196
|
-
▼
|
|
1197
|
-
┌─────────────────────────────────────────────────────────┐
|
|
1198
|
-
│ Check 2: Direct Name (Fallback) │
|
|
1199
|
-
│ │
|
|
1200
|
-
│ process.env.GMAIL_ACCESS_TOKEN │
|
|
1201
|
-
│ │
|
|
1202
|
-
│ ✓ If found → Use it │
|
|
1203
|
-
│ │ │
|
|
1204
|
-
│ └─> GMAIL_ACCESS_TOKEN = "ya29.a0AXooCg..." │
|
|
1205
|
-
│ │
|
|
1206
|
-
└─────────────────────────────────────────────────────────┘
|
|
1207
|
-
│
|
|
1208
|
-
│ NOT FOUND
|
|
1209
|
-
▼
|
|
1210
|
-
┌─────────────────────────────────────────────────────────┐
|
|
1211
|
-
│ No Token Found │
|
|
1212
|
-
│ │
|
|
1213
|
-
│ Parameter not injected │
|
|
1214
|
-
│ Tool execution may fail if token was required │
|
|
1215
|
-
│ │
|
|
1216
|
-
│ Error: "Missing required parameter: GMAIL_ACCESS_TOKEN" │
|
|
1217
|
-
│ │
|
|
1218
|
-
└─────────────────────────────────────────────────────────┘
|
|
1219
|
-
```
|
|
1220
|
-
|
|
1221
|
-
## Quick Reference
|
|
1222
|
-
|
|
1223
|
-
### Getting Started (5 Steps)
|
|
1224
|
-
|
|
1225
|
-
1. **Obtain Token** - Via OAuth Playground or your app's auth flow
|
|
1226
|
-
2. **Set Environment** - `export GMAIL_ACCESS_TOKEN=token`
|
|
1227
|
-
3. **Load Tools** - `await loader.loadToolsFromDirectory()`
|
|
1228
|
-
4. **Execute** - `await matimo.execute('tool-name', params)`
|
|
1229
|
-
5. **Handle Errors** - Check error code and token validity
|
|
1230
|
-
|
|
1231
|
-
### Common Patterns
|
|
1232
|
-
|
|
1233
|
-
| Pattern | Use Case | Token Passing |
|
|
1234
|
-
|---------|----------|---------------|
|
|
1235
|
-
| **Factory** | Scripts, direct SDK | Auto-inject from env |
|
|
1236
|
-
| **Decorator** | Framework integration | Auto-inject from env |
|
|
1237
|
-
| **AI Agent** | LLM-driven tools | Auto-inject from env |
|
|
1238
|
-
| **Environment File** | Local development | Load from `.env` |
|
|
1239
|
-
| **Secure Vault** | Production | Retrieve at runtime |
|
|
1240
|
-
|
|
1241
|
-
### Environment Variable Names
|
|
1242
|
-
|
|
1243
|
-
**Format:** `{PROVIDER}_{TYPE}`
|
|
1244
|
-
|
|
1245
|
-
Examples:
|
|
1246
|
-
- `GMAIL_ACCESS_TOKEN`
|
|
1247
|
-
- `GITHUB_API_KEY`
|
|
1248
|
-
- `SLACK_BOT_TOKEN`
|
|
1249
|
-
|
|
1250
|
-
**Fallback:** Direct name without `` prefix
|
|
1251
|
-
|
|
1252
|
-
### Security Checklist
|
|
1253
|
-
|
|
1254
|
-
- [ ] **Storage**: Never hardcode tokens in source code
|
|
1255
|
-
- [ ] **Files**: Add `.env` to `.gitignore`
|
|
1256
|
-
- [ ] **Logging**: Never log tokens or include in error messages
|
|
1257
|
-
- [ ] **Scope**: Request minimum required permissions only
|
|
1258
|
-
- [ ] **Expiration**: Monitor token expiry and refresh periodically
|
|
1259
|
-
- [ ] **Rotation**: Rotate tokens regularly (recommend: monthly)
|
|
1260
|
-
- [ ] **Revocation**: Revoke tokens when no longer needed
|
|
1261
|
-
- [ ] **Transmission**: Always use HTTPS/TLS for requests
|
|
1262
|
-
|
|
1263
|
-
## Troubleshooting
|
|
1264
|
-
|
|
1265
|
-
### Common Issues
|
|
1266
|
-
|
|
1267
|
-
| Symptom | Cause | Solution |
|
|
1268
|
-
|---------|-------|----------|
|
|
1269
|
-
| "Missing required parameter: GMAIL_ACCESS_TOKEN" | Token env var not set | `export GMAIL_ACCESS_TOKEN=token` |
|
|
1270
|
-
| "401 Unauthorized" | Invalid or expired token | Refresh token or re-authenticate |
|
|
1271
|
-
| "403 Forbidden" | Insufficient scopes | Check token has required permissions |
|
|
1272
|
-
| "400 Bad Request" | Malformed request | Verify parameter encoding and URL |
|
|
1273
|
-
| "Invalid grant" | Token not recognized | Token revoked or never issued |
|
|
1274
|
-
| "Token expired" | Access token lifetime exceeded | Refresh token (Phase 2 feature) |
|
|
1275
|
-
| Tool not found | Tool YAML doesn't exist | Verify `tools/{provider}/{tool}.yaml` |
|
|
1276
|
-
| Parameter mismatch | User param doesn't match schema | Check tool's parameter definitions |
|
|
1277
|
-
|
|
1278
|
-
### Debug Steps
|
|
1279
|
-
|
|
1280
|
-
```typescript
|
|
1281
|
-
// 1. Check env var is set
|
|
1282
|
-
console.log(process.env.GMAIL_ACCESS_TOKEN);
|
|
1283
|
-
|
|
1284
|
-
// 2. Check parameter name contains TOKEN/KEY/SECRET
|
|
1285
|
-
const tool = tools.find(t => t.name === 'send-email');
|
|
1286
|
-
console.log(tool.execution);
|
|
1287
|
-
|
|
1288
|
-
// 3. Verify token format and expiration
|
|
1289
|
-
// Access tokens typically valid for 1 hour
|
|
1290
|
-
|
|
1291
|
-
// 4. Test with explicit token override
|
|
1292
|
-
await matimo.execute('send-email', {
|
|
1293
|
-
to: 'user@example.com',
|
|
1294
|
-
subject: 'Test',
|
|
1295
|
-
body: 'Test',
|
|
1296
|
-
GMAIL_ACCESS_TOKEN: 'explicit-token' // Bypass env lookup
|
|
1297
|
-
});
|
|
1298
|
-
|
|
1299
|
-
// 5. Check token has required scopes
|
|
1300
|
-
// Different tools need different scopes
|
|
1301
|
-
```
|
|
1302
|
-
|
|
1303
|
-
### Token Expiration & Refresh
|
|
1304
|
-
|
|
1305
|
-
```typescript
|
|
1306
|
-
// Token expires after ~1 hour
|
|
1307
|
-
// Options until Phase 2 auto-refresh:
|
|
1308
|
-
|
|
1309
|
-
// Option 1: Refresh using OAuth library
|
|
1310
|
-
const newToken = await oauth2.refreshToken(refreshToken);
|
|
1311
|
-
process.env.GMAIL_ACCESS_TOKEN = newToken;
|
|
1312
|
-
|
|
1313
|
-
// Option 2: Re-authenticate at OAuth Playground
|
|
1314
|
-
// Visit: https://developers.google.com/oauthplayground
|
|
1315
|
-
// Copy fresh token to env var
|
|
1316
|
-
|
|
1317
|
-
// Option 3: Implement token refresh logic in your code
|
|
1318
|
-
async function ensureValidToken() {
|
|
1319
|
-
const token = process.env.GMAIL_ACCESS_TOKEN;
|
|
1320
|
-
if (isExpired(token)) {
|
|
1321
|
-
const newToken = await refreshToken();
|
|
1322
|
-
process.env.GMAIL_ACCESS_TOKEN = newToken;
|
|
1323
|
-
}
|
|
1324
|
-
return token;
|
|
1325
|
-
}
|
|
1326
|
-
```
|
|
1327
|
-
|
|
1328
|
-
## Adding New Providers
|
|
1329
|
-
|
|
1330
|
-
To add support for a new provider (GitHub, Slack, etc.):
|
|
1331
|
-
|
|
1332
|
-
1. **Create Provider Config** - `tools/{provider}/definition.yaml`
|
|
1333
|
-
```yaml
|
|
1334
|
-
provider:
|
|
1335
|
-
name: github
|
|
1336
|
-
oauth2:
|
|
1337
|
-
auth_url: https://github.com/login/oauth/authorize
|
|
1338
|
-
token_url: https://github.com/login/oauth/access_token
|
|
1339
|
-
scopes:
|
|
1340
|
-
- repo
|
|
1341
|
-
- admin:user
|
|
1342
|
-
```
|
|
1343
|
-
|
|
1344
|
-
2. **Create Tool Definitions** - `tools/{provider}/{tool}.yaml`
|
|
1345
|
-
```yaml
|
|
1346
|
-
authentication:
|
|
1347
|
-
type: oauth2
|
|
1348
|
-
provider: github
|
|
1349
|
-
required_scopes: [repo]
|
|
1350
|
-
execution:
|
|
1351
|
-
headers:
|
|
1352
|
-
Authorization: "Bearer {GITHUB_API_KEY}"
|
|
1353
|
-
```
|
|
1354
|
-
|
|
1355
|
-
3. **Set Environment Variable** - `export GITHUB_API_KEY=token`
|
|
1356
|
-
|
|
1357
|
-
4. **Load & Execute** - No code changes needed!
|
|
1358
|
-
```typescript
|
|
1359
|
-
const result = await matimo.execute('get-repo', {...});
|
|
1360
|
-
```
|
|
1361
|
-
|
|
1362
|
-
---
|
|
1363
|
-
|
|
1364
|
-
**Last Updated:** February 2, 2026
|
|
1365
|
-
**Matimo Phase:** 1 (OAuth2 provider config and token injection)
|
|
1366
|
-
**Next Phase:** Phase 2 - Automatic token refresh, secure storage, built-in OAuth flows
|