@iflow-mcp/dynamicendpoints-etsy-mcp 1.2.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.
- package/.env.example +9 -0
- package/.github/copilot-instructions.md +16 -0
- package/.smithery/index.cjs +1352 -0
- package/DEPLOYMENT_CHECKLIST.md +206 -0
- package/OAUTH_SETUP.md +275 -0
- package/PROMPTS_AND_RESOURCES.md +353 -0
- package/QUICK_REFERENCE.md +186 -0
- package/README.md +677 -0
- package/SMITHERY_DEPLOYMENT.md +276 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +2459 -0
- package/icon.svg +54 -0
- package/language.json +1 -0
- package/package.json +1 -0
- package/package_name +1 -0
- package/push_info.json +5 -0
- package/smithery.yaml +1 -0
- package/src/index.ts +2667 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Smithery Deployment Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist to verify your Etsy MCP server is ready for Smithery deployment.
|
|
4
|
+
|
|
5
|
+
## ✅ Required Files
|
|
6
|
+
|
|
7
|
+
- [x] `smithery.yaml` - Runtime configuration
|
|
8
|
+
- [x] `package.json` - With `module` field pointing to `src/index.ts`
|
|
9
|
+
- [x] `src/index.ts` - Exports default `createServer` function
|
|
10
|
+
- [x] `tsconfig.json` - TypeScript configuration
|
|
11
|
+
- [x] `.gitignore` - Excludes node_modules and build artifacts
|
|
12
|
+
|
|
13
|
+
## ✅ Code Structure
|
|
14
|
+
|
|
15
|
+
- [x] Default export: `createServer` function
|
|
16
|
+
- [x] Configuration schema: `configSchema` exported with Zod
|
|
17
|
+
- [x] Returns MCP Server object from `createServer`
|
|
18
|
+
- [x] Stdio support: CLI entry point for local execution
|
|
19
|
+
- [x] Config support: Accepts config from Smithery or environment
|
|
20
|
+
|
|
21
|
+
## ✅ Dependencies
|
|
22
|
+
|
|
23
|
+
- [x] `@modelcontextprotocol/sdk` in dependencies
|
|
24
|
+
- [x] `axios` for HTTP requests
|
|
25
|
+
- [x] `zod` for schema validation
|
|
26
|
+
- [x] `@smithery/cli` in devDependencies
|
|
27
|
+
- [x] TypeScript types installed
|
|
28
|
+
|
|
29
|
+
## ✅ Scripts
|
|
30
|
+
|
|
31
|
+
- [x] `npm run build` - Uses Smithery CLI
|
|
32
|
+
- [x] `npm run dev` - Opens interactive playground
|
|
33
|
+
- [x] `npm run compile` - TypeScript compilation (for testing)
|
|
34
|
+
- [x] `npm start` - Runs compiled server
|
|
35
|
+
|
|
36
|
+
## ✅ Testing
|
|
37
|
+
|
|
38
|
+
### Local Testing
|
|
39
|
+
```bash
|
|
40
|
+
# Install dependencies
|
|
41
|
+
npm install
|
|
42
|
+
|
|
43
|
+
# Test compilation
|
|
44
|
+
npm run compile
|
|
45
|
+
|
|
46
|
+
# Test with Smithery playground
|
|
47
|
+
npm run dev
|
|
48
|
+
|
|
49
|
+
# Test direct execution
|
|
50
|
+
ETSY_API_KEY=your_key npm start
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Verify These Work:
|
|
54
|
+
- [ ] Server starts without errors
|
|
55
|
+
- [ ] All 19 tools are listed
|
|
56
|
+
- [ ] Configuration schema shows 3 fields
|
|
57
|
+
- [ ] Tools execute and return responses
|
|
58
|
+
|
|
59
|
+
## ✅ Configuration Schema
|
|
60
|
+
|
|
61
|
+
The exported `configSchema` includes:
|
|
62
|
+
- [x] `apiKey` (string, required) - With description
|
|
63
|
+
- [x] `shopId` (string, optional) - With description
|
|
64
|
+
- [x] `accessToken` (string, optional) - With description
|
|
65
|
+
|
|
66
|
+
## ✅ Tools Exported
|
|
67
|
+
|
|
68
|
+
### Read-Only (10 tools)
|
|
69
|
+
- [x] search_listings
|
|
70
|
+
- [x] get_listing
|
|
71
|
+
- [x] get_shop
|
|
72
|
+
- [x] get_shop_listings
|
|
73
|
+
- [x] search_shops
|
|
74
|
+
- [x] get_listing_inventory
|
|
75
|
+
- [x] get_listing_images
|
|
76
|
+
- [x] get_shop_sections
|
|
77
|
+
- [x] get_trending_listings
|
|
78
|
+
- [x] find_shops
|
|
79
|
+
|
|
80
|
+
### Shop Management (9 tools)
|
|
81
|
+
- [x] create_listing
|
|
82
|
+
- [x] update_listing
|
|
83
|
+
- [x] delete_listing
|
|
84
|
+
- [x] update_listing_inventory
|
|
85
|
+
- [x] upload_listing_image
|
|
86
|
+
- [x] create_shop_section
|
|
87
|
+
- [x] update_shop_section
|
|
88
|
+
- [x] delete_shop_section
|
|
89
|
+
- [x] update_shop
|
|
90
|
+
|
|
91
|
+
## ✅ Documentation
|
|
92
|
+
|
|
93
|
+
- [x] README.md - Main documentation
|
|
94
|
+
- [x] SMITHERY_DEPLOYMENT.md - Deployment guide
|
|
95
|
+
- [x] OAUTH_SETUP.md - OAuth setup instructions
|
|
96
|
+
- [x] QUICK_REFERENCE.md - Quick reference guide
|
|
97
|
+
- [x] .env.example - Environment template
|
|
98
|
+
|
|
99
|
+
## ✅ GitHub Repository
|
|
100
|
+
|
|
101
|
+
Before deploying:
|
|
102
|
+
- [ ] Push all files to GitHub
|
|
103
|
+
- [ ] Repository is public (or accessible to Smithery)
|
|
104
|
+
- [ ] All commits are up to date
|
|
105
|
+
- [ ] .gitignore excludes sensitive files
|
|
106
|
+
|
|
107
|
+
## 🚀 Deployment Steps
|
|
108
|
+
|
|
109
|
+
1. **Push to GitHub**
|
|
110
|
+
```bash
|
|
111
|
+
git add .
|
|
112
|
+
git commit -m "Ready for Smithery deployment"
|
|
113
|
+
git push origin main
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
2. **Connect to Smithery**
|
|
117
|
+
- Go to https://smithery.ai/new
|
|
118
|
+
- Connect your GitHub account
|
|
119
|
+
- Select the `etsy_mcp` repository
|
|
120
|
+
|
|
121
|
+
3. **Configure Server**
|
|
122
|
+
- Name: Etsy MCP Server
|
|
123
|
+
- Description: MCP server for Etsy API integration
|
|
124
|
+
- Category: E-commerce / API Integration
|
|
125
|
+
|
|
126
|
+
4. **Deploy**
|
|
127
|
+
- Click "Deploy" button
|
|
128
|
+
- Wait for build to complete
|
|
129
|
+
- Test deployed server
|
|
130
|
+
|
|
131
|
+
## ✅ Post-Deployment Verification
|
|
132
|
+
|
|
133
|
+
After deployment, verify:
|
|
134
|
+
- [ ] Server shows as "Running" in Smithery dashboard
|
|
135
|
+
- [ ] All 19 tools are discoverable
|
|
136
|
+
- [ ] Configuration form displays correctly
|
|
137
|
+
- [ ] Test tools work with valid API key
|
|
138
|
+
- [ ] Error messages are clear and helpful
|
|
139
|
+
|
|
140
|
+
## 🧪 Testing Deployed Server
|
|
141
|
+
|
|
142
|
+
### With Claude Desktop
|
|
143
|
+
Add to `claude_desktop_config.json`:
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"mcpServers": {
|
|
147
|
+
"etsy": {
|
|
148
|
+
"url": "https://server.smithery.ai/YOUR-USERNAME/etsy-mcp-server/mcp",
|
|
149
|
+
"config": {
|
|
150
|
+
"apiKey": "your_etsy_api_key"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### With MCP Inspector
|
|
158
|
+
```bash
|
|
159
|
+
npx @modelcontextprotocol/inspector https://server.smithery.ai/YOUR-USERNAME/etsy-mcp-server/mcp
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Test These Operations:
|
|
163
|
+
- [ ] Search for listings works
|
|
164
|
+
- [ ] Get listing details works
|
|
165
|
+
- [ ] Get shop information works
|
|
166
|
+
- [ ] Error handling for invalid API key
|
|
167
|
+
- [ ] Error handling for missing resources
|
|
168
|
+
|
|
169
|
+
## 📊 Monitoring
|
|
170
|
+
|
|
171
|
+
After deployment, check:
|
|
172
|
+
- [ ] View usage metrics in Smithery dashboard
|
|
173
|
+
- [ ] Monitor error logs for issues
|
|
174
|
+
- [ ] Check performance data
|
|
175
|
+
- [ ] Review user feedback
|
|
176
|
+
|
|
177
|
+
## 🔧 Troubleshooting
|
|
178
|
+
|
|
179
|
+
If deployment fails:
|
|
180
|
+
|
|
181
|
+
1. **Check build logs** in Smithery dashboard
|
|
182
|
+
2. **Verify locally** with `npm run build`
|
|
183
|
+
3. **Test compilation** with `npm run compile`
|
|
184
|
+
4. **Review errors** and fix TypeScript issues
|
|
185
|
+
5. **Check dependencies** in package.json
|
|
186
|
+
6. **Validate structure** matches Smithery requirements
|
|
187
|
+
|
|
188
|
+
## ✅ Success Criteria
|
|
189
|
+
|
|
190
|
+
Your deployment is successful when:
|
|
191
|
+
- ✅ Build completes without errors
|
|
192
|
+
- ✅ Server shows as "Running"
|
|
193
|
+
- ✅ All tools are listed
|
|
194
|
+
- ✅ Configuration form works
|
|
195
|
+
- ✅ Test queries return results
|
|
196
|
+
- ✅ Error messages are clear
|
|
197
|
+
|
|
198
|
+
## 🎉 You're Ready!
|
|
199
|
+
|
|
200
|
+
Once all items are checked, your Etsy MCP server is:
|
|
201
|
+
- ✅ **Smithery-compatible**
|
|
202
|
+
- ✅ **Production-ready**
|
|
203
|
+
- ✅ **Fully documented**
|
|
204
|
+
- ✅ **Ready to deploy**
|
|
205
|
+
|
|
206
|
+
Click that Deploy button! 🚀
|
package/OAUTH_SETUP.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Etsy OAuth Setup Guide
|
|
2
|
+
|
|
3
|
+
This guide will help you set up OAuth 2.0 authentication to enable shop management features in the Etsy MCP server.
|
|
4
|
+
|
|
5
|
+
## Why OAuth?
|
|
6
|
+
|
|
7
|
+
While the Etsy API key allows you to **read** public data (search listings, view shops), you need an **OAuth access token** to:
|
|
8
|
+
- Create new listings
|
|
9
|
+
- Update or delete your listings
|
|
10
|
+
- Manage shop sections
|
|
11
|
+
- Update shop information
|
|
12
|
+
- Manage inventory
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
1. An Etsy account with a shop
|
|
17
|
+
2. An Etsy developer account ([sign up here](https://www.etsy.com/developers/register))
|
|
18
|
+
3. A registered app in the Etsy Developer Portal
|
|
19
|
+
|
|
20
|
+
## Step-by-Step OAuth Setup
|
|
21
|
+
|
|
22
|
+
### Step 1: Create an Etsy App
|
|
23
|
+
|
|
24
|
+
1. Go to [Etsy Developer Portal](https://www.etsy.com/developers/your-apps)
|
|
25
|
+
2. Click **"Create a New App"**
|
|
26
|
+
3. Fill in the required information:
|
|
27
|
+
- **App Name**: Your MCP Server name
|
|
28
|
+
- **Is this app for production?**: Choose based on your needs
|
|
29
|
+
- **Tell us about your app**: Brief description
|
|
30
|
+
4. Click **"Read Terms and Create App"**
|
|
31
|
+
|
|
32
|
+
### Step 2: Configure OAuth Settings
|
|
33
|
+
|
|
34
|
+
1. In your app dashboard, go to **"API Keys & Access Tokens"**
|
|
35
|
+
2. Note your **Keystring** (this is your `ETSY_API_KEY`)
|
|
36
|
+
3. Under **OAuth Settings**, add a redirect URI:
|
|
37
|
+
- For local testing: `http://localhost:3000/callback`
|
|
38
|
+
- For production: Your production callback URL
|
|
39
|
+
4. Save the settings
|
|
40
|
+
|
|
41
|
+
### Step 3: Request Authorization
|
|
42
|
+
|
|
43
|
+
Build an authorization URL with the following format:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
https://www.etsy.com/oauth/connect?response_type=code&redirect_uri=YOUR_REDIRECT_URI&scope=listings_w%20shops_w%20shops_r%20listings_r&client_id=YOUR_KEYSTRING&state=YOUR_RANDOM_STATE&code_challenge=YOUR_CODE_CHALLENGE&code_challenge_method=S256
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Required Parameters:**
|
|
50
|
+
- `response_type`: Always `code`
|
|
51
|
+
- `redirect_uri`: Must match your registered URI (URL encoded)
|
|
52
|
+
- `scope`: Space-separated permissions (URL encoded):
|
|
53
|
+
- `listings_r` - Read listings
|
|
54
|
+
- `listings_w` - Write/manage listings
|
|
55
|
+
- `shops_r` - Read shop info
|
|
56
|
+
- `shops_w` - Update shop info
|
|
57
|
+
- `transactions_r` - Read orders
|
|
58
|
+
- `transactions_w` - Update orders
|
|
59
|
+
- `client_id`: Your app's Keystring
|
|
60
|
+
- `state`: Random string for security
|
|
61
|
+
- `code_challenge`: PKCE challenge (base64url encoded SHA256 hash)
|
|
62
|
+
- `code_challenge_method`: Always `S256`
|
|
63
|
+
|
|
64
|
+
### Step 4: Generate PKCE Code Verifier and Challenge
|
|
65
|
+
|
|
66
|
+
PKCE (Proof Key for Code Exchange) is required for security. Here's a Node.js example:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
const crypto = require('crypto');
|
|
70
|
+
|
|
71
|
+
// Generate code verifier
|
|
72
|
+
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
73
|
+
|
|
74
|
+
// Generate code challenge
|
|
75
|
+
const codeChallenge = crypto
|
|
76
|
+
.createHash('sha256')
|
|
77
|
+
.update(codeVerifier)
|
|
78
|
+
.digest('base64url');
|
|
79
|
+
|
|
80
|
+
console.log('Code Verifier:', codeVerifier);
|
|
81
|
+
console.log('Code Challenge:', codeChallenge);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Save the code verifier** - you'll need it in the next step!
|
|
85
|
+
|
|
86
|
+
### Step 5: User Authorization
|
|
87
|
+
|
|
88
|
+
1. Open the authorization URL in a browser
|
|
89
|
+
2. Log in to Etsy (if not already logged in)
|
|
90
|
+
3. Review the permissions your app is requesting
|
|
91
|
+
4. Click **"Allow Access"**
|
|
92
|
+
5. You'll be redirected to your callback URL with a `code` parameter:
|
|
93
|
+
```
|
|
94
|
+
http://localhost:3000/callback?code=AUTHORIZATION_CODE&state=YOUR_STATE
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 6: Exchange Code for Access Token
|
|
98
|
+
|
|
99
|
+
Make a POST request to exchange the authorization code for an access token:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
curl -X POST "https://api.etsy.com/v3/public/oauth/token" \
|
|
103
|
+
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
104
|
+
-d "grant_type=authorization_code" \
|
|
105
|
+
-d "client_id=YOUR_KEYSTRING" \
|
|
106
|
+
-d "redirect_uri=YOUR_REDIRECT_URI" \
|
|
107
|
+
-d "code=AUTHORIZATION_CODE" \
|
|
108
|
+
-d "code_verifier=YOUR_CODE_VERIFIER"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Node.js Example:**
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
const axios = require('axios');
|
|
115
|
+
|
|
116
|
+
const data = new URLSearchParams({
|
|
117
|
+
grant_type: 'authorization_code',
|
|
118
|
+
client_id: 'YOUR_KEYSTRING',
|
|
119
|
+
redirect_uri: 'http://localhost:3000/callback',
|
|
120
|
+
code: 'AUTHORIZATION_CODE_FROM_CALLBACK',
|
|
121
|
+
code_verifier: 'YOUR_CODE_VERIFIER_FROM_STEP_4'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
axios.post('https://api.etsy.com/v3/public/oauth/token', data, {
|
|
125
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
126
|
+
})
|
|
127
|
+
.then(response => {
|
|
128
|
+
console.log('Access Token:', response.data.access_token);
|
|
129
|
+
console.log('Refresh Token:', response.data.refresh_token);
|
|
130
|
+
console.log('Expires In:', response.data.expires_in, 'seconds');
|
|
131
|
+
})
|
|
132
|
+
.catch(error => {
|
|
133
|
+
console.error('Error:', error.response?.data || error.message);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Response:**
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"access_token": "YOUR_ACCESS_TOKEN",
|
|
141
|
+
"token_type": "Bearer",
|
|
142
|
+
"expires_in": 3600,
|
|
143
|
+
"refresh_token": "YOUR_REFRESH_TOKEN"
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Step 7: Add Token to Environment
|
|
148
|
+
|
|
149
|
+
Add the access token to your `.env` file:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
ETSY_API_KEY=your_keystring_here
|
|
153
|
+
ETSY_SHOP_ID=your_shop_id
|
|
154
|
+
ETSY_ACCESS_TOKEN=your_access_token_here
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Or add it to your Claude Desktop config:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"mcpServers": {
|
|
162
|
+
"etsy": {
|
|
163
|
+
"command": "node",
|
|
164
|
+
"args": ["C:\\path\\to\\etsy_mcp\\build\\index.js"],
|
|
165
|
+
"env": {
|
|
166
|
+
"ETSY_API_KEY": "your_keystring",
|
|
167
|
+
"ETSY_ACCESS_TOKEN": "your_access_token"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Token Refresh
|
|
175
|
+
|
|
176
|
+
Access tokens expire after 1 hour. Use the refresh token to get a new access token:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
curl -X POST "https://api.etsy.com/v3/public/oauth/token" \
|
|
180
|
+
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
181
|
+
-d "grant_type=refresh_token" \
|
|
182
|
+
-d "client_id=YOUR_KEYSTRING" \
|
|
183
|
+
-d "refresh_token=YOUR_REFRESH_TOKEN"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Quick Test Script
|
|
187
|
+
|
|
188
|
+
Save this as `oauth-helper.js`:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const crypto = require('crypto');
|
|
192
|
+
const readline = require('readline');
|
|
193
|
+
|
|
194
|
+
const rl = readline.createInterface({
|
|
195
|
+
input: process.stdin,
|
|
196
|
+
output: process.stdout
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const CLIENT_ID = 'YOUR_KEYSTRING_HERE';
|
|
200
|
+
const REDIRECT_URI = 'http://localhost:3000/callback';
|
|
201
|
+
const STATE = crypto.randomBytes(16).toString('hex');
|
|
202
|
+
const CODE_VERIFIER = crypto.randomBytes(32).toString('base64url');
|
|
203
|
+
const CODE_CHALLENGE = crypto.createHash('sha256').update(CODE_VERIFIER).digest('base64url');
|
|
204
|
+
|
|
205
|
+
const scopes = 'listings_r listings_w shops_r shops_w';
|
|
206
|
+
const authUrl = `https://www.etsy.com/oauth/connect?response_type=code&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&scope=${encodeURIComponent(scopes)}&client_id=${CLIENT_ID}&state=${STATE}&code_challenge=${CODE_CHALLENGE}&code_challenge_method=S256`;
|
|
207
|
+
|
|
208
|
+
console.log('\n=== Etsy OAuth Helper ===\n');
|
|
209
|
+
console.log('1. Open this URL in your browser:\n');
|
|
210
|
+
console.log(authUrl);
|
|
211
|
+
console.log('\n2. After authorization, copy the "code" parameter from the redirect URL\n');
|
|
212
|
+
|
|
213
|
+
rl.question('Enter the authorization code: ', async (code) => {
|
|
214
|
+
const axios = require('axios');
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const data = new URLSearchParams({
|
|
218
|
+
grant_type: 'authorization_code',
|
|
219
|
+
client_id: CLIENT_ID,
|
|
220
|
+
redirect_uri: REDIRECT_URI,
|
|
221
|
+
code: code.trim(),
|
|
222
|
+
code_verifier: CODE_VERIFIER
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const response = await axios.post('https://api.etsy.com/v3/public/oauth/token', data, {
|
|
226
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
console.log('\n✅ Success! Add these to your .env file:\n');
|
|
230
|
+
console.log(`ETSY_ACCESS_TOKEN=${response.data.access_token}`);
|
|
231
|
+
console.log(`ETSY_REFRESH_TOKEN=${response.data.refresh_token}`);
|
|
232
|
+
console.log(`\nToken expires in: ${response.data.expires_in} seconds`);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error('\n❌ Error:', error.response?.data || error.message);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
rl.close();
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Run it with:
|
|
242
|
+
```bash
|
|
243
|
+
npm install axios
|
|
244
|
+
node oauth-helper.js
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Troubleshooting
|
|
248
|
+
|
|
249
|
+
### "Invalid redirect_uri"
|
|
250
|
+
Make sure the redirect URI in your request exactly matches the one registered in your app settings.
|
|
251
|
+
|
|
252
|
+
### "Invalid code_verifier"
|
|
253
|
+
Ensure you're using the same code_verifier that was used to generate the code_challenge.
|
|
254
|
+
|
|
255
|
+
### "Token expired"
|
|
256
|
+
Access tokens expire after 1 hour. Use the refresh token to get a new one.
|
|
257
|
+
|
|
258
|
+
### "Insufficient scope"
|
|
259
|
+
Request the appropriate scopes during authorization:
|
|
260
|
+
- `listings_w` for creating/updating listings
|
|
261
|
+
- `shops_w` for updating shop info
|
|
262
|
+
|
|
263
|
+
## Security Best Practices
|
|
264
|
+
|
|
265
|
+
1. **Never commit tokens** to version control - use `.env` files
|
|
266
|
+
2. **Store refresh tokens securely** - they don't expire
|
|
267
|
+
3. **Use PKCE** - always include code_challenge
|
|
268
|
+
4. **Validate state parameter** - prevents CSRF attacks
|
|
269
|
+
5. **Use HTTPS in production** - HTTP is only for local testing
|
|
270
|
+
|
|
271
|
+
## Resources
|
|
272
|
+
|
|
273
|
+
- [Etsy OAuth Documentation](https://developers.etsy.com/documentation/essentials/authentication/)
|
|
274
|
+
- [Etsy API Reference](https://developers.etsy.com/documentation/reference)
|
|
275
|
+
- [OAuth 2.0 PKCE Specification](https://tools.ietf.org/html/rfc7636)
|