Package Exports
- opencode-qwen-auth
Readme
OpenCode Qwen Auth Plugin
Qwen OAuth authentication plugin for OpenCode with multi-account rotation, proactive token refresh, and automatic API translation.
Features
- Device Flow OAuth - PKCE-secured authentication, works in headless/CI environments
- Multi-Account Support - Store and rotate between multiple Qwen accounts
- Proactive Token Refresh - Automatically refresh tokens before expiry
- Rate Limit Handling - Detects 429 responses, rotates accounts, respects retry-after
- API Translation - Bridges OpenAI Responses API ↔ Chat Completions API
- Streaming Support - Full SSE transformation for real-time responses
Installation
# Using Bun (recommended)
bun add opencode-qwen-auth
# Using npm
npm install opencode-qwen-authAdd to your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-qwen-auth"],
"provider": {
"qwen": {
"npm": "@ai-sdk/openai",
"options": {
"baseURL": "https://portal.qwen.ai/v1",
"compatibility": "strict"
},
"models": {
"qwen3-coder-plus": { "contextWindow": 1048576 },
"qwen3-vl-plus": { "contextWindow": 262144, "attachment": true }
}
}
}
}Quick Start
Start OpenCode in your project directory:
opencode
Authenticate with Qwen:
/authSelect Qwen OAuth and follow the device flow instructions.
Start coding with Qwen models:
/model qwen/qwen3-coder-plus
Configuration
Create .opencode/qwen.json in your project or ~/.config/opencode/qwen.json for user-level config:
{
"base_url": "https://portal.qwen.ai/v1",
"client_id": "f0304373b74a44d2b584a3fb70ca9e56",
"oauth_base_url": "https://chat.qwen.ai",
"rotation_strategy": "round-robin",
"proactive_refresh": true,
"refresh_window_seconds": 300,
"max_rate_limit_wait_seconds": 300,
"quiet_mode": false
}Configuration Options
| Option | Default | Description |
|---|---|---|
base_url |
https://portal.qwen.ai/v1 |
API endpoint for Qwen requests |
client_id |
(built-in) | OAuth client ID |
oauth_base_url |
https://chat.qwen.ai |
OAuth server URL |
rotation_strategy |
round-robin |
Account rotation: round-robin or sequential |
proactive_refresh |
true |
Refresh tokens before expiry |
refresh_window_seconds |
300 |
Seconds before expiry to trigger refresh |
max_rate_limit_wait_seconds |
300 |
Maximum wait time when rate limited |
quiet_mode |
false |
Suppress informational messages |
Environment Variables
All options can be overridden via environment variables:
QWEN_API_BASE_URLQWEN_OAUTH_CLIENT_IDQWEN_OAUTH_BASE_URLQWEN_ROTATION_STRATEGYQWEN_PROACTIVE_REFRESHQWEN_REFRESH_WINDOW_SECONDSQWEN_MAX_RATE_LIMIT_WAIT_SECONDSQWEN_QUIET_MODE
Models
Available via OAuth
| Model | Context Window | Features |
|---|---|---|
qwen3-coder-plus |
1M tokens | Optimized for coding tasks |
qwen3-vl-plus |
256K tokens | Vision + language multimodal |
Multi-Account Rotation
Add multiple accounts for higher throughput:
- Run
/authand complete the first login - Run
/authagain to add additional accounts - The plugin automatically rotates between accounts
Rotation Strategies
- round-robin: Cycles through accounts on each request
- sequential: Uses one account until rate limited, then switches
How It Works
This plugin bridges OpenCode's Responses API format with Qwen's Chat Completions API:
OpenCode → [Responses API] → Plugin → [Chat Completions] → Qwen
↓
OpenCode ← [Responses API] ← Plugin ← [Chat Completions] ← QwenRequest Transformation
| Responses API | Chat Completions API |
|---|---|
input |
messages |
input_text |
text content type |
input_image |
image_url content type |
instructions |
System message |
max_output_tokens |
max_tokens |
Response Transformation (Streaming)
Converts SSE events from Chat Completions to Responses API format:
response.createdresponse.output_item.addedresponse.content_part.addedresponse.output_text.deltaresponse.completed
Storage Locations
| Data | Location |
|---|---|
| User config | ~/.config/opencode/qwen.json |
| Project config | .opencode/qwen.json |
| Account tokens | ~/.config/opencode/qwen-auth-accounts.json |
Security Note: Tokens are stored with restricted permissions (0600). Ensure appropriate filesystem security.
Troubleshooting
Authentication Issues
"invalid_grant" error
- Your refresh token has expired. Run
/authto re-authenticate.
Device code expired
- Complete the browser login within 5 minutes of starting
/auth.
Rate Limiting
Frequent 429 errors
- Add more accounts with
/auth - Increase
max_rate_limit_wait_secondsin config
Reset Plugin State
To start fresh, delete the accounts file:
rm ~/.config/opencode/qwen-auth-accounts.jsonDevelopment
This project uses Bun for development.
Prerequisites
- Bun 1.0+ (recommended)
- Node.js 20+ (for npm compatibility)
Getting Started
# Install dependencies
bun install
# Build
bun run build
# Run tests
bun test
# Run tests in watch mode
bun test --watch
# Run e2e test (requires authenticated Qwen account)
bun run test:e2e
# Link for local testing
bun linkUsing npm
The project also works with npm:
npm install
npm run build
npm testKnown Limitations
- Audio input (
input_audio) is not supported by Qwen and is converted to placeholder text
License
Apache-2.0