CI HUBCI HUB SDK
Guides

Handle token refresh

Keep a session alive by refreshing the CI HUB and DAM tokens, and recover when one expires.

Using the client library?

TokenManager implements this entire guide: proactive refresh of the CI HUB session, reactive retry on expiry, refresh-token rotation, and the DAM try-then-fallback. See the client library page. What follows documents the wire contract underneath, for other languages or custom implementations.

A connected session holds two kinds of token, each with its own lifetime: the CI HUB access token from token exchange, and the DAM connection token from a DAM login. Both are renewed through GET /auth/refreshToken; the token you send in provider-authorization decides which session is renewed.

Lifetimes

  • CI HUB access token. Expires about an hour after exchange. Renew it with the CI HUB refresh token returned alongside it. When the refresh token itself expires, run the token exchange again.
  • DAM connection token. Lifetime and refresh model are provider-dependent. Some providers issue a refresh token; others force a fresh login. See the refresh support matrix.

The refresh response returns a new access_token and refresh_token but no expires_in. Track the access token's lifetime from the expires_in returned by the original exchange, or from the token's exp claim.

Detect expiry from the error

You do not have to track expiry to handle it. An expired token surfaces as a specific error code, so a reactive path works: catch the code and refresh.

CodeHTTPWhat expiredRecover by
cihub-access-token-invalid401CI HUB access tokenRefresh the CI HUB session. If that fails, re-exchange.
cihub-refresh-token-invalid401CI HUB refresh tokenRun the token exchange again.
provider-access-token-invalid403DAM connection tokenRefresh the DAM token, or start a fresh DAM login.

Refresh the CI HUB session

Send the CI HUB refresh token in provider-authorization. The call returns a new access token and a new refresh token; store both.

You can refresh either way: pre-emptively before the hour is up, or reactively on the first cihub-access-token-invalid. The reactive wrapper below refreshes once and retries; pre-emptive refresh follows the same call on a timer keyed off expires_in.

const BASE_URL = 'https://stage.ci-hub.com/api/v1'

async function withFreshToken(call: (accessToken: string) => Promise<Response>) {
  const response = await call(session.accessToken)
  if (response.status !== 401) return response

  // Only an expired access token is refreshable here; pass other 401s through.
  const { error } = await response.clone().json()
  if (error?.code !== 'cihub-access-token-invalid') return response

  const refresh = await fetch(`${BASE_URL}/auth/refreshToken`, {
    headers: {
      Authorization: `Bearer ${session.accessToken}`,
      'provider-authorization': `Bearer ${session.refreshToken}`,
    },
  })
  if (!refresh.ok) {
    // Refresh token is gone too. Re-run the token exchange.
    throw new Error('CI HUB session expired; re-exchange required')
  }

  const { access_token, refresh_token } = await refresh.json()
  session.accessToken = access_token
  session.refreshToken = refresh_token // rotate; the previous refresh token is spent
  return call(session.accessToken)
}

Refresh the DAM connection

The DAM connection token expires on the provider's schedule. Renew it through the same endpoint, with the DAM refresh token in provider-authorization. Handle every provider with one path: try the refresh, and fall back to a fresh DAM login when it fails. A 404 means the provider has no refresh path, so treat it (and any other failure) as the signal to log in again. Some providers return only a new access_token; when refresh_token is absent, keep the prior one. The Token refresh reference covers the request and the try-then-fallback pattern.

Storing tokens

The partner platform stores both tokens. CI HUB does not persist DAM connection tokens server-side, so a dropped token means a fresh login, not a server lookup. Refresh rotates the CI HUB refresh token on every call, so always overwrite the stored pair with the values from the latest response. Keep tokens out of logs and analytics.

Next

On this page