Skip to content

Fix Qwen Portal OAuth - Currently Broken (Manual Token Flow, Not Real OAuth) #675

@fakhriaunur

Description

@fakhriaunur

Description

Description

The qwen-portal provider in /packages/ai/src/utils/oauth/qwen-portal.ts is not actually implementing OAuth. Despite being classified as an OAuth provider, it uses a manual token copy-paste flow rather than proper OAuth 2.0 Device Code Flow.

Current implementation is functionally:

// BAD: Just asks user to manually paste token
const token = await options.onPrompt({
  message: "Paste your Qwen OAuth token or API key",
  placeholder: "sk-...",
});

This is not OAuth - it's a manual API key flow falsely labeled as OAuth. The provider:

  • Has no OAuth 2.0 authorization code exchange
  • Has no PKCE implementation
  • Has no token refresh mechanism
  • Is treated as a static API key in refreshOAuthToken() (line 411 in index.ts)

Steps to Reproduce

  1. Run omp auth login qwen-portal
  2. Observe the prompt: "Paste your Qwen OAuth token or API key"
  3. Note that there's no device code flow, no browser opening with verification code
  4. Compare with working OAuth providers like github-copilot or openai-codex which open browser and use device code flow

Expected Behavior

  • Browser opens to https://chat.qwen.ai/api/v1/oauth2/device/code
  • User sees device code and verification URL
  • After authorization, tokens are automatically exchanged
  • Refresh tokens are properly supported

Working reference: OmniRoute implementation at https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/qwen.ts

Endpoints:

  • Device code URL: https://chat.qwen.ai/api/v1/oauth2/device/code
  • Token URL: https://chat.qwen.ai/api/v1/oauth2/token
  • Scope: openid profile email model.completion
  • Method: OAuth 2.0 Device Authorization Grant (RFC 8628)

Error Output

Platform

Windows (WSL)

omp version

14.0.3

Bun version

1.3.11

Provider

None

Area

Authentication / Login

Additional context

Reference Implementation:

Working implementation pattern from OmniRoute:

// 1. Request device code
const response = await fetch(deviceCodeUrl, {
  method: "POST",
  body: new URLSearchParams({
    client_id: config.clientId,
    scope: config.scope,
    code_challenge: codeChallenge,
    code_challenge_method: "S256",
  }),
});

// 2. Poll for token
const tokenResponse = await fetch(tokenUrl, {
  method: "POST",
  body: new URLSearchParams({
    grant_type: "urn:ietf:params:oauth:grant-type:device_code",
    device_code: deviceCode,
    code_verifier: codeVerifier,
  }),
});

// 3. Returns proper OAuth credentials
return {
  accessToken: tokens.access_token,
  refreshToken: tokens.refresh_token,
  expiresIn: tokens.expires_in,
  idToken: tokens.id_token,
  email, // from JWT decode
};

Impact:

  • Users expect OAuth capabilities (token refresh, revocation)
  • Security: Device code flow is CLI standard (GitHub, etc.)
  • UX: Manual copy-paste breaks OAuth workflows
  • Classification mismatch causes confusion

Acceptance Criteria

  • New provider qwen-code created (not modifying existing qwen-portal)
  • User can authenticate via device code flow (browser opens, user enters code)
  • Access token, refresh token, and expiration properly returned
  • refreshOAuthToken() supports Qwen Code with refreshQwenCodeToken() implementation
  • JWT decoding extracts user email from id_token or access_token
  • Follows same pattern as other OAuth providers (GitHub, OpenAI Codex)
  • OAuth Client ID is optional (public client supported)
  • Backward compatibility maintained (qwen-portal unchanged)

PR

See PR: fix-qwen-oauth-device-code-flow branch

  • Commit: 085d0c5a6 - feat(oauth): add proper Qwen Code OAuth device flow

Metadata

Metadata

Assignees

No one assigned

    Labels

    authAuthentication and login flowsbugSomething isn't workingprio:p2Medium: important but not urgentprovider:qwenProvider-specific issues for qwenprovidersLLM provider-specific issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions