Skip to content

UPS OAuth Redirect issues with SDK #129

@TroyMeOut

Description

@TroyMeOut

SDK does not handle UPS Connect with the 302 response and redirect URL (to OAuth) in the header. Instead, a timeout is hit.
Please update the response object to have the redirect URL and have it return accordingly. The HttpClient needs to be updated to not "AllowAutoRedirect" and pull the URL from the "Location" header.

Error is thrown on:
await shipEngineSdk.ConnectCarrier(CarrierName.Ups, upsAccountInfo, cancellationToken);

I have tried doing the following and was still throwing a custom ShipEngineException:

public virtual async Task<IShipEngine> GetShipEngineSDKWithNoRedirectAsync()
    {
#if NET48
        System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
#endif

#if NETFRAMEWORK
        var handler = new HttpClientHandler { AllowAutoRedirect = false };
#else
    var handler = new SocketsHttpHandler { AllowAutoRedirect = false };
#endif

        var httpClient = new HttpClient(handler)
        {
            BaseAddress = new Uri("https://api.shipengine.com/"),
        };

        // Some CDNs/WAFs reject requests with no UA header — add one.
        httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("YourApiClient/1.0");

        var apiKey = await ... GetApiKey;
        var config = new Config(apiKey);

        return new ShipEngine(config, httpClient);
    }

This is our current work around to connect without using the SDK:

private async Task<string> UpsConnectAsync(
    string apiKey,
    string baseUrl, // e.g., "https://api.shipengine.com/" or "https://api.eu.shipengine.com/"
    string accountNumber,
    string nickname,
    string? accountCountryCode,
    string? accountPostalCode,
    CancellationToken ct)
    {
#if NET48
        System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
#endif

#if NETFRAMEWORK
        var handler = new HttpClientHandler { AllowAutoRedirect = false };
#else
    var handler = new SocketsHttpHandler { AllowAutoRedirect = false };
#endif

        using var http = new HttpClient(handler) { BaseAddress = new Uri(baseUrl) };
        http.DefaultRequestHeaders.Add("API-Key", apiKey);                 // ShipEngine auth
        http.DefaultRequestHeaders.Accept.ParseAdd("application/json");
        http.DefaultRequestHeaders.UserAgent.ParseAdd("YourAPIClient/1.0");
        http.DefaultRequestHeaders.ExpectContinue = false;

        // Minimal body for UPS connect (snake_case fields per API)
        var body = new
        {
            nickname = nickname,
            account_number = accountNumber,
            account_country_code = accountCountryCode,
            account_postal_code = accountPostalCode
        };

        using var req = new HttpRequestMessage(HttpMethod.Post, "v1/connections/carriers/ups")
        {
            Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json")
        };

        using var resp = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, ct);

        if (resp.StatusCode == HttpStatusCode.Redirect || resp.StatusCode == HttpStatusCode.RedirectMethod)
        {
            var oauthUrl = resp.Headers.Location?.ToString();
            if (!string.IsNullOrEmpty(oauthUrl))
                return oauthUrl!;

            var b = await resp.Content.ReadAsStringAsync();
            throw new InvalidOperationException("Expected UPS OAuth Location header was missing. Body: " + b);
        }

        // Bubble up config/auth issues with details
        var bodyText = await resp.Content.ReadAsStringAsync();
        throw new InvalidOperationException($"ShipEngine connect returned {(int)resp.StatusCode} {resp.ReasonPhrase}. Body: {bodyText}");
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions