Authentication
Every generated client takes its credentials at construction. For a bearer-token API,
pass token — or set the environment variable the SDK is generated to read:
import { Client } from 'glotto-sdk';
const client = new Client({ token: '<token>' });
const result = await client.pets.createPet({ name: 'Biscuit', species: 'cat' });regenerated + byte-diffed in CI a0f8af4b462c
If you omit token, the client falls back to its configured env var (e.g.
PETSTORE_TOKEN). The scheme and env var come from glotto.yml#/client_settings/auth.
Other schemes
The constructor options match the API’s declared security scheme:
- API key —
apiKey, withapiKeyName(defaultX-API-Key) andapiKeyIn(headerorquery, defaultheader). - OAuth2 —
accessToken, orclientId/clientSecret/tokenEndpoint/scopefor the client-credentials flow (the client caches the token and de-dupes in-flight refreshes). - Basic and custom schemes are generated when the spec declares them.
Typed scope constants
When an OAuth2 scheme in your spec declares scopes, every generated SDK also exports them as typed constants — a module-level scope enumeration (sorted scope → description), so consumers reference the API’s scopes by a checked name instead of a hand-typed string. In TypeScript:
export const OAuth2Scopes = {
'admin:settings': 'Administrative settings access',
read: 'Read access',
write: 'Write access',
} as const;
export type OAuth2Scope = keyof typeof OAuth2Scopes;
Each language gets its native idiom:
| Language | Emitted shape |
|---|---|
| TypeScript, React Native | OAuth2Scopes const map (as const) + OAuth2Scope key type |
| Python | class OAuth2Scope(StrEnum), UPPER_SNAKE members |
| Go | type OAuth2Scope string + a sorted const block (OAuth2ScopeAdminSettings) |
| Java | public enum OAuth2Scopes, each constant carrying scope + description |
| Kotlin | enum class OAuth2Scope(val scope: String, val description: String) |
| C# | public static class OAuth2Scopes of const string fields |
| PHP | enum OAuth2Scope: string (a backed enum) |
| Ruby | an OAuth2Scopes module of string constants |
| Rust | pub const OAUTH2_SCOPES: &[(&str, &str)] |
| Swift | public enum OAuth2Scope: String |
| Dart | class OAuth2Scope of static const String fields |
| Elixir | a Glotto.OAuth2Scope module (scopes/0) |
Methods advertise what they need, too: an operation whose security requirement carries required
scopes gets a Required OAuth2 scopes: … note in its generated doc comment (JSDoc, docstring,
Javadoc, and so on), so the requirement shows up in your editor at the call site.
Both emissions appear only when the spec declares scopes — a scope-less spec generates exactly the same SDK as before. And they are metadata + docs only: the client attaches the token as configured and never gates a call on scopes.
OAuth2 token-endpoint errors
When the token endpoint rejects a request, the SDK raises its usual typed error — the same
ApiError (or per-status subclass) you already catch — and additionally attaches the
RFC 6749 §5.2 reason as a typed
OAuthErrorResponse carrying error, error_description, and error_uri. That lets you branch
on the cause instead of hand-parsing the raw body:
try:
client.pets.list_pets()
except ApiError as err:
if err.oauth_error and err.oauth_error.error == "invalid_grant":
reauthenticate() # the user's grant expired or was revoked
elif err.oauth_error and err.oauth_error.error == "invalid_client":
raise ConfigError(err.oauth_error.error_description) # bad deployment credentials
It is populated on both the in-client client-credentials fetch and the standalone
exchange_code_for_token / refresh_access_token helpers. The decode is best-effort: a token
endpoint that returns a non-JSON, non-object, or error-less body simply leaves the field unset
rather than failing differently, and the error’s status, raw body, and headers are unchanged
either way.
| Language | Accessor |
|---|---|
| Python | err.oauth_error (OAuthErrorResponse) |
| Ruby | err.oauth_error |
| PHP | $err->oauthError |
| Java | err.oauthError() |
| Kotlin | err.oauthError |
| C# | err.OauthError |
Go and TypeScript are not in this list yet: their token fetches still surface a plain error /
Error rather than the typed ApiError, so there is no typed error to attach the reason to.
On React Native, the bearer token can be backed by secure storage — see the
React Native guide. Every other SDK language accepts an optional pluggable
token store on the same idea: pass a token_store (an object exposing get_token, plus
set_token for OAuth2 — idiomatic casing and shape per language: a TypeScript tokenStore
option, a Python token_store kwarg, a Go WithTokenStore option, a Rust with_token_store
builder, a Dart tokenStore parameter, an Elixir :secure_token_store option, and the
constructor knobs on Ruby, PHP, C#, Java, and Kotlin) to resolve the bearer token from your own
secure backend per request, and to persist the OAuth2 client-credentials token cache across
process restarts. On APIs with per-endpoint security (a security_schemes registry), every one of
those clients takes one read-only store per bearer-style scheme instead of the single knob,
resolved before that scheme’s static credential — a Ruby token_store_<scheme> kwarg, a PHP
$tokenStore<Scheme> parameter, a C# TokenStore<Scheme> option, Java and Kotlin
tokenStore<Scheme> constructor params, a TypeScript and React Native tokenStore<Scheme> option,
a Python token_store_<scheme> kwarg, a Go WithTokenStore<Scheme> option, a Rust
with_token_store_<scheme> builder, a Dart tokenStore<Scheme> parameter, and an Elixir
:secure_token_store_<scheme> option. The store is read-only there because a multi-scheme client
attaches static credentials and never runs a token fetch, so it has no cache to persist. No storage
backend is bundled — bring your vault, OS keyring, or encrypted file store.