Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authentication

Every generated SDK includes a runtime authentication module with built-in support for Bearer tokens, API keys, and HTTP Basic auth. Security schemes declared in your OpenAPI spec are reflected in the generated client interface — you supply the credentials when constructing the client, and they are automatically attached to every outgoing request.

Usage Patterns

Static Token

The simplest case: a long-lived token known at startup.

TypeScript

import { Configuration, PetsApi } from "@example/petstore";

const api = new PetsApi(new Configuration({
  basePath: "https://api.example.com",
  accessToken: process.env.API_TOKEN,
}));

const pet = await api.getPetById({ petId: 42 });

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BearerAuth{Token: os.Getenv("API_TOKEN")}),
)
api := sdk.NewPetsApi(client)
pet, err := api.GetPetById(context.Background(), 42)

Python

import os
from sdk import PetsApi
from sdk.runtime import Client, BearerAuth

api = PetsApi(Client(
    base_url="https://api.example.com",
    authenticator=BearerAuth(os.environ["API_TOKEN"]),
))
pet = api.get_pet_by_id(pet_id=42)

Rust

#![allow(unused)]
fn main() {
use sdk::PetsApi;
use sdk::runtime::{Client, BearerAuth};

let client = Client::new("https://api.example.com")
    .with_auth(BearerAuth::new(std::env::var("API_TOKEN").unwrap()));
let api = PetsApi::new(client);
let pet = api.get_pet_by_id(42).await?;
}

Dynamic Token (OAuth2 refresh)

When tokens expire and need periodic refresh, pass a function that returns the current token. The function is called on every request, so it always picks up the latest value.

TypeScript

class TokenStore {
  private token: string | null = null;
  private expiresAt = 0;

  async getToken(): Promise<string> {
    if (Date.now() > this.expiresAt) {
      const res = await fetch("/oauth/token", {
        method: "POST",
        body: new URLSearchParams({
          grant_type: "client_credentials",
          client_id: process.env.CLIENT_ID!,
          client_secret: process.env.CLIENT_SECRET!,
        }),
      });
      const data = await res.json();
      this.token = data.access_token;
      this.expiresAt = Date.now() + data.expires_in * 1000;
    }
    return this.token!;
  }
}

const store = new TokenStore();
const api = new PetsApi(new Configuration({
  basePath: "https://api.example.com",
  accessToken: () => store.getToken(),  // evaluated per-request
}));

Go

type TokenStore struct {
    mu        sync.Mutex
    token     string
    expiresAt time.Time
}

func (s *TokenStore) GetToken() string {
    s.mu.Lock()
    defer s.mu.Unlock()
    if time.Now().After(s.expiresAt) {
        // refresh logic ...
        s.token = refreshedToken
        s.expiresAt = time.Now().Add(1 * time.Hour)
    }
    return s.token
}

store := &TokenStore{}
client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BearerAuth{
        TokenProvider: store.GetToken,  // evaluated per-request
    }),
)

Python

import time
import httpx
from sdk import PetsApi
from sdk.runtime import Client, BearerAuth

class TokenStore:
    def __init__(self):
        self._token: str | None = None
        self._expires_at = 0.0

    def get_token(self) -> str:
        if time.time() > self._expires_at:
            resp = httpx.post("https://auth.example.com/oauth/token", data={
                "grant_type": "client_credentials",
                "client_id": os.environ["CLIENT_ID"],
                "client_secret": os.environ["CLIENT_SECRET"],
            })
            data = resp.json()
            self._token = data["access_token"]
            self._expires_at = time.time() + data["expires_in"]
        return self._token

store = TokenStore()
api = PetsApi(Client(
    base_url="https://api.example.com",
    authenticator=BearerAuth(store.get_token),  # evaluated per-request
))

Rust

#![allow(unused)]
fn main() {
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use sdk::PetsApi;
use sdk::runtime::{Client, BearerAuth};

struct TokenStore {
    token: Mutex<String>,
    expires_at: Mutex<Instant>,
}

impl TokenStore {
    fn get_token(&self) -> String {
        let mut expires = self.expires_at.lock().unwrap();
        if Instant::now() > *expires {
            // refresh logic ...
            *self.token.lock().unwrap() = refreshed_token;
            *expires = Instant::now() + Duration::from_secs(3600);
        }
        self.token.lock().unwrap().clone()
    }
}

let store = Arc::new(TokenStore { /* ... */ });
let s = Arc::clone(&store);
let client = Client::new("https://api.example.com")
    .with_auth(BearerAuth::from_provider(move || s.get_token()));
let api = PetsApi::new(client);
}

Authenticator Interface

All generators expose an Authenticator interface (trait in Rust, abstract base class in Python) that the generated client calls before each request. The runtime ships with three concrete implementations:

Auth TypeClass / StructWire Format
Bearer tokenBearerAuthAuthorization: Bearer <token>
API keyApiKeyAuthConfigurable header, query parameter, or cookie
HTTP BasicBasicAuthAuthorization: Basic <base64(user:pass)>

Bearer Tokens

Static Token

Pass a string at construction time. The same token is sent with every request.

TypeScript

import { Configuration, DefaultApi } from "./runtime";

const config = new Configuration({
  basePath: "https://api.example.com",
  accessToken: "my-static-token",
});

const api = new DefaultApi(config);

Go

import "example.com/sdk/runtime"

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BearerAuth{Token: "my-static-token"}),
)

Rust

#![allow(unused)]
fn main() {
use sdk::runtime::{Client, BearerAuth};

let client = Client::new("https://api.example.com")
    .with_auth(BearerAuth::new("my-static-token"));
}

Python

from sdk.runtime import Client, BearerAuth

client = Client(
    base_url="https://api.example.com",
    authenticator=BearerAuth("my-static-token"),
)

Java

import com.example.sdk.runtime.ApiClient;
import com.example.sdk.runtime.BearerAuth;

ApiClient client = new ApiClient(
    "https://api.example.com",
    new OkHttpClient(),
    new BearerAuth("my-static-token"),
    Map.of()
);

Kotlin

import com.example.sdk.runtime.ApiClient
import com.example.sdk.runtime.BearerAuth

val client = ApiClient(
    baseUrl = "https://api.example.com",
    client = OkHttpClient(),
    authenticator = BearerAuth("my-static-token"),
    defaultHeaders = emptyMap()
)

Dynamic Token Provider

When the token changes over time — after user login, or when refreshing an OAuth2 access token — pass a function instead of a string. The function is called on every request, so it always produces the current token.

TypeScript

const config = new Configuration({
  basePath: "https://api.example.com",
  accessToken: () => getCurrentBearerToken(),  // called per-request
});

The accessToken field accepts string | Promise<string> | ((name?, scopes?) => string | Promise<string>). A plain function is called synchronously; an async function or Promise is awaited.

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BearerAuth{
        TokenProvider: func() string {
            return getCurrentToken()  // called per-request
        },
    }),
)

If both Token and TokenProvider are set, the provider takes precedence.

Rust

#![allow(unused)]
fn main() {
use sdk::runtime::{Client, BearerAuth};

let client = Client::new("https://api.example.com")
    .with_auth(BearerAuth::from_provider(|| {
        get_current_token()  // called per-request
    }));
}

BearerAuth::new(token) stores a static string. BearerAuth::from_provider(fn) wraps your closure in an Arc and evaluates it on every authenticate() call. The closure must be Fn() -> String + Send + Sync + 'static.

Python

from sdk.runtime import Client, BearerAuth

client = Client(
    base_url="https://api.example.com",
    authenticator=BearerAuth(lambda: get_current_token()),  # called per-request
)

BearerAuth accepts str | Callable[[], str]. If you pass a callable, it is invoked inside auth_headers() on every request.

Java

import java.util.function.Supplier;

ApiClient client = new ApiClient(
    "https://api.example.com",
    new OkHttpClient(),
    new BearerAuth(() -> getCurrentToken()),  // called per-request
    Map.of()
);

BearerAuth has two constructors: BearerAuth(String token) for static tokens, and BearerAuth(Supplier<String> tokenProvider) for dynamic ones.

Kotlin

val client = ApiClient(
    baseUrl = "https://api.example.com",
    client = OkHttpClient(),
    authenticator = BearerAuth { getCurrentToken() },  // called per-request
    defaultHeaders = emptyMap()
)

Kotlin’s trailing-lambda syntax makes the provider form especially concise. BearerAuth has two constructors: constructor(token: String) and constructor(tokenProvider: () -> String).

API Key Authentication

ApiKeyAuth sends a named key in a header, query parameter, or cookie. Like BearerAuth, it supports both static keys and dynamic key providers evaluated per-request.

Static Key

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.ApiKeyAuth{
        Key:      "sk-abc123",
        Name:     "X-API-Key",
        Location: runtime.APIKeyInHeader,
    }),
)

Rust

#![allow(unused)]
fn main() {
use sdk::runtime::{Client, ApiKeyAuth};

let client = Client::new("https://api.example.com")
    .with_auth(ApiKeyAuth::new("X-API-Key", "sk-abc123"));
}

Python

from sdk.runtime import Client, ApiKeyAuth

client = Client(
    base_url="https://api.example.com",
    authenticator=ApiKeyAuth(header_name="X-API-Key", api_key="sk-abc123"),
)

Java

import com.example.sdk.runtime.ApiKeyAuth;
import com.example.sdk.runtime.ApiKeyLocation;

new ApiKeyAuth("sk-abc123", "X-API-Key", ApiKeyLocation.HEADER);

Kotlin

import com.example.sdk.runtime.ApiKeyAuth
import com.example.sdk.runtime.ApiKeyLocation

ApiKeyAuth("sk-abc123", "X-API-Key", ApiKeyLocation.HEADER)

TypeScript

TypeScript handles API keys through the apiKey field on ConfigurationParameters, which supports the same string | Promise<string> | ((name: string) => string | Promise<string>) union as accessToken. Because the wire placement (header name, query parameter, or cookie) depends on the OpenAPI security scheme definition, the key is available for use in custom middleware rather than being auto-wired:

const config = new Configuration({
  basePath: "https://api.example.com",
  apiKey: (name) => getApiKey(name),  // called with the scheme name
});

Dynamic Key Provider

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.ApiKeyAuth{
        KeyProvider: func() string {
            return getCurrentApiKey()  // called per-request
        },
        Name:     "X-API-Key",
        Location: runtime.APIKeyInHeader,
    }),
)

Rust

#![allow(unused)]
fn main() {
let client = Client::new("https://api.example.com")
    .with_auth(ApiKeyAuth::from_provider("X-API-Key", || {
        get_current_api_key()  // called per-request
    }));
}

Python

client = Client(
    base_url="https://api.example.com",
    authenticator=ApiKeyAuth(
        header_name="X-API-Key",
        api_key=lambda: get_current_api_key(),  # called per-request
    ),
)

Java

new ApiKeyAuth(() -> getCurrentApiKey(), "X-API-Key", ApiKeyLocation.HEADER);

Kotlin

ApiKeyAuth({ getCurrentApiKey() }, "X-API-Key", ApiKeyLocation.HEADER)

HTTP Basic Authentication

BasicAuth sends a base64-encoded username:password pair. Available in Go and TypeScript; for other languages, implement a custom Authenticator.

Static Credentials

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BasicAuth{
        Username: "alice",
        Password: "s3cret",
    }),
)

TypeScript

const config = new Configuration({
  basePath: "https://api.example.com",
  username: "alice",
  password: "s3cret",
});

Dynamic Credentials

Go

client := runtime.NewClient("https://api.example.com",
    runtime.WithAuth(runtime.BasicAuth{
        UsernameProvider: func() string { return getCurrentUser() },
        PasswordProvider: func() string { return getCurrentPass() },
    }),
)

TypeScript

const config = new Configuration({
  basePath: "https://api.example.com",
  username: () => getCurrentUser(),
  password: () => getCurrentPass(),
});

The username and password fields accept string | (() => string | Promise<string>). A plain function is called synchronously; an async function is awaited. Basic auth is only applied when no Authorization header has already been set by accessToken.

Custom Authenticators

Every generator’s Authenticator is an open interface — you can implement it for custom auth schemes without modifying the generated code.

TypeScript

Use middleware:

const api = new DefaultApi(config).withPreMiddleware({
  pre: async (ctx) => {
    ctx.init.headers = { ...ctx.init.headers, 'X-Custom': 'value' };
    return ctx;
  },
});

Go

type myAuth struct{}

func (myAuth) AuthenticateRequest(req *http.Request) error {
    req.Header.Set("X-Custom", "value")
    return nil
}

Rust

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
struct MyAuth;

impl Authenticator for MyAuth {
    fn authenticate(&self, headers: &mut HeaderMap) -> Result<(), Error> {
        headers.insert(
            HeaderName::from_static("x-custom"),
            HeaderValue::from_static("value"),
        );
        Ok(())
    }
}
}

Python

class MyAuth(Authenticator):
    def auth_headers(self) -> dict[str, str]:
        return {"X-Custom": "value"}

Java

public class MyAuth implements Authenticator {
    @Override
    public void authenticate(Request.Builder builder) {
        builder.header("X-Custom", "value");
    }
}

Kotlin

class MyAuth : Authenticator {
    override fun authenticate(builder: Request.Builder) {
        builder.header("X-Custom", "value")
    }
}