---
editLink: false
lastUpdated: false
outline: [2, 3]
---

<!-- Generated by python/b2c-tooling-sdk/scripts/generate_api_docs.py. Do not edit. -->

# b2c_tooling_sdk.auth

Authentication strategies and helpers for the B2C tooling SDK.

Mirrors the `@salesforce/b2c-tooling-sdk/auth` subpath export. Each strategy
implements the [`AuthStrategy`](/python/api/auth#authstrategy) protocol (an async `fetch` that injects
credentials and handles retry/refresh). The persistent session store here reads
and writes the *same* `auth-sessions.json` file as the B2C CLI, so tokens are
shared across the Python and TypeScript tooling.

## Classes

### AccessTokenResponse {#accesstokenresponse}

```python
class AccessTokenResponse
```

Access token response from Account Manager.

**Fields**

| Name | Type |
| --- | --- |
| `access_token` | `str` |
| `expires` | `datetime` |
| `scopes` | `list[str]` |

### DecodedJWT {#decodedjwt}

```python
class DecodedJWT
```

A decoded (unverified) JWT.

**Fields**

| Name | Type |
| --- | --- |
| `header` | `dict[str, Any]` |
| `payload` | `dict[str, Any]` |

### AuthStrategy {#authstrategy}

```python
class AuthStrategy(Protocol)
```

Protocol implemented by every authentication strategy.

Implementations must inject the auth header and handle their own 401
retry/refresh inside `fetch`.

#### fetch <Badge type="info" text="method" /> {#authstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, **kwargs: Any) -> httpx.Response
```

Perform an authenticated request and return the response.

### ScopedAuthStrategy {#scopedauthstrategy}

```python
class ScopedAuthStrategy(AuthStrategy, Protocol)
```

An [`AuthStrategy`](/python/api/auth#authstrategy) that can also mint/return tokens and manage scopes.

#### get_authorization_header <Badge type="info" text="method" /> {#scopedauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the full `Authorization` header value (e.g. `Bearer ...`).

#### invalidate_token <Badge type="info" text="method" /> {#scopedauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Invalidate the cached token, forcing re-auth on the next request.

#### with_additional_scopes <Badge type="info" text="method" /> {#scopedauthstrategy-with-additional-scopes}

```python
def with_additional_scopes(additional_scopes: list[str]) -> ScopedAuthStrategy
```

Return a copy of this strategy with `additional_scopes` merged in.

#### get_access_token_for_cascade <Badge type="info" text="method" /> {#scopedauthstrategy-get-access-token-for-cascade}

```python
async def get_access_token_for_cascade(candidates: list[list[str]]) -> str
```

Resolve a scope cascade, returning the first token Account Manager accepts.

### BasicAuthConfig {#basicauthconfig}

```python
class BasicAuthConfig
```

Basic authentication (username / access-key). Used for WebDAV.

**Fields**

| Name | Type |
| --- | --- |
| `username` | `str` |
| `password` | `str` |

### OAuthAuthConfig {#oauthauthconfig}

```python
class OAuthAuthConfig
```

OAuth authentication configuration for OCAPI / platform APIs.

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `client_id` | `str` |  |
| `client_secret` | `str \| None` | `None` |
| `scopes` | `list[str] \| None` | `None` |
| `account_manager_host` | `str \| None` | `None` |
| `jwt_cert_path` | `str \| None` | `None` |
| `jwt_key_path` | `str \| None` | `None` |
| `jwt_passphrase` | `str \| None` | `None` |
| `redirect_uri` | `str \| None` | `None` |
| `open_browser` | `Callable[[str], Awaitable[None]] \| None` | `None` |

### ApiKeyAuthConfig {#apikeyauthconfig}

```python
class ApiKeyAuthConfig
```

API key authentication (MRT and external services).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `key` | `str` |  |
| `header_name` | `str \| None` | `None` |

### AuthConfig {#authconfig}

```python
class AuthConfig
```

Combined authentication configuration used by [`B2CInstance`](/python/api/instance#b2cinstance).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `basic` | `BasicAuthConfig \| None` | `None` |
| `oauth` | `OAuthAuthConfig \| None` | `None` |
| `api_key` | `ApiKeyAuthConfig \| None` | `None` |
| `auth_methods` | `list[AuthMethod] \| None` | `None` |

### AuthCredentials {#authcredentials}

```python
class AuthCredentials
```

Flat credential bundle accepted by [`resolve_auth_strategy`](/python/api/auth#resolve-auth-strategy).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `client_id` | `str \| None` | `None` |
| `client_secret` | `str \| None` | `None` |
| `scopes` | `list[str] \| None` | `None` |
| `account_manager_host` | `str \| None` | `None` |
| `username` | `str \| None` | `None` |
| `password` | `str \| None` | `None` |
| `api_key` | `str \| None` | `None` |
| `api_key_header_name` | `str \| None` | `None` |
| `redirect_uri` | `str \| None` | `None` |
| `open_browser` | `Callable[[str], Awaitable[None]] \| None` | `None` |
| `extra` | `dict[str, Any]` | `field(default_factory=dict)` |

### OAuthStrategy {#oauthstrategy}

```python
class OAuthStrategy
```

OAuth 2.0 client-credentials authentication strategy.

:example:

```python
from b2c_tooling_sdk.auth import OAuthStrategy

auth = OAuthStrategy(OAuthConfig(
    client_id="your-client-id",
    client_secret="your-client-secret",
    scopes=["sfcc.products"],
))
response = await auth.fetch("https://api.example.com/products")
```

#### fetch <Badge type="info" text="method" /> {#oauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform an authenticated request, injecting a bearer token and retrying once on a post-success 401.

#### get_authorization_header <Badge type="info" text="method" /> {#oauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header value (`Bearer <token>`).

#### get_jwt <Badge type="info" text="method" /> {#oauthstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded (unverified) access-token JWT.

#### get_token_response <Badge type="info" text="method" /> {#oauthstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the full token response (token + expiry + scopes), using the cache when valid.

#### invalidate_token <Badge type="info" text="method" /> {#oauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Invalidate every cached token for this client/method/AM-host identity.

#### with_additional_scopes <Badge type="info" text="method" /> {#oauthstrategy-with-additional-scopes}

```python
def with_additional_scopes(additional_scopes: list[str]) -> OAuthStrategy
```

Return a new strategy with `additional_scopes` merged into the configured scopes.

#### get_access_token_for_cascade <Badge type="info" text="method" /> {#oauthstrategy-get-access-token-for-cascade}

```python
async def get_access_token_for_cascade(candidates: list[list[str]]) -> str
```

Resolve a scope cascade, returning the first token AM accepts.

Each candidate is merged with this strategy's base scopes. Pass 1 scans the
cache for a token satisfying any candidate; pass 2 requests each candidate
from AM in order, skipping `invalid_scope` rejections and rethrowing anything else.

### OAuthConfig {#oauthconfig}

```python
class OAuthConfig
```

Configuration for [`OAuthStrategy`](/python/api/auth#oauthstrategy) (client-credentials grant).

### JwtOAuthStrategy {#jwtoauthstrategy}

```python
class JwtOAuthStrategy
```

OAuth 2.0 JWT Bearer authentication strategy (RFC 7523).

Differs from client credentials: uses a public/private key pair instead of a
secret, sends a self-signed short-lived JWT as `client_assertion` in the POST
body, and shares the module-level token cache under the `jwt` method.

#### fetch <Badge type="info" text="method" /> {#jwtoauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with JWT Bearer auth, retrying once on a post-success 401.

#### get_authorization_header <Badge type="info" text="method" /> {#jwtoauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header value (`Bearer <token>`).

#### get_jwt <Badge type="info" text="method" /> {#jwtoauthstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded (unverified) access-token JWT.

#### get_token_response <Badge type="info" text="method" /> {#jwtoauthstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the full token response, using the cache when valid.

#### invalidate_token <Badge type="info" text="method" /> {#jwtoauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Evict every cached token for this client/AM-host JWT identity.

#### with_additional_scopes <Badge type="info" text="method" /> {#jwtoauthstrategy-with-additional-scopes}

```python
def with_additional_scopes(additional_scopes: list[str]) -> JwtOAuthStrategy
```

Return a new strategy with `additional_scopes` merged into the configured scopes.

#### get_access_token_for_cascade <Badge type="info" text="method" /> {#jwtoauthstrategy-get-access-token-for-cascade}

```python
async def get_access_token_for_cascade(candidates: list[list[str]]) -> str
```

Resolve a scope cascade for the JWT flow (mirrors [`OAuthStrategy.get_access_token_for_cascade`](/python/api/auth#oauthstrategy-get-access-token-for-cascade)).

### JwtOAuthConfig {#jwtoauthconfig}

```python
class JwtOAuthConfig
```

Configuration for [`JwtOAuthStrategy`](/python/api/auth#jwtoauthstrategy).

### PkceOAuthStrategy {#pkceoauthstrategy}

```python
class PkceOAuthStrategy
```

OAuth 2.0 Authorization Code Flow with PKCE (public clients).

#### fetch <Badge type="info" text="method" /> {#pkceoauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with PKCE auth, retrying once on a post-success 401.

#### get_authorization_header <Badge type="info" text="method" /> {#pkceoauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header value (`Bearer <token>`).

#### get_jwt <Badge type="info" text="method" /> {#pkceoauthstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded (unverified) access-token JWT.

#### get_token_response <Badge type="info" text="method" /> {#pkceoauthstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the full token response, refreshing or running the browser flow as needed.

#### invalidate_token <Badge type="info" text="method" /> {#pkceoauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Drop only the cached access token; the refresh token is preserved for silent renewal.

### PkceOAuthConfig {#pkceoauthconfig}

```python
class PkceOAuthConfig
```

Configuration for the OAuth Authorization Code + PKCE flow.

### PkceGrantUnsupportedError {#pkcegrantunsupportederror}

```python
class PkceGrantUnsupportedError(Exception)
```

Raised when the Authorization Code + PKCE flow fails because the client is
not registered for that grant (e.g. a legacy implicit-only public client or a
missing/mismatched redirect URI) rather than a transient or user-driven failure.

[`PkceWithImplicitFallbackStrategy`](/python/api/auth#pkcewithimplicitfallbackstrategy)
keys its automatic fallback off this type so it retries with the legacy implicit
flow ONLY for grant/registration failures — never for user-cancel, state
mismatch, or a port-in-use error.

### PkceWithImplicitFallbackStrategy {#pkcewithimplicitfallbackstrategy}

```python
class PkceWithImplicitFallbackStrategy
```

Wraps a [`PkceOAuthStrategy`](/python/api/auth#pkceoauthstrategy), falling back to implicit on a grant error.

#### fetch <Badge type="info" text="method" /> {#pkcewithimplicitfallbackstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Fetch via PKCE, falling back to implicit on a grant-unsupported error.

#### get_authorization_header <Badge type="info" text="method" /> {#pkcewithimplicitfallbackstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header, falling back to implicit on a grant error.

#### get_jwt <Badge type="info" text="method" /> {#pkcewithimplicitfallbackstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded access-token JWT, falling back to implicit on a grant error.

#### get_token_response <Badge type="info" text="method" /> {#pkcewithimplicitfallbackstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the full token response, falling back to implicit on a grant error.

#### invalidate_token <Badge type="info" text="method" /> {#pkcewithimplicitfallbackstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Invalidate cached tokens on both the PKCE and (if present) implicit strategies.

### ImplicitOAuthStrategy {#implicitoauthstrategy}

```python
class ImplicitOAuthStrategy
```

OAuth 2.0 Implicit Grant flow (deprecated; public clients only).

#### fetch <Badge type="info" text="method" /> {#implicitoauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with implicit-flow auth, retrying once on a post-success 401.

#### get_authorization_header <Badge type="info" text="method" /> {#implicitoauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header value (`Bearer <token>`).

#### get_jwt <Badge type="info" text="method" /> {#implicitoauthstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded (unverified) access-token JWT.

#### get_token_response <Badge type="info" text="method" /> {#implicitoauthstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the full token response, running the browser flow when the cache is stale.

#### invalidate_token <Badge type="info" text="method" /> {#implicitoauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Invalidate the cached token, forcing re-authentication on the next request.

### ImplicitOAuthConfig {#implicitoauthconfig}

```python
class ImplicitOAuthConfig
```

Configuration for the legacy implicit OAuth flow.

### StatefulOAuthStrategy {#statefuloauthstrategy}

```python
class StatefulOAuthStrategy
```

Auth strategy that uses a persisted access token from the unified store.

No refresh — on expiry/401, the session is cleared and the caller is expected
to re-authenticate.

#### fetch <Badge type="info" text="method" /> {#statefuloauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with the stored token; on 401 clear the session.

#### get_authorization_header <Badge type="info" text="method" /> {#statefuloauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization` header value (`Bearer <token>`).

#### get_token_response <Badge type="info" text="method" /> {#statefuloauthstrategy-get-token-response}

```python
async def get_token_response() -> AccessTokenResponse
```

Return the current token as an [`AccessTokenResponse`](/python/api/auth#accesstokenresponse) (expires/scopes from the JWT).

#### get_jwt <Badge type="info" text="method" /> {#statefuloauthstrategy-get-jwt}

```python
async def get_jwt() -> DecodedJWT
```

Return the decoded (unverified) access-token JWT.

#### invalidate_token <Badge type="info" text="method" /> {#statefuloauthstrategy-invalidate-token}

```python
def invalidate_token() -> None
```

Delete the persisted session and blank the in-memory access token.

### StatefulOAuthStrategyOptions {#statefuloauthstrategyoptions}

```python
class StatefulOAuthStrategyOptions
```

Options for [`StatefulOAuthStrategy`](/python/api/auth#statefuloauthstrategy) (kept for API parity with the TS SDK).

### BasicAuthStrategy {#basicauthstrategy}

```python
class BasicAuthStrategy
```

Basic authentication strategy.

:example:

```python
from b2c_tooling_sdk.auth import BasicAuthStrategy

auth = BasicAuthStrategy("username", "access-key")
response = await auth.fetch("https://webdav.example.com/path")
```

#### fetch <Badge type="info" text="method" /> {#basicauthstrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with the `Authorization: Basic` header set.

#### get_authorization_header <Badge type="info" text="method" /> {#basicauthstrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the `Authorization: Basic` header value.

### ApiKeyStrategy {#apikeystrategy}

```python
class ApiKeyStrategy
```

API key authentication strategy.

:example:

```python
# MRT API (Bearer token) -> Authorization: Bearer {key}
auth = ApiKeyStrategy(api_key, "Authorization")

# Custom header -> x-api-key: {key}
auth = ApiKeyStrategy(api_key, "x-api-key")
```

#### fetch <Badge type="info" text="method" /> {#apikeystrategy-fetch}

```python
async def fetch(url: str, *, method: str = 'GET', headers: dict[str, str] | None = None, content: Any = None, dispatcher: httpx.AsyncBaseTransport | None = None, **kwargs: Any) -> httpx.Response
```

Perform a request with the API-key header set.

#### get_authorization_header <Badge type="info" text="method" /> {#apikeystrategy-get-authorization-header}

```python
async def get_authorization_header() -> str
```

Return the header value (`Bearer {key}` for Authorization, else the raw key).

### AvailableAuthMethods {#availableauthmethods}

```python
class AvailableAuthMethods
```

Result of checking which auth methods have credentials available.

**Fields**

| Name | Type |
| --- | --- |
| `available` | `list[AuthMethod]` |
| `unavailable` | `list[UnavailableAuthMethod]` |

### UnavailableAuthMethod {#unavailableauthmethod}

```python
class UnavailableAuthMethod
```

A method that is missing at least one required credential.

**Fields**

| Name | Type |
| --- | --- |
| `method` | `AuthMethod` |
| `reason` | `str` |

### AuthMiddleware {#authmiddleware}

```python
class AuthMiddleware(Protocol)
```

Middleware for authentication requests (analogous to openapi-fetch middleware).

#### on_request <Badge type="info" text="method" /> {#authmiddleware-on-request}

```python
async def on_request(request: httpx.Request) -> httpx.Request | None
```

Called before the auth request is sent; may mutate or replace it.

#### on_response <Badge type="info" text="method" /> {#authmiddleware-on-response}

```python
async def on_response(request: httpx.Request, response: httpx.Response) -> httpx.Response | None
```

Called after the auth response is received; may mutate or replace it.

### AuthMiddlewareProvider {#authmiddlewareprovider}

```python
class AuthMiddlewareProvider(Protocol)
```

Supplies [`AuthMiddleware`](/python/api/auth#authmiddleware) for auth requests.

**Fields**

| Name | Type |
| --- | --- |
| `name` | `str` |

#### get_middleware <Badge type="info" text="method" /> {#authmiddlewareprovider-get-middleware}

```python
def get_middleware() -> AuthMiddleware | None
```

Return middleware to apply, or `None` to skip.

### AuthMiddlewareRegistry {#authmiddlewareregistry}

```python
class AuthMiddlewareRegistry
```

Collects middleware from providers, returning them in registration order.

**Fields**

| Name | Type | Description |
| --- | --- | --- |
| `size` | `int` | Number of registered providers. |

#### register <Badge type="info" text="method" /> {#authmiddlewareregistry-register}

```python
def register(provider: AuthMiddlewareProvider) -> None
```

Register a middleware provider.

#### unregister <Badge type="info" text="method" /> {#authmiddlewareregistry-unregister}

```python
def unregister(name: str) -> bool
```

Remove a provider by name; return `True` if one was removed.

#### get_middleware <Badge type="info" text="method" /> {#authmiddlewareregistry-get-middleware}

```python
def get_middleware() -> list[AuthMiddleware]
```

Collect middleware from all providers, in registration order.

#### clear <Badge type="info" text="method" /> {#authmiddlewareregistry-clear}

```python
def clear() -> None
```

Clear all registered providers (primarily for testing).

#### get_provider_names <Badge type="info" text="method" /> {#authmiddlewareregistry-get-provider-names}

```python
def get_provider_names() -> list[str]
```

Return the names of all registered providers.

### AuthSession {#authsession}

```python
class AuthSession
```

One persisted authentication session, keyed by `client_id`.

Field names are snake_case in Python but serialize to the camelCase keys the
TypeScript SDK writes (`clientId`, `accessToken`, `refreshToken`, ...).

**Fields**

| Name | Type | Default |
| --- | --- | --- |
| `client_id` | `str` |  |
| `flow` | `AuthSessionFlow` |  |
| `access_token` | `str` |  |
| `pkce_unsupported` | `bool \| None` | `None` |
| `refresh_token` | `str \| None` | `None` |
| `sub` | `str \| None` | `None` |
| `expires_at` | `str \| None` | `None` |
| `scopes` | `list[str] \| None` | `None` |
| `account_manager_host` | `str \| None` | `None` |
| `last_used_at` | `str \| None` | `None` |

#### to_json <Badge type="info" text="method" /> {#authsession-to-json}

```python
def to_json() -> dict[str, Any]
```

Serialize to a dict with camelCase keys, omitting `None` fields (matching JSON.stringify).

#### from_json <Badge type="info" text="method" /> {#authsession-from-json}

```python
def from_json(data: dict[str, Any]) -> AuthSession
```

Build an [`AuthSession`](/python/api/auth#authsession) from a camelCase dict written by any backend.

### AuthSessionBackend {#authsessionbackend}

```python
class AuthSessionBackend(Protocol)
```

Pluggable backend for the auth-session store.

### FileAuthSessionBackend {#fileauthsessionbackend}

```python
class FileAuthSessionBackend
```

Default JSON-file backend at `<data dir>/auth-sessions.json`.

Writes atomically via a temp file + rename, with the directory created
`0o700` and the file written `0o600` (matching the TS backend, since the
file holds long-lived PKCE refresh tokens).

**Fields**

| Name | Type |
| --- | --- |
| `data_dir` | `Path` |

### InMemoryAuthSessionBackend {#inmemoryauthsessionbackend}

```python
class InMemoryAuthSessionBackend
```

In-memory backend, useful for tests and IDE adapters.

## Functions

### create_user_auth_strategy {#create-user-auth-strategy}

```python
def create_user_auth_strategy(config: PkceOAuthConfig) -> PkceOAuthStrategy | PkceWithImplicitFallbackStrategy
```

Build the browser-based "user" auth strategy.

Returns a plain [`PkceOAuthStrategy`](/python/api/auth#pkceoauthstrategy) when the fallback is disabled
(`SFCC_DISABLE_PKCE_FALLBACK`), otherwise a
[`PkceWithImplicitFallbackStrategy`](/python/api/auth#pkcewithimplicitfallbackstrategy).

### is_pkce_fallback_disabled {#is-pkce-fallback-disabled}

```python
def is_pkce_fallback_disabled() -> bool
```

True when `SFCC_DISABLE_PKCE_FALLBACK` is set to any truthy value.

### resolve_auth_strategy {#resolve-auth-strategy}

```python
def resolve_auth_strategy(credentials: AuthCredentials, allowed_methods: list[AuthMethod] | None = None) -> AuthStrategy
```

Resolve and create the appropriate auth strategy.

Iterates through allowed methods in priority order and returns the first
strategy for which the required credentials are available.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `credentials` | `AuthCredentials` | The available credentials. |
| `allowed_methods` | `list[AuthMethod] \| None` | Allowed methods in priority order (defaults to [`ALL_AUTH_METHODS`](/python/api/auth#all-auth-methods), where PKCE-based `user` auth is preferred over the deprecated `implicit` flow). |

**Raises**

- `RuntimeError` — if no allowed method has the required credentials.

### check_available_auth_methods {#check-available-auth-methods}

```python
def check_available_auth_methods(credentials: AuthCredentials, allowed_methods: list[AuthMethod] | None = None) -> AvailableAuthMethods
```

Check which auth methods have the required credentials available.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `credentials` | `AuthCredentials` | The available credentials. |
| `allowed_methods` | `list[AuthMethod] \| None` | Methods to check (defaults to [`ALL_AUTH_METHODS`](/python/api/auth#all-auth-methods)). |

**Returns:** The available and unavailable methods.

### encode_basic_client_credentials {#encode-basic-client-credentials}

```python
def encode_basic_client_credentials(client_id: str, client_secret: str) -> str
```

Build the Base64 payload for `Authorization: Basic` per RFC 6749 §2.3.1.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `client_id` | `str` | The OAuth client identifier. |
| `client_secret` | `str` | The OAuth client password/secret. |

**Returns:** The Base64 string to place after `Basic ` in the header.

### decode_jwt {#decode-jwt}

```python
def decode_jwt(token: str) -> DecodedJWT
```

Decode a JWT into its header and payload without verifying the signature.

**Raises**

- `ValueError` — if the token is not a well-formed three-part JWT.

### decode_jwt_token_info {#decode-jwt-token-info}

```python
def decode_jwt_token_info(token: str) -> tuple[datetime, list[str]]
```

Return `(expires, scopes)` for a token. Propagates decode errors.

### extract_jwt_scopes {#extract-jwt-scopes}

```python
def extract_jwt_scopes(payload: dict[str, Any]) -> list[str]
```

Extract `scope` from a decoded JWT payload (array or space-delimited string).

### is_jwt_token_valid {#is-jwt-token-valid}

```python
def is_jwt_token_valid(token: str, required_scopes: list[str] | None = None, expiry_buffer_sec: int = DEFAULT_EXPIRY_BUFFER_SEC) -> bool
```

Return `True` if the token decodes, is unexpired (with buffer), and has all scopes.

### get_oauth_cache_key {#get-oauth-cache-key}

```python
def get_oauth_cache_key(client_id: str, method: str, account_manager_host: str, scopes: list[str] | None = None) -> str
```

Build a token cache key. Includes the auth method to keep grants distinct.

### get_cached_oauth_token {#get-cached-oauth-token}

```python
def get_cached_oauth_token(cache_key: str, required_scopes: list[str] | None = None) -> AccessTokenResponse | None
```

Return a cached token if present, unexpired, and covering `required_scopes`.

### set_cached_oauth_token {#set-cached-oauth-token}

```python
def set_cached_oauth_token(cache_key: str, token_response: AccessTokenResponse) -> None
```

Store a token in the global cache.

### find_cached_token_satisfying {#find-cached-token-satisfying}

```python
def find_cached_token_satisfying(identity_prefix: str, required_scopes: list[str]) -> AccessTokenResponse | None
```

Return the first non-expired cached token (matching `identity_prefix`) whose scopes ⊇ `required_scopes`.

Used by cascade resolution: a token granted with broader scopes automatically
satisfies a later request needing a narrower scope, with no extra AM round trip.

### invalidate_cached_tokens_for_identity {#invalidate-cached-tokens-for-identity}

```python
def invalidate_cached_tokens_for_identity(identity_prefix: str) -> None
```

Evict every cached token for an identity prefix (host:clientId:method:).

Cascade-resolving strategies cache tokens under merged-scope keys, so deleting
only the base key on a 401 would leave a rejected merged token cached. Clearing
by identity prefix evicts all of them so the retry re-requests from AM.

### reset_oauth_cache_for_testing {#reset-oauth-cache-for-testing}

```python
def reset_oauth_cache_for_testing() -> None
```

Clear the module-level token cache and pending-request map (tests only).

### apply_auth_request_middleware {#apply-auth-request-middleware}

```python
async def apply_auth_request_middleware(request: httpx.Request, middleware: list[AuthMiddleware]) -> httpx.Request
```

Apply every `on_request` hook in order, accumulating modifications.

### apply_auth_response_middleware {#apply-auth-response-middleware}

```python
async def apply_auth_response_middleware(request: httpx.Request, response: httpx.Response, middleware: list[AuthMiddleware]) -> httpx.Response
```

Apply every `on_response` hook in order, accumulating modifications.

### get_default_data_dir {#get-default-data-dir}

```python
def get_default_data_dir(*, data_directory: str | None = None, environment: dict[str, str] | None = None, home_directory: str | None = None, platform: str | None = None) -> Path
```

Resolve the shared oclif-compatible B2C *data* directory (the session store).

Mirrors `@oclif/core`'s `Config.dataDir` — and the sibling
[`get_b2c_config_directory`](/python/api/config#get-b2c-config-directory) — so the SDK
reads the same `auth-sessions.json` the `b2c` CLI writes:

`$B2C_DATA_DIR | $XDG_DATA_HOME | (win32 %LOCALAPPDATA%) | ~/.local/share` then `/b2c`.

Note: oclif's *data* dir uses the XDG `~/.local/share` base on macOS too —
*not* `~/Library/Application Support` (that path is only oclif's *cache* dir).

### set_auth_session_backend {#set-auth-session-backend}

```python
def set_auth_session_backend(backend: AuthSessionBackend | None) -> None
```

Register an auth-session backend. Pass `None` to fall back to the file backend.

### get_auth_session_backend {#get-auth-session-backend}

```python
def get_auth_session_backend() -> AuthSessionBackend
```

Return the active backend (lazily creating the file-backed default).

### initialize_file_auth_session_store {#initialize-file-auth-session-store}

```python
def initialize_file_auth_session_store(data_dir: str | os.PathLike[str]) -> None
```

Install a [`FileAuthSessionBackend`](/python/api/auth#fileauthsessionbackend) pointed at `data_dir`.

### find_auth_session {#find-auth-session}

```python
def find_auth_session(client_id: str) -> AuthSession | None
```

Read the stored session for `client_id` (or `None`).

### save_auth_session {#save-auth-session}

```python
def save_auth_session(session: AuthSession) -> None
```

Write a session, replacing any prior record for the same `client_id`.

### delete_auth_session {#delete-auth-session}

```python
def delete_auth_session(client_id: str) -> None
```

Delete the session for `client_id`.

### list_auth_sessions {#list-auth-sessions}

```python
def list_auth_sessions() -> list[AuthSession]
```

List all stored sessions (for diagnostics).

### clear_all_auth_sessions {#clear-all-auth-sessions}

```python
def clear_all_auth_sessions() -> None
```

Remove every stored session. Used by `auth logout`.

### is_auth_session_token_valid {#is-auth-session-token-valid}

```python
def is_auth_session_token_valid(session: AuthSession, required_scopes: list[str] | None = None, expiry_buffer_sec: int = DEFAULT_EXPIRY_BUFFER_SEC, required_client_id: str | None = None) -> bool
```

Return `True` if the session's access token is present, unexpired, and in-scope.

Performs no network calls — validity is derived from the JWT `exp`/`scope`.

### reset_auth_session_store_for_testing {#reset-auth-session-store-for-testing}

```python
def reset_auth_session_store_for_testing() -> None
```

Reset the active backend (tests). The next call falls back to the file default.

## Attributes

### AuthMethod {#authmethod}

```python
AuthMethod = Literal['client-credentials', 'jwt', 'user', 'implicit', 'basic', 'api-key']
```

### ALL_AUTH_METHODS {#all-auth-methods}

```python
ALL_AUTH_METHODS: list[AuthMethod] = ['client-credentials', 'jwt', 'user', 'implicit', 'basic', 'api-key']
```

### DEFAULT_EXPIRY_BUFFER_SEC {#default-expiry-buffer-sec}

```python
DEFAULT_EXPIRY_BUFFER_SEC = 60
```

### global_auth_middleware_registry {#global-auth-middleware-registry}

```python
global_auth_middleware_registry = AuthMiddlewareRegistry()
```

### AuthSessionFlow {#authsessionflow}

```python
AuthSessionFlow = Literal['pkce', 'implicit', 'client-credentials']
```
