@@ -502,6 +502,102 @@ s = UnstructuredClient(debug_logger=logging.getLogger("unstructured_client"))
502502
503503<!-- Placeholder for Future Speakeasy SDK Sections -->
504504
505+ ## Authentication with Client Secrets
506+
507+ > Available from SDK version ** X.Y.Z** (first release carrying the
508+ > ` unstructured_client.auth ` module).
509+
510+ If you are running against an Unstructured deployment that issues ** client
511+ secrets** (` uns_sk_... ` ) — e.g. Dedicated Instances or self-hosted
512+ clusters with ` DEPLOYMENT_MODE=dedicated ` on account-service — the SDK
513+ can transparently exchange that secret for a short-lived JWT, cache it,
514+ refresh it before expiry, and send it on every request as
515+ ` Authorization: Bearer <jwt> ` .
516+
517+ ### Synchronous usage
518+
519+ ``` python
520+ from unstructured_client import UnstructuredClient
521+ from unstructured_client.auth import ClientCredentials
522+
523+ client = UnstructuredClient(
524+ api_key_auth = ClientCredentials(
525+ client_secret = " uns_sk_..." ,
526+ server_url = " https://accounts.unstructuredapp.io" , # account-service base URL
527+ ),
528+ server_url = " https://platform.unstructuredapp.io" , # platform-api / core-product
529+ )
530+
531+ # Every operation automatically carries Authorization: Bearer <jwt>.
532+ client.general.partition(... )
533+ ```
534+
535+ ### Asynchronous usage
536+
537+ ``` python
538+ import asyncio
539+ from unstructured_client import UnstructuredClient
540+ from unstructured_client.auth import AsyncClientCredentials
541+
542+ async def main () -> None :
543+ auth = AsyncClientCredentials(
544+ client_secret = " uns_sk_..." ,
545+ server_url = " https://accounts.unstructuredapp.io" ,
546+ )
547+ async with UnstructuredClient(api_key_auth = auth) as client:
548+ await client.general.partition_async(... )
549+
550+ asyncio.run(main())
551+ ```
552+
553+ ### Legacy API-key bridge
554+
555+ For deployments still using legacy api-tracking keys, the same machinery
556+ is available through ` LegacyKeyExchange ` / ` AsyncLegacyKeyExchange ` . It
557+ hits the same ` /auth/token-exchange ` endpoint with
558+ ` grant_type=api_key ` and is intentionally transitional — migrate to
559+ ` ClientCredentials ` once client secrets are provisioned.
560+
561+ ``` python
562+ from unstructured_client.auth import LegacyKeyExchange
563+
564+ client = UnstructuredClient(
565+ api_key_auth = LegacyKeyExchange(
566+ api_key = " your-legacy-uns_ak-key" ,
567+ server_url = " https://accounts.unstructuredapp.io" ,
568+ ),
569+ )
570+ ```
571+
572+ ### Behavior and tuning
573+
574+ - ** Caching:** JWTs are held in-memory and reused until
575+ ` refresh_buffer_seconds ` (default ** 60s** ) before absolute expiry.
576+ - ** Concurrency:** sync callers share a ` threading.Lock ` , async callers
577+ share an ` asyncio.Lock ` . Ten concurrent requests on a cold cache drive
578+ exactly one exchange.
579+ - ** Retries:** 5xx and network errors retry with exponential backoff
580+ (default ` max_retries=3 ` ). ` 400 ` / ` 401 ` fail fast with
581+ ` TokenExchangeError ` / ` InvalidCredentialError ` .
582+ - ** Outage fallback:** if account-service is unreachable * and* a cached
583+ token is still within its absolute TTL, the cached token is returned
584+ and a warning is logged on ` unstructured-client.auth ` .
585+ - ** Disabled exchange:** when the server responds with
586+ ` token_exchange_enabled=False ` , the call raises
587+ ` TokenExchangeDisabledError ` — that deployment expects the plain
588+ ` api_key_auth="..." ` string form instead.
589+
590+ ### Backward compatibility
591+
592+ Passing a plain string still works exactly as before:
593+
594+ ``` python
595+ client = UnstructuredClient(api_key_auth = " your-key" )
596+ ```
597+
598+ In that case the SDK sends ` unstructured-api-key: your-key ` without any
599+ token exchange, identical to pre-` auth ` SDK versions.
600+
505601### Maturity
506602
507603This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage
0 commit comments