OAuth 2.0 for carrier APIs, explained

What OAuth 2.0 and the client credentials grant mean for carrier API integrations, how they differ from API keys, and a worked UPS example.

OAuth 2.0 for carrier APIs, explained

What OAuth 2.0 client credentials actually means

OAuth 2.0 is an authorization framework that lets one piece of software prove its identity to another system without passing around a permanent password. In carrier connectivity, almost every rate, label and tracking call now runs through one specific flavor of it: the client credentials grant. This is a machine-to-machine exchange where your integration authenticates using its own client ID and secret, no shipper or customer login involved, and gets back a short-lived bearer token in return. As OAuth.net puts it, the Client Credentials grant is used for machine-to-machine communication where no user is involved, and the client authenticates directly with the authorization server using its own credentials and receives an access token.

That's the whole concept in one paragraph. The rest of this post is about why that matters right now, because UPS, FedEx and USPS have all forced this exact grant type on shippers who were previously getting away with a static key pasted into a config file years ago.

OAuth 2.0 vs. API keys: what's actually different

An API key is a static string. You get it once, you paste it into every request, and it stays valid until someone manually revokes it, sometimes for years. An OAuth 2.0 access token is the opposite in every way that matters operationally: it's requested on demand from a token endpoint, it expires on its own (typically within an hour), and it's issued in exchange for a client ID/secret pair rather than being the credential itself.

Plenty of API platforms actually run both models side by side for different purposes. As Axway describes it, the common pattern is authenticating a consumer so you can allow access only for a designated group of clients, know who's consuming your APIs and how much, and block clients that misbehave, and carriers have decided that a rotating, expiring, scoped token does that job far better than a key that never changes.

This is exactly why the big three parcel carriers all moved the same direction. UPS was blunt about it when it announced the change: it implemented an OAuth 2.0 security model for all APIs to enhance the overall security for our customers to reduce fraud and provide enhanced API capabilities, deprecating the existing Access Key-based authorization. FedEx is following the same logic with its SOAP-to-REST migration, where REST APIs use current authentication frameworks like OAuth 2.0, protecting your and your customers' data, with migrations required to be complete by June 1, 2026.

The client credentials grant, step by step

Mechanically, the flow is short: your application sends its client ID and secret to a token endpoint, the authorization server validates them, and it hands back an access token with a type and an expiry window. There's no browser popup, no redirect, no username field for a human to fill in.

  • Your integration sends a POST request to the carrier's OAuth token endpoint with grant_type=client_credentials plus your client ID and secret
  • The authorization server validates those credentials against its registry
  • It returns a JSON response containing an access token, a token type (almost always "Bearer"), and an expiry in seconds
  • Your app attaches that token to the Authorization header on every subsequent API call, until it expires

One detail that trips people up: there's no refresh token in this grant. Unlike the authorization code flow you'd use for a consumer-facing app, client credentials skips that entirely. As OAuth.net explains, there is no redirect, no user login, and no refresh token, just a direct exchange of credentials for an access token, and because access tokens are short-lived, clients should request a new one when the current one expires rather than storing it permanently. In practice that means your code just repeats step one whenever the old token runs out. No special refresh logic, no rotating secondary secret to manage, just re-authenticate.

Worked example: getting a token from UPS

UPS's implementation is a clean, well-documented example of exactly this pattern, and it's the one most European shippers hit first since UPS forced the switch back in 2023 to 2024. UPS's own developer documentation describes the client credentials use case plainly: it's built for cases integrating UPS APIs into your business's software, best used for when the integration owner is also the UPS shipper being represented, since you will know your own UPS ID credentials.

In practice, a developer registers an application in the UPS Developer Portal, which issues a client ID and client secret tied to that app. From there, the flow is exactly what UPS's own guidance describes: make a call to the OAuth endpoint with your client ID and client secret. The response comes back as a bearer token, and per UPS's getting-started documentation, you include your token as a "Bearer" token in the "Authorization" header, using it on every subsequent call to the Ship API, Track API, or Rating API. That token is good for roughly an hour before you have to request a new one.

FedEx followed the same playbook when it retired its legacy SOAP platform. Under the old system, authentication used static credentials, a meter number, authentication key, password, and account number, whereas the new FedEx REST APIs, available through the FedEx Developer Portal, use RESTful architecture, JSON payloads, OAuth 2.0 token-based authentication. USPS's Web Tools shutdown in January 2026 pushed shippers through the identical transition on the postal side.

If you're building and maintaining these OAuth clients yourself across a dozen or more carrier accounts, the token caching, expiry tracking, and re-authentication logic adds up fast, and it's exactly the layer that carrier-connectivity platforms like Cargoson handle by default rather than leaving each carrier's OAuth quirks to your own developers. Other TMS vendors such as nShift, Shiptify and FreightPOP take a similar approach, and it's worth checking whether MercuryGate, Descartes or Alpega already absorb this for the carriers you use before you write a fifth custom OAuth client from scratch.

Common mistakes shippers make with OAuth-based carrier APIs

The most frequent one: treating the bearer token like a permanent API key. Someone hardcodes it into a config file, it works fine in testing, and then it silently starts failing in production an hour later when the token expires and nobody built the re-auth logic. The fix is caching the token in memory alongside its expiry timestamp and requesting a fresh one proactively, not reactively after a wave of 401 errors during your peak shipping window.

The second mistake is confusing client credentials with the authorization code grant. They solve different problems. Axway's own grant-type guidance is clear that Authorization Code with PKCE is the default for any user-facing application, web apps, single-page apps, mobile apps, protecting public clients that cannot keep a secret, while Client Credentials is for machine-to-machine traffic where no user is involved, where the application authenticates itself with a client ID and secret and gets a token scoped to the application, used for backend service calls and scheduled jobs. Your ERP talking to UPS's Ship API is squarely the second case. If a carrier's documentation is pointing you toward a login redirect and an authorization code, you're either integrating the wrong endpoint or building for a use case (like a customer-facing portal) that doesn't match a backend shipping integration.

FAQ

Is OAuth 2.0 the same as an API key?

No. An API key is a single static credential you send with every call. OAuth 2.0's client credentials grant exchanges a client ID and secret for a temporary access token that expires and has to be renewed, which is a meaningfully different security model even though both end up in an HTTP header.

Do I need to handle a refresh token for carrier APIs?

Generally no. Pure client credentials flows don't issue refresh tokens, since there is no redirect, no user login, and no refresh token, just a direct exchange of credentials for an access token. When your token expires, you just call the token endpoint again with the same client ID and secret.

Which carriers currently require OAuth 2.0?

UPS has required it since 2024, USPS retired its old Web Tools authentication in January 2026, and FedEx is retiring SOAP with migrations required to be complete by June 1, 2026. DHL had already moved to REST and OAuth earlier than either.

What happens if my token expires mid-shipment-run?

You'll get a 401 Unauthorized on the next call. Well-built integrations catch that response, silently request a fresh token, and retry the original call rather than surfacing an error to whoever's printing labels.

Is OAuth 2.0 more secure than a static API key?

Yes, structurally. A leaked API key is valid indefinitely until someone notices and revokes it. A leaked OAuth access token is only useful for the remainder of its short lifespan, and the underlying client secret can be rotated without touching the rest of your integration logic.