--- title: Client settings | Stainless description: Configure your SDK's client level settings, including authentication, custom arguments, default headers, retries with exponential backoff, timeouts, idempotency keys, and file uploads. --- ## Authentication [\[reference\]](/docs/reference/config#client-opt/index.md) The Stainless Generator defines your SDK’s authentication using the [`#/security` and `#/components/securitySchemes`](https://swagger.io/docs/specification/authentication/) particulars from your OpenAPI spec. By default, Stainless SDKs are set to authenticate using an environment variable: ``` client_settings: opts: auth_token: type: string # Whether this client option is required to instantiate the client: nullable: false # Whether this value should be read from an env: read_env: ORG_AUTH_TOKEN auth: { security_scheme: BearerAuth } # optional, overrides the OpenAPI spec's top-level security key, required if it isn't present security: - BearerAuth: [] ``` For more complicated authentication schemes, or should the Stainless Generator fail to configure yours correctly, see the examples below. The Stainless generator uses the top-level `security` as the security configuration supported by the SDKs, but you may want to specify a different combination of `security` than the one used in your OpenAPI spec. The `security` and `security_schemes` in the Stainless config overrides the values in the spec. HTTP Bearer `Authorization: Bearer ` The [HTTP Bearer](https://swagger.io/docs/specification/authentication/bearer-authentication/) authentication method is configured like so: ``` # OpenAPI components: security_schemes: MyBearerAuth: type: http scheme: bearer # optional, documentation purpose only bearerFormat: JWT security: - MyBearerAuth: {} ``` ``` # Stainless config client_settings: opts: my_bearer_token: # or `token`, `bearer_token`, `api_key`, etc. type: string read_env: ORG_BEARER_TOKEN auth: { security_scheme: MyBearerAuth } ``` API Key `
: ` An [API key in a header](https://swagger.io/docs/specification/authentication/api-keys/) authentication method is configured like so: ``` # OpenAPI components: security_schemes: MyApiKeyAuth: type: apiKey name: My-Api-Key in: header security: - MyApiKeyAuth: {} ``` ``` # Stainless config client_settings: opts: my_api_key: # or `token`, `auth_token`, etc. type: string read_env: ORG_API_KEY_TOKEN auth: { security_scheme: MyApiKeyAuth } ``` HTTP Basic `Authorization: Basic ` The [HTTP Basic](https://swagger.io/docs/specification/authentication/basic-authentication/) authentication method is configured like so: ``` # OpenAPI components: security_schemes: MyBasicAuth: type: http scheme: basic security: - MyBasicAuth: {} ``` ``` # Stainless config client_settings: opts: my_username: type: string read_env: ORG_MY_USERNAME_TOKEN auth: { security_scheme: MyBasicAuth, role: 'username' } my_password: type: string read_env: ORG_MY_PASSWORD_TOKEN auth: { security_scheme: MyBasicAuth, role: 'password' } ``` OAuth 2.0 Client Credentials Stainless fully supports OAuth `client_credentials`. For this grant type, our SDKs handle initial authorization and the entire token management lifecycle. Stainless uses the [OAuth configuration in your OpenAPI spec](https://swagger.io/docs/specification/v3_0/authentication/oauth2/) if present, or you can specify an OAuth configuration in your Stainless config. Example security configuration in the Stainless config: ``` security: - OAuth2: [] security_schemes: OAuth2: type: oauth2 flows: clientCredentials: tokenUrl: >- https://example.com/oauth2/token?grant_type=client_credentials scopes: # ... ``` You must also define client options for the `client_id` and `client_secret` parameters in your Stainless config so users of your SDKs can provide those values. The names of these parameters in `opts` can be customized; the important part is to specify the correct `auth` information for each (especially `auth.role`, which must be either `client_id` or `client_secret`). ``` client_settings: opts: client_id: type: string auth: security_scheme: OAuth2 role: client_id read_env: ORG_CLIENT_ID client_secret: type: string auth: security_scheme: OAuth2 role: client_secret read_env: ORG_CLIENT_SECRET ``` With a configuration like the one above, users can provide a `client_id` and `client_secret` when initializing your SDK to use OAuth. Behind the scenes, the SDK will fetch an access token from the configured `tokenUrl` when the first request is made, cache it, and use it for all following requests until the token expires. Upon expiration, the SDK will automatically obtain a new token. Failed OAuth requests are automatically retried based on [the retry configuration for the SDK](https://www.stainless.com/docs/configure/client#retries). If all retries fail, an exception will be thrown or an error will be returned (whichever makes sense for the particular language being used). Please [reach out](mailto:support@stainless.com) if you need help supporting your configuration. OAuth 2.0 Authorization Codes If you’re using authorization codes, we recommend you set up Bearer Authentication and add custom code to help your users convert authorization codes to access tokens. If you’re interested in generated helpers for this, or if you need additional guidance, [reach out and let us know](mailto:support@stainless.com)! With this approach, initial authorization and token management are not handled by Stainless. We recommend you point your users to [an OAuth SDK](https://oauth.net/code/) in their preferred language for handling these parts of the OAuth flow. Once Stainless is configured to use Bearer Authentication, as seen in the example below, users of your SDKs will be able to authenticate with their access token. OpenAPI spec: ``` securitySchemes: OAuth2: type: oauth2 flows: authorizationCode: authorizationUrl: https://example.com/oauth2/auth tokenUrl: https://example.com/oauth2/token scopes: # ... ``` Stainless config: ``` client_settings: opts: access_token: type: string auth: security_scheme: BearerAuth read_env: MY_TEAM_ACCESS_TOKEN security: - BearerAuth: [] security_schemes: BearerAuth: type: http scheme: bearer ``` Please [reach out](mailto:support@stainless.com) if you need help supporting your configuration. Optional Auth To specify that you accept no authentication, declare a security configuration with no key and no properties like so: ``` security: - BearerAuth: {} - {} # <= No auth ``` Multiple API Keys If your API requires different keys for different endpoints, you can configure multiple security schemes in your OpenAPI spec and corresponding client options in your Stainless config: ``` # OpenAPI components: securitySchemes: ReadKeyAuth: type: apiKey in: header name: X-Read-Api-Key WriteKeyAuth: type: apiKey in: header name: X-Write-Api-Key security: - ReadKeyAuth: [] - WriteKeyAuth: [] ``` ``` # Stainless config client_settings: opts: read_key: type: string nullable: true auth: security_scheme: ReadKeyAuth read_env: READ_API_KEY write_key: type: string nullable: true auth: security_scheme: WriteKeyAuth read_env: WRITE_API_KEY ``` The generated SDK accepts multiple keys during initialization. When both keys are provided, all configured auth credentials are sent with each request: - [TypeScript](#tab-panel-0) - [Python](#tab-panel-1) - [Go](#tab-panel-2) ``` const client = new MyAPI({ readKey: 'read_key_123', writeKey: 'write_key_456', }); // Both keys are sent with requests client.resources.list(); client.resources.create({...}); ``` ``` client = MyAPI( read_key="read_key_123", write_key="write_key_456", ) # Both keys are sent with requests client.resources.list() client.resources.create(...) ``` ``` client := myapi.NewClient( option.WithReadKey("read_key_123"), option.WithWriteKey("write_key_456"), ) // Both keys are sent with requests client.Resources.List(ctx) client.Resources.New(ctx, ...) ``` ### Extra client arguments [\[reference\]](/docs/reference/config#client-opt/index.md) You can define extra client arguments, which generally appears as an extra argument on the client constructor of each SDK (in Go, it appears as an extra `RequestOption`). These are generally used for supplying values for [authentication methods](#authentication), but can be also used for extra headers and more. ``` client_settings: opts: pet_store_version: type: string # can be a string, boolean, or a number nullable: true # makes this an optional argument default: v3 # the default pet store version to use read_env: PETSTORE_VERSION send_in_header: 'X-Petstore-Version' ``` ``` const client = new Petstore({ apiKey: '...', petStoreVersion: 'v2', // sends 'X-Petstore-Version: v2' }); ``` ### Default headers [\[reference\]](/docs/reference/config#client-settings/index.md) Default headers are headers we add to every request made by the SDK. We send platform headers so that you can collect metrics on the languages and platforms your users use. For all SDKs, we send the following: | Headers | Description | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `X-Stainless-Arch` | The architecture, such as `x32`, `x64`, `arm`, `aarch64`, or `other:xxx`. | | `X-Stainless-Lang` | The language, such as `typescript`, `python`, `java`, `kotlin`, or `go`. | | `X-Stainless-OS` | The OS, such as `Android`, `MacOS`, `Windows`, `FreeBSD`, `OpenBSD`, `Linux`, or `Other:xxx`. | | `X-Stainless-Package-Version` | The package version, such as `v2.3.1`. | | `X-Stainless-Read-Timeout` | The timeout, in seconds, between receiving response chunks, such as `3`. Not sent if no read timeout is configured. | | `X-Stainless-Retry-Count` | Which retry number the request is for, such as `0` for the first request, `1` for the first retry, `2` for the second retry, and so on. | | `X-Stainless-Runtime` | The runtime, such as `node` or `CPython`. | | `X-Stainless-Runtime-Version` | The runtime version, such as `v14.8.0`. | | `X-Stainless-Timeout` | The timeout, in seconds, for the entire request, such as `10`. Not sent if no overall timeout is configured. | We also send some extra headers for each language: | Python Headers | Description | | ------------------- | ------------------------------------------ | | `X-Stainless-Async` | Whether or not the `AsyncClient` was used. | | Java/Kotlin Headers | Description | | ------------------------ | ------------------------------- | | `X-Stainless-OS-Version` | The OS version, such as `14.4`. | For requests made by a Stainless-generated MCP server, we will also send some extra headers: | MCP Headers | Description | | ----------------- | -------------- | | `X-Stainless-MCP` | Always `true`. | ### Retries Our clients retry connection errors (for example, a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors. By default, our clients retry 2 times (so a total of 3 requests) using the [exponential backoff strategy](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/) with an initial delay of 0.5s and a max delay of 8s. We also add a jitter of 25% to spread out requests. This can be configured by you for your users: ``` client_settings: default_retries: # 5 retries are made, with the interval [1, 2, 4, 8, 10 (capped by the max)] # not accounting for jitter max_retries: 5 initial_delay_seconds: 1 max_delay_seconds: 10 ``` Or it can be changed by the user in each language’s SDK: ``` client = new Petstore({ maxRetry: 3, }); ``` Each request includes an `X-Stainless-Retry-Count` header so you know how often clients retry. See [Default headers](#default-headers) for details. #### Disabling retries Retries can be disabled in two ways. Your users can disable this at at the client level by setting max\_retries to 0. For example: ``` client = new Petstore({ maxRetry: 0, // Doesn't retry at all }); ``` Alternatively, your API can direct our SDKs to not retry by sending the [`X-Should-Retry`](#x-should-retry) header in your responses. #### `Retry-After` and `Retry-After-Ms` Our SDKs also respect [the `Retry-After` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) sent by the API, which defines in integers how many seconds we should wait before making another request. We also support the `Retry-After-Ms` header which is less standard but gives more fine-grained control over timings in milliseconds. The clients only respect values that are “reasonable” which are positive values less than a minute. #### `X-Should-Retry` Additionally, the clients support the `X-Should-Retry` header, which can be used to explicitly control whether a request should be retried. This header must be explicitly set to either `X-Should-Retry: true` or `X-Should-Retry: false` to be used as an override. When set to `true`, it forces a retry attempt even if the request would not normally be retried based on the default retry rules. When set to `false`, it prevents a retry attempt even if the request would normally be retried. If the header is not present or set to any other value, the default retry behavior is used. We recommend using the header over other methods to control the retry behavior on special status codes or other situations specific to your API, as it can be used by all consumers of the API and can be configured independently of the version of the SDK. ### Timeouts [\[reference\]](/docs/reference/config#client-settings/index.md) In addition to retries, our clients also have a default timeout of 60 seconds, which can be configured. ``` client_settings: default_timeout: PT60S # ISO8601 or number of milliseconds. This is 60 seconds ``` ### Idempotency key [\[reference\]](/docs/reference/config#client-settings/index.md) [Idempotency Keys](https://stripe.com/docs/api/idempotent_requests) can prevent errors where multiple retried requests are interpreted as separate requests. Our clients [retry connection errors and certain status codes](#retries) by default to create robust integrations, so we recommend that your API supports idempotency keys, especially for critical endpoints. You can configure idempotency keys by specifying `client_settings.idempotency` like so: ``` client_settings: idempotency: header: 'Idempotency-Key' # or a header you prefer, like 'X-Request-Id' ``` We send the configured header with a value in the format `stainless-retry-{random_uuid}` on all non-`GET` requests. This header is also possible to override in every SDK that we generate. ### File uploads Our SDKs support file uploads out of the box, via `multipart/form-data` requests. File parameters can be defined in the OpenAPI spec by specifying a `multipart/form-data` request with parameters that are `type: string` and `format: binary`. ``` paths: /files: post: summary: Upload a file requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary description: The file to upload file_metadata: type: string description: > Some other property that you can add, serialized as a field in multipart/form-data required: - file responses: '200': description: File uploaded successfully ``` Each SDK provides convenient ways to handle file uploads appropriate for that language. Below is an example in TypeScript: ``` await client.files.create({ file: fs.createReadStream('./local-file.txt') }); // or await client.files.create({ file: new File(['my bytes'], 'content.txt') }); ``` Similar helpers exist in other languages. For example, in Python: ``` with open('content.txt', 'rb') as f: client.files.create(file=f) ``` See the README.md of each SDK for language-specific documentation.