> For the complete documentation index, see [llms.txt](/llms.txt)

# 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:

**TypeScript** (regenerated + byte-diffed in CI `a0f8af4b462c`)

```ts
import { Client } from 'glotto-sdk';

const client = new Client({ token: '<token>' });
const result = await client.pets.createPet({ name: 'Biscuit', species: 'cat' });
```

**React Native** (regenerated + byte-diffed in CI `a1fefe7d3458`)

```ts
import { Client } from 'glotto-sdk';

const client = new Client({ token: '<token>' });
const result = await client.pets.createPet({ name: 'Biscuit', species: 'cat' });
```

**Python** (regenerated + byte-diffed in CI `2242160f8958`)

```python
from glotto_sdk import Client, PetCreate, PetCreateSpecies

client = Client(token="<token>")
result = client.pets.create_pet(body=PetCreate(name='Biscuit', species=PetCreateSpecies.CAT))
```

**Go** (regenerated + byte-diffed in CI `f0c565cc46f8`)

```go
package main

import (
    "context"
    "fmt"

    sdk "example.com/glotto-sdk-go"
)

func main() {
    ctx := context.Background()
    client := sdk.NewClient(sdk.WithToken("<token>"))
    result, err := client.Pets.CreatePet(ctx, sdk.PetCreate{Name: "Biscuit", Species: "cat"})
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}
```

**Java** (regenerated + byte-diffed in CI `12c05e098737`)

```java
import com.glotto.Client;
import com.glotto.models.PetCreate;
import com.glotto.models.PetCreateSpecies;

public class Snippet {
    public static void main(String[] args) throws Exception {
        Client client = Client.builder().token("<token>").build();
        var result = client.pets().createPet(PetCreate.builder().name("Biscuit").species(PetCreateSpecies.CAT).build());
        System.out.println(result);
    }
}
```

**Kotlin** (regenerated + byte-diffed in CI `0f5e53ae2522`)

```kotlin
import com.glotto.Client
import com.glotto.models.PetCreate
import com.glotto.models.PetCreateSpecies
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.flow.collect

fun main() = runBlocking {
    val client = Client(token = "<token>")
    val result = client.pets.createPet(PetCreate(name = "Biscuit", species = PetCreateSpecies.CAT))
    println(result)
}
```

**C#** (regenerated + byte-diffed in CI `c5013ce0e88b`)

```csharp
using Glotto;
using PetCreate = Glotto.Models.PetCreate;
using PetCreateSpecies = Glotto.Models.PetCreateSpecies;

var client = new Glotto.Client("<token>");
var result = await client.Pets.CreatePet(new PetCreate("Biscuit", PetCreateSpecies.Cat));
Console.WriteLine(result);
```

**PHP** (regenerated + byte-diffed in CI `1acd16081b46`)

```php
<?php
require 'vendor/autoload.php';

$client = new Glotto\Client(token: '<token>');
$result = $client->pets->createPet(new Glotto\Models\PetCreate('Biscuit', Glotto\Models\PetCreateSpecies::Cat));
var_dump($result);
```

**Ruby** (regenerated + byte-diffed in CI `a2b854f6593f`)

```ruby
require 'glotto'

client = Glotto::Client.new(token: '<token>')
result = client.pets.create_pet(body: { name: 'Biscuit', species: 'cat' })
puts result
```

**Rust** (regenerated + byte-diffed in CI `716e9ec181d1`)

```rust
let client = Client::default().with_token("<token>");
let result = client.pets().create_pet(PetCreate { name: "Biscuit".to_string(), species: PetCreateSpecies::Cat, extra_fields: Default::default() }).await?;
```

**Swift** (regenerated + byte-diffed in CI `0cc357352baf`)

```swift
import Foundation
import GlottoSdk

let client = Client(token: "<token>")
let result = try await client.pets.createPet(body: PetCreate(name: "Biscuit", species: PetCreateSpecies.cat))
```

**Dart** (regenerated + byte-diffed in CI `67567d6df435`)

```dart
import 'package:glotto_sdk/glotto_sdk.dart';

final client = Client(token: "<token>");
try {
  final result = await client.pets.createPet(PetCreate(name: "Biscuit", species: PetCreateSpecies.cat));
} finally {
  client.close();
}
```

**Elixir** (regenerated + byte-diffed in CI `b97af402f1d7`)

```elixir
client = Glotto.new(token: "<token>")
{:ok, result} = Glotto.Pets.create_pet(client, %Glotto.PetCreate{name: "Biscuit", species: "cat"})
```

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`, with `apiKeyName` (default `X-API-Key`) and `apiKeyIn` (`header` or `query`, default `header`).
- **OAuth2** — `accessToken`, or `clientId` / `clientSecret` / `tokenEndpoint` / `scope` for 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:

```ts
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](https://datatracker.ietf.org/doc/html/rfc6749#section-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:

```python
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](/docs/react-native). 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.
