You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Winforms+C#的Upwork API桌面应用授权登录方式咨询

Upwork API Authorization for WinForms + C# Desktop Apps

Hey there! I’ve tackled this exact scenario before—Upwork’s docs do a poor job of calling out desktop-specific OAuth flows, so let me break down how to get this working for your WinForms app.

Upwork uses OAuth 2.0 with PKCE (Proof Key for Code Exchange) for desktop/mobile apps (since you can’t securely store a client secret in a desktop binary). Here’s the step-by-step implementation:

1. First, Configure Your Upwork Developer App

  • Head to your Upwork Developer Dashboard and create/edit your app.
  • Set the app type to Desktop/Mobile (this enables PKCE support).
  • Add a custom redirect URI (e.g., myupworkapp://authcallback)—you’ll need this to capture the authorization code after the user logs in.

2. Implement the PKCE Flow in C#

Step 1: Generate PKCE Code Verifier & Challenge

You’ll need these to secure the authorization flow (no client secret required):

using System.Security.Cryptography;
using System.Text;
using System.Web;

// Generate a random code verifier (32-128 chars, Base64URL encoded)
private string GenerateCodeVerifier()
{
    var randomBytes = new byte[32];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(randomBytes);
    return Convert.ToBase64String(randomBytes)
        .Replace('+', '-')
        .Replace('/', '_')
        .TrimEnd('=');
}

// Generate the code challenge from the verifier (SHA256 + Base64URL)
private string GenerateCodeChallenge(string codeVerifier)
{
    using var sha256 = SHA256.Create();
    var verifierBytes = Encoding.UTF8.GetBytes(codeVerifier);
    var hashBytes = sha256.ComputeHash(verifierBytes);
    return Convert.ToBase64String(hashBytes)
        .Replace('+', '-')
        .Replace('/', '_')
        .TrimEnd('=');
}

Step 2: Launch the Authorization URL

Use the user’s default browser (or a WinForms WebBrowser control) to open the Upwork authorization page:

private void StartAuthorization()
{
    var clientId = "YOUR_UPWORK_CLIENT_ID";
    var redirectUri = "myupworkapp://authcallback";
    var codeVerifier = GenerateCodeVerifier();
    var codeChallenge = GenerateCodeChallenge(codeVerifier);
    var scope = "api:read"; // Add scopes you need, e.g., "api:read api:write"

    // Store the code verifier temporarily (e.g., in a static variable or app settings)
    _tempCodeVerifier = codeVerifier;

    var authUrl = $"https://www.upwork.com/api/auth/v1/authorize?" +
                  $"client_id={HttpUtility.UrlEncode(clientId)}" +
                  $"&redirect_uri={HttpUtility.UrlEncode(redirectUri)}" +
                  $"&response_type=code" +
                  $"&code_challenge={HttpUtility.UrlEncode(codeChallenge)}" +
                  $"&code_challenge_method=S256" +
                  $"&scope={HttpUtility.UrlEncode(scope)}";

    // Open the URL in default browser
    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(authUrl) { UseShellExecute = true });
}

Step 3: Capture the Authorization Code via Custom URI Scheme

Windows needs to know that your app handles the myupworkapp:// scheme. You can register this temporarily on app startup (or via installer):

// Add this to your app's startup logic (run as admin if needed)
private void RegisterCustomUriScheme()
{
    var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
    using var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Classes\myupworkapp");
    key.SetValue("", "URL:My Upwork App");
    key.SetValue("URL Protocol", "");
    using var shellKey = key.CreateSubKey(@"shell\open\command");
    shellKey.SetValue("", $"\"{appPath}\" \"%1\"");
}

Then, in your Program.cs, handle the command-line argument that contains the callback URL:

static class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var mainForm = new MainForm();

        // Check if we're being launched via the OAuth callback
        if (args.Length > 0 && args[0].StartsWith("myupworkapp://authcallback"))
        {
            // Parse the authorization code from the callback URL
            var callbackUrl = new Uri(args[0]);
            var code = HttpUtility.ParseQueryString(callbackUrl.Query).Get("code");
            mainForm.HandleAuthorizationCode(code);
        }

        Application.Run(mainForm);
    }
}

Step 4: Exchange Code for Access Token

Once you have the authorization code, exchange it (along with the saved code verifier) for an access token:

using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

private async Task<string> ExchangeCodeForToken(string authorizationCode)
{
    var clientId = "YOUR_UPWORK_CLIENT_ID";
    var redirectUri = "myupworkapp://authcallback";

    using var client = new HttpClient();
    var formData = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("grant_type", "authorization_code"),
        new KeyValuePair<string, string>("client_id", clientId),
        new KeyValuePair<string, string>("code", authorizationCode),
        new KeyValuePair<string, string>("redirect_uri", redirectUri),
        new KeyValuePair<string, string>("code_verifier", _tempCodeVerifier)
    });

    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    var response = await client.PostAsync("https://www.upwork.com/api/auth/v1/token", formData);
    response.EnsureSuccessStatusCode();

    var tokenJson = await response.Content.ReadAsStringAsync();
    // Parse tokenJson to get access_token, refresh_token, expires_in, etc.
    // You can use Newtonsoft.Json or System.Text.Json for parsing
    return tokenJson;
}

// Call this from your form when you receive the code
public void HandleAuthorizationCode(string code)
{
    _ = ExchangeCodeForToken(code).ContinueWith(task =>
    {
        if (task.IsCompletedSuccessfully)
        {
            var tokenData = task.Result;
            // Save the access/refresh tokens securely (e.g., using Windows Credential Manager)
            // Now you can use the access token to call Upwork API endpoints
        }
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

3. Key Notes

  • Scopes: Make sure you request only the scopes your app actually needs—Upwork may restrict access to certain scopes until your app is approved.
  • Token Storage: Never store access/refresh tokens in plain text. Use Windows Credential Manager or encrypted app settings to keep them secure.
  • Refresh Tokens: When your access token expires, use the refresh token to get a new one without prompting the user again (follow similar steps but use grant_type=refresh_token).

内容的提问来源于stack exchange,提问作者Valery Yegorov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:02:38