Skip to main content

Authentication

The SDK authenticates every request with an OAuth 2.0 bearer token. You choose how that token is obtained when you create the client (or bring one yourself via the OAuth 2.0 endpoints). Configure auth once; the SDK applies it — and, where the flow allows, refreshes it — for every request.

Choosing a flow​

FlowUse it forClient secretSDK config
Authorization Code + PKCEInteractive apps acting as a user — SPAs, CLIs, mobile/desktopNorefreshToken (or bearer)
Client credentialsConfidential server-to-server machine accessYesclientCredentials
Token exchangeA partner's server acting in one sub-accountYestokenExchange
Password grantFirst-party scripts / quick devNopassword
Bearer tokenA token you already hold—bearer

If your software acts on behalf of a human who logs in, use Authorization Code + PKCE. For an unattended backend, client credentials is the long-term answer (see the availability note below); until it ships, a password grant is the simplest first-party option.

Authorization Code + PKCE​

The modern, secure flow for public clients (RFC 7636) — no client secret is ever stored. The user authenticates with babelforce and approves your app; you then exchange the returned code (bound to a one-time PKCE verifier) for an access token and a rotating refresh token. The SDK ships helpers for each step (pkceChallenge / GeneratePKCE, buildAuthorizeUrl / BuildAuthorizeURL, and the authorization-code exchange). How refresh tokens rotate, and what happens when one is used twice, is explained under Refresh tokens.

// 1. Generate a PKCE verifier/challenge and send the user to the consent page.
const { codeVerifier, codeChallenge } = await pkceChallenge();
const consentUrl = buildAuthorizeUrl({
baseUrl: "https://services.babelforce.com",
clientId: "your-public-client-id",
redirectUri: "https://app.example.com/callback",
scope: "*",
codeChallenge,
state: "csrf-token",
});
// Redirect the user to `consentUrl`; they return to redirectUri?code=…&state=…

// 2. Exchange the code (with the same codeVerifier) for tokens.
const tokens = await authorizationCodeGrant({
baseUrl: "https://services.babelforce.com",
code: "code-from-the-redirect",
redirectUri: "https://app.example.com/callback",
clientId: "your-public-client-id",
codeVerifier,
});

// 3a. Long-lived client — the access token refreshes transparently (refresh tokens rotate):
const mgr = await ManagerClient.connect({
auth: { kind: "refreshToken", refreshToken: tokens.refresh_token!, clientId: "your-public-client-id" },
});
// 3b. …or a one-shot client straight from the access token:
// const mgr = await ManagerClient.connect({ auth: { kind: "bearer", token: tokens.access_token } });

Client credentials​

An OAuth2 client_credentials grant for confidential, server-to-server access: the SDK exchanges your clientId / clientSecret for a bearer token at /oauth/token and applies it to every request. The token is refreshed transparently before it expires in all three languages.

The client_id / client_secret pair comes from an OAuth application of your account, created by an owner or manager with oauthApplications.create (see the Partner API guide, step 1). A token from such an application acts as a manager of the account and has no refresh token; the SDK fetches a new one before it expires.

Availability and secrets

OAuth applications created through the API are being rolled out; ask babelforce support whether they are available for your account. Treat any client secret as highly sensitive — never commit it or expose it to a browser/mobile client. It is shown once, at creation or reset.

const mgr = await ManagerClient.connect({
auth: { kind: "clientCredentials", clientId, clientSecret },
});

Password grant (legacy)​

A first-party grant kept for interactive/dev use — it sends a username/password to /oauth/token with the public manager client id (no secret). Prefer PKCE or client credentials for new integrations. The token refreshes transparently in all three languages.

const mgr = await ManagerClient.connect({ auth: { kind: "password", user, pass } });

Bearer token​

If you already hold a valid access token — for example from the PKCE exchange above, or one minted elsewhere — pass it directly:

const mgr = await ManagerClient.connect({ auth: { kind: "bearer", token } });

OAuth 2.0 endpoints​

The raw OAuth 2.0 endpoints — /oauth/authorize, /oauth/token, /oauth/revoke — are exposed as mgr.auth / mgr.Auth for when you manage tokens yourself. They authenticate via credentials carried in the request itself (per RFC 6749 / 7009), independent of the client's configured auth.

Token endpoint​

Exchange a grant (authorization_code, refresh_token, password, or client_credentials) for an access token.

const tokens = await mgr.auth.token({
grant_type: "client_credentials",
client_id: "…",
client_secret: "…",
scope: "…",
});
console.log(tokens.access_token, tokens.expires_in);

Authorize & revoke​

// Authorization-code consent/redirect (for PKCE, prefer buildAuthorizeUrl above):
await mgr.auth.authorize({
response_type: "code",
client_id: "…",
redirect_uri: "https://app.example.com/callback",
scope: "…",
});

// Revoke an access or refresh token (RFC 7009):
await mgr.auth.revoke({ token: "…" });

Grant failures​

A failed grant — wrong credentials, an expired or already-used refresh token, an unavailable token endpoint — surfaces as the SDK's typed API error, whether the SDK fetched the token transparently or you called a grant helper yourself: ManagerApiError (status, code, body) in TypeScript, *manager.APIError (Status, Code, Message, Body; errors.As compatible) in Go, and ManagerError::Api { status, code, .. } in Rust. Branch on the structured status/code fields rather than parsing the error message.

Base URL​

The SDK talks to https://services.babelforce.com by default. Set baseUrl (TypeScript) / BaseURL (Go) — or the builder's .base_url() (Rust) — to target a per-customer or non-production host:

const mgr = await ManagerClient.connect({
baseUrl: "https://acme.babelforce.com",
auth: { kind: "clientCredentials", clientId, clientSecret },
});

Reference​