Authentication
Supply an OAuth bearer token to the SDK; it attaches Authorization: Bearer … to every request.
The token identifies one agent. Login and token renewal belong to your application.
Choosing a flow
| Flow | Use | Default client ID |
|---|---|---|
| Authorization Code + PKCE | Interactive apps | babelconnect, no client secret |
| Password grant | First-party scripts and local development | manager |
| SSO | Tenants with a configured identity provider | Deployment-specific |
| Existing bearer | Host application already authenticated the agent | No further exchange |
Get a token
The password grant posts form data to the server's /oauth/token endpoint:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=AGENT&password=SECRET&client_id=manager
Use passwordGrant({ serverUrl, user, pass }) in TypeScript or
bcclient.PasswordGrant(ctx, serverURL, user, pass) in Go. Both return only the access-token string;
TypeScript allows a clientId override, while Go fixes it to manager. Handle a thrown exception
(TS) or returned error (Go) for a failed grant or network request.
Connect with the token
Use BabelconnectClient.connect({ serverUrl, token }) or
bcclient.Dial(ctx, bcclient.Options{Addr: addr, Token: token}).
Go's current Addr uses plain HTTP; it is not an HTTPS URL.
For REST, attach the header yourself:
GET /v1/agent/state
Authorization: Bearer <token>
REST covers unary operations; live state uses Subscribe. See API surfaces.
Authorization Code + PKCE
Ask the operator for the OAuth consent origin, an allowed callback URL, and the required scope.
The agent server proxies POST /oauth/token, but does not serve GET /oauth/authorize.
buildAuthorizeUrl only constructs a URL: its serverUrl must point to the consent origin, even
though that parameter shares its name with the API origin. In Go the parameter is OAuthBase.
- Generate a fresh verifier/challenge with
pkceChallenge()(TS) orGeneratePKCE()(Go). - Generate an unpredictable
state, keep it and the verifier across the redirect, and navigate tobuildAuthorizeUrl/PkceAuthorizeURL. Use the registeredredirectUri, challenge and scope. - At the callback, reject a missing/mismatched
stateor a login error. Exchangecodewith the same verifier and redirect URI; remove the one-time stored values. - Connect with the returned access token.
This TypeScript fragment shows the SDK calls; your login routes own navigation, one-time storage,
and validation of returnedCode and returnedState:
import { pkceChallenge, buildAuthorizeUrl, authorizationCodeGrant } from "@babelforce/babelconnect-sdk";
const { codeVerifier, codeChallenge } = await pkceChallenge();
const state = crypto.randomUUID();
const redirectUri = "https://app.example.com/oauth/callback";
const consentUrl = buildAuthorizeUrl({
serverUrl: "https://login.example.com", redirectUri, scope: "*", codeChallenge, state,
});
// Save { codeVerifier, state } for this login, then navigate to consentUrl.
// In the callback, load them and validate before exchanging:
if (returnedState !== state) throw new Error("Login state mismatch");
const tokens = await authorizationCodeGrant({
serverUrl: "https://agent.example.com", code: returnedCode, redirectUri, codeVerifier,
});
// Connect with tokens.access_token; retain lifetime fields for renewal.
Go uses PkceAuthorizeURL(bcclient.AuthorizeURLParams{OAuthBase, RedirectURI, Scope, CodeChallenge, State}), then AuthorizationCodeGrant(ctx, tokenOrigin, code, redirectURI, verifier).
Handle errors from both verifier generation and token exchange. Unlike TypeScript, Go returns
only the access token, not refresh/lifetime fields. Both default the public client ID to
babelconnect; Go's AuthorizationCodeGrantClient also accepts an explicit client and HTTP client.
A redirect_uri_mismatch means the callback is not registered for that OAuth client.
Keep verifiers short-lived. Send the verifier only in the token-exchange body, never in redirect URLs.
Don't ship credentials to the browser
Interactive apps should redirect to the configured login with PKCE or obtain a short-lived token
from their own backend. Keep account passwords and client secrets out of application bundles.
Keep tokens out of logs and URLs. An embedding host hands the token to
the app through postMessage.
SSO
The server accepts POST /auth/sso/init/{tenant}/babelconnect to begin configured tenant login and
POST /auth/sso/{tenant} to exchange the returned IdP code. These are auth proxy routes, not part
of the generated Agent OpenAPI reference. Obtain the tenant's request/response contract from the
operator; once you have a token, SDK connection is the same.
Token lifetime
Neither standalone TypeScript nor Go refreshes tokens automatically. Track expiry in your login layer and replace the client with a fresh token when necessary; see Errors & reconnects for the audio consequences.
| Helper | Returned lifetime information |
|---|---|
TS passwordGrant, Go PasswordGrant | Access token only |
TS authorizationCodeGrant | Full response: access token, optional expires_in, optional refresh_token |
Go AuthorizationCodeGrant | Access token only |
Read the full /oauth/token response yourself if the helper omits fields you need. When the
issuer grants rotating refresh tokens, retain the newest token after each exchange; a used token
cannot be reused. An authentication failure on reconnect may mean expiry or revocation, not a
network outage. Request a new login rather than retrying rejected credentials indefinitely.
The embedded app has a separate in-place token handoff.
Logout
Closing a client releases its stream and media; it does not revoke its token.
TypeScript provides revokeToken({ serverUrl, token }); Go provides
bcclient.RevokeToken(ctx, oauthBase, token) and the configurable RevokeTokenClient.
Both post to /oauth/revoke, with the token in the form body and bearer header. The token-type
hint defaults to access_token (Go also sends a client ID, default babelconnect).
Revocation is best-effort: helpers accept non-2xx responses and only report transport/request errors. An unknown token may also return 200; success is not proof it was active. Always finish local cleanup even if revocation fails:
try { await revokeToken({ serverUrl, token }); }
finally { await bc.close(); }
Security checklist
- Serve browser apps and APIs over HTTPS; allow microphone access only where needed.
- Allow only the intended CORS origins. The empty allowlist is permissive.
- Register exact OAuth callback URLs and validate one-time
statevalues. - Keep tokens and refresh credentials out of logs, URLs, and source; revoke on logout.
- For embeds, configure framing, message origins and microphone delegation separately; see Embedding.
- The current Go client constructs a plain HTTP URL. Use it only behind a trusted local tunnel or in an explicitly trusted network; it cannot directly target a production HTTPS origin.