Skip to content

OAuth apps

Describes stx-python 0.8.0, the current release.

One registered app on one exchange.

Configuration comes from the arguments, then STX_OAUTH_CLIENT_ID, STX_OAUTH_CLIENT_SECRET, STX_OAUTH_REDIRECT_URI; the exchange is picked as for AsyncSTX (host=, or region= and env=, or STX_HOST / a profile):

oauth = AsyncOAuthClient(
client_id=CLIENT_ID, client_secret=CLIENT_SECRET,
redirect_uri="https://your.app/callback", region="us", env="demo",
)

Omit client_secret for a public client (registered without one): it identifies with client_id in the form and PKCE is its proof; it cannot mint app tokens. Prefer discover, which takes every endpoint from the exchange’s discovery document and checks scopes against what the exchange offers before sending a member anywhere.

Parameter Description
scope default scopes to request, space-delimited or a list.
endpoints overrides for authorize, token, revoke, introspect (paths or absolute URLs).
metadata a discovery document already fetched.
transport an httpx.AsyncBaseTransport, for tests.
Attribute Type Description
endpoints Dict[str, str]
host str
is_public bool True without a client secret: PKCE only, no app tokens.
app(scope: ScopeInput = None) -> OAuthAppAuth

An auth provider acting as the app (client credentials).

Parameter Type Description
scope ScopeInput
app_client(scope: ScopeInput = None, **kwargs: Any) -> AsyncSTX

An AsyncSTX acting as the app: markets(), events(), event_players(), market_types(), create_markets() (with markets.write) and, through websocket(), the public market channels. scope defaults to every app scope the app holds.

Parameter Type Description
scope ScopeInput
kwargs Any
app_token(scope: ScopeInput = None) -> AppTokenProvider

A cached app token that re-mints itself before expiry. The same scope returns the same provider, so every client built from this app shares one token.

Parameter Type Description
scope ScopeInput
authorization_url(*, scope: ScopeInput = None, state: Optional[str] = None, redirect_uri: Optional[str] = None, prompt: Optional[str] = None, connection: Optional[str] = None, login_hint: Optional[str] = None, extra_params: Optional[Mapping[str, str]] = None) -> Authorization

A fresh PKCE pair and state, and the authorize URL for them.

prompt is none (silent reconnect), login or consent. connection (google, apple, x) skips STX’s sign-in page for that provider; login_hint preselects the member’s email. Keep state and code_verifier; begin_authorization does that for you.

Parameter Type Description
scope ScopeInput
state Optional[str]
redirect_uri Optional[str]
prompt Optional[str]
connection Optional[str]
login_hint Optional[str]
extra_params Optional[Mapping[str, str]]
begin_authorization(pending_store: Any, *, scope: ScopeInput = None, data: Optional[Dict[str, Any]] = None, ttl: float = 600.0, redirect_uri: Optional[str] = None, prompt: Optional[str] = None, connection: Optional[str] = None, login_hint: Optional[str] = None, extra_params: Optional[Mapping[str, str]] = None) -> Authorization

Start a sign-in: remember the PKCE verifier (and data) in pending_store under a fresh state for ttl seconds, and return the URL to redirect the member to. Finish with complete_authorization on the callback.

Parameter Type Description
pending_store Any
scope ScopeInput
data Optional[Dict[str, Any]]
ttl float
redirect_uri Optional[str]
prompt Optional[str]
connection Optional[str]
login_hint Optional[str]
extra_params Optional[Mapping[str, str]]
build_authorize_url(*, state: str, code_challenge: str, scope: ScopeInput = None, redirect_uri: Optional[str] = None, prompt: Optional[str] = None, connection: Optional[str] = None, login_hint: Optional[str] = None, extra_params: Optional[Mapping[str, str]] = None) -> str

The authorize URL for a challenge you already have.

Parameter Type Description
state str
code_challenge str
scope ScopeInput
redirect_uri Optional[str]
prompt Optional[str]
connection Optional[str]
login_hint Optional[str]
extra_params Optional[Mapping[str, str]]
client_credentials(scope: ScopeInput = None) -> TokenSet

Mint an app token (RFC 6749 section 4.4): the app acting as itself, no member, no refresh token. App scopes only (market_data, events, markets.write); omit scope for every app scope the app holds. Needs a client secret. For a cached, self-renewing token use app_token.

Parameter Type Description
scope ScopeInput
complete_authorization(pending_store: Any, callback: CallbackInput, *, store: Any = None, member_key: Union[str, Callable[[Optional[Dict[str, Any]]], str], None] = None) -> CompletedAuthorization

Finish a sign-in from the callback URL or its query.

Uses up the state, raises the callback’s error as a typed exception (see read_callback), exchanges the code with the stored verifier and, given store, saves the tokens under member_key (a string, or a function of the data passed to begin_authorization).

Parameter Type Description
pending_store Any
callback CallbackInput
store Any
member_key Union[str, Callable[[Optional[Dict[str, Any]]], str], None]
discover(client_id: Optional[str] = None, client_secret: Optional[str] = None, **kwargs: Any) -> AsyncOAuthClient

A client whose endpoints come from the exchange’s discovery document.

Raises STXNotAvailableError (oauth) on an exchange without OAuth. Takes the same arguments as the constructor.

Parameter Type Description
client_id Optional[str]
client_secret Optional[str]
kwargs Any
exchange_code(code: str, code_verifier: str, *, redirect_uri: Optional[str] = None) -> TokenSet

Exchange an authorization code for tokens, proving PKCE.

Parameter Type Description
code str
code_verifier str
redirect_uri Optional[str]
introspect(token: str) -> Dict[str, Any]

A token’s active state and scope (RFC 7662). Confidential clients only.

Parameter Type Description
token str
member_client(store: Any, member_key: str, **kwargs: Any) -> AsyncSTX

An AsyncSTX acting for one connected member.

Every member method (balance, positions, orders, place_order, cancel_order…) with the member’s token, refreshed when due, and websocket() for their channels. Session options (skew, on_refresh, on_grant_revoked, on_terms_required) and AsyncSTX options (timeout, retry, on_response) are passed through.

Parameter Type Description
store Any
member_key str
kwargs Any
metadata(*, refresh: bool = False) -> AuthorizationServerMetadata

GET /.well-known/oauth-authorization-server, fetched once.

Raises STXNotAvailableError (oauth) when the exchange does not publish it (a 404).

Parameter Type Description
refresh bool
protected_resource() -> Dict[str, Any]

GET /.well-known/oauth-protected-resource (RFC 9728).

read_callback(pending_store: Any, callback: CallbackInput) -> CallbackResult

Check an authorize callback and use up its pending sign-in, without calling STX. Pass the result to redeem_authorization.

Raises the callback’s error as a typed exception, or STXOAuthException with invalid_request (no code or state) or invalid_state (unknown, used or expired).

Parameter Type Description
pending_store Any
callback CallbackInput
redeem_authorization(callback: CallbackResult, *, store: Any = None, member_key: Union[str, Callable[[Optional[Dict[str, Any]]], str], None] = None) -> CompletedAuthorization

The second half of complete_authorization, for a callback already read with read_callback (one callback URL serving several apps).

Parameter Type Description
callback CallbackResult
store Any
member_key Union[str, Callable[[Optional[Dict[str, Any]]], str], None]
refresh_token(refresh_token: str) -> TokenSet

Trade a refresh token for a new pair. STX rotates refresh tokens: store whatever comes back.

A refused refresh (invalid_grant) raises STXGrantRevokedException; a member still being verified raises STXAccountPendingException (keep the tokens). While the member has new STX terms to accept the refresh succeeds and the result has terms_required and terms_url.

Parameter Type Description
refresh_token str
revoke(token: str, token_type_hint: Optional[str] = None) -> None

Revoke a token (RFC 7009). A refresh token ends the member’s whole grant; an access token revokes only its pair.

Parameter Type Description
token str
token_type_hint Optional[str]
session(store: Any, member_key: str, *, skew: float = 30.0, on_refresh: Optional[Callable[[StoredTokens], Any]] = None, on_grant_revoked: Optional[Callable[[STXGrantRevokedException], Any]] = None, on_terms_required: Optional[Callable[[str], Any]] = None) -> OAuthSessionAuth

An auth provider for one member, over store: attaches their access token, refreshes it skew seconds before expiry and once on a 401 (storing the rotated pair), and treats a revoked grant as final (deletes the tokens, raises STXGrantRevokedException).

Parameter Type Description
store Any
member_key str
skew float
on_refresh Optional[Callable[[StoredTokens], Any]]
on_grant_revoked Optional[Callable[[STXGrantRevokedException], Any]]
on_terms_required Optional[Callable[[str], Any]]
unlink(store: Any, member_key: str) -> bool

Disconnect a member: revoke their grant at the exchange (best effort) and delete their tokens from store. Returns True when the exchange confirmed the revoke; the local tokens are deleted either way.

Parameter Type Description
store Any
member_key str

Blocking OAuth client for one app. Takes the same arguments as AsyncOAuthClient and has the same methods without await:

oauth = OAuthClient.discover(
client_id=CLIENT_ID, client_secret=CLIENT_SECRET,
redirect_uri="https://your.app/callback", region="us", env="demo",
)
auth = oauth.begin_authorization(pending, data={"user_id": "u1"})
# ... redirect to auth.url; on the callback:
done = oauth.complete_authorization(pending, request_url, store=tokens, member_key="u1")
with oauth.member_client(tokens, "u1") as stx:
print(stx.balance().available_balance)
Attribute Type Description
async_client AsyncOAuthClient
base_url str
host str
client_id str
redirect_uri Optional[str]
endpoints Dict[str, str]
is_public bool
app_client(scope: ScopeInput = None, **kwargs: Any) -> STX

A blocking STX acting as the app. See AsyncOAuthClient.app_client.

Parameter Type Description
scope ScopeInput
kwargs Any
app_token(scope: ScopeInput = None) -> AppToken
Parameter Type Description
scope ScopeInput
authorization_url(**kwargs: Any) -> Authorization
Parameter Type Description
kwargs Any
begin_authorization(pending_store: Any, **kwargs: Any) -> Authorization
Parameter Type Description
pending_store Any
kwargs Any
build_authorize_url(**kwargs: Any) -> str
Parameter Type Description
kwargs Any
client_credentials(scope: ScopeInput = None) -> TokenSet
Parameter Type Description
scope ScopeInput
complete_authorization(pending_store: Any, callback: CallbackInput, *, store: Any = None, member_key: Union[str, Callable[[Optional[Dict[str, Any]]], str], None] = None) -> CompletedAuthorization
Parameter Type Description
pending_store Any
callback CallbackInput
store Any
member_key Union[str, Callable[[Optional[Dict[str, Any]]], str], None]
discover(client_id: Optional[str] = None, client_secret: Optional[str] = None, **kwargs: Any) -> OAuthClient

A client on the endpoints the exchange publishes. Raises STXNotAvailableError (oauth) on an exchange without OAuth.

Parameter Type Description
client_id Optional[str]
client_secret Optional[str]
kwargs Any
exchange_code(code: str, code_verifier: str, *, redirect_uri: Optional[str] = None) -> TokenSet
Parameter Type Description
code str
code_verifier str
redirect_uri Optional[str]
introspect(token: str) -> Dict[str, Any]
Parameter Type Description
token str
member_client(store: Any, member_key: str, **kwargs: Any) -> STX

A blocking STX acting for one connected member. See AsyncOAuthClient.member_client.

Parameter Type Description
store Any
member_key str
kwargs Any
metadata(*, refresh: bool = False) -> AuthorizationServerMetadata
Parameter Type Description
refresh bool
protected_resource() -> Dict[str, Any]
read_callback(pending_store: Any, callback: CallbackInput) -> CallbackResult
Parameter Type Description
pending_store Any
callback CallbackInput
redeem_authorization(callback: CallbackResult, *, store: Any = None, member_key: Union[str, Callable[[Optional[Dict[str, Any]]], str], None] = None) -> CompletedAuthorization
Parameter Type Description
callback CallbackResult
store Any
member_key Union[str, Callable[[Optional[Dict[str, Any]]], str], None]
refresh_token(refresh_token: str) -> TokenSet
Parameter Type Description
refresh_token str
revoke(token: str, token_type_hint: Optional[str] = None) -> None
Parameter Type Description
token str
token_type_hint Optional[str]
unlink(store: Any, member_key: str) -> bool
Parameter Type Description
store Any
member_key str

A cached app token. Mints on first use, re-mints skew seconds before expiry, mints once for concurrent callers, and can be invalidated after a 401 so the next call mints fresh.

Attribute Type Description
granted_scope Optional[str] The scope the exchange granted the current token, once minted.
fresh() -> str

Invalidate and mint now.

get() -> str

A valid access token, minting when missing or near expiry.

invalidate() -> None

Drop the cached token; the next get mints.

A cached app token, blocking. See AppTokenProvider.

Attribute Type Description
granted_scope Optional[str]
fresh() -> str

Invalidate and mint now.

get() -> str

A valid access token, minting when missing or near expiry.

invalidate() -> None

A token response (RFC 6749 section 5.1).

expires_at is Unix time in seconds, from expires_in. refresh_token is absent on an app token. id_token is set when openid was granted (verify it before trusting it; Connect does). On a refresh, terms_required and terms_url say the member has new STX terms to accept: the tokens work, placing orders waits until they do.

Attribute Type Description
access_token str
refresh_token Optional[str]
token_type Optional[str]
expires_in Optional[int]
expires_at Optional[float]
scope Optional[str]
id_token Optional[str]
terms_required bool
terms_url Optional[str]
scopes List[str] The granted scopes, canonical names.
to_stored() -> StoredTokens

The StoredTokens a TokenStore keeps.

One prepared authorize redirect.

Send the member’s browser to url; keep state and code_verifier server-side until the callback.

Attribute Type Description
url str
state str
code_verifier str
code_challenge str
redirect_uri str

A validated callback: the code and the pending sign-in its state named (now used up).

Attribute Type Description
code str
pending PendingAuthorization

What complete_authorization returns.

scopes may be narrower than requested. data is what you passed to begin_authorization; member_key the key the tokens were stored under, when a store was given.

Attribute Type Description
tokens TokenSet
scopes List[str]
data Optional[Dict[str, Any]]
member_key Optional[str]

RFC 8414 metadata, as the exchange publishes it. raw is the whole document.

Attribute Type Description
issuer str
authorization_endpoint str
token_endpoint str
revocation_endpoint Optional[str]
introspection_endpoint Optional[str]
registration_endpoint Optional[str]
scopes_supported Tuple[str, ...]
grant_types_supported Tuple[str, ...]
code_challenge_methods_supported Tuple[str, ...]
token_endpoint_auth_methods_supported Tuple[str, ...]
raw Dict[str, Any]
from_dict(doc: Mapping[str, Any]) -> AuthorizationServerMetadata
Parameter Type Description
doc Mapping[str, Any]

One member’s tokens, as a TokenStore keeps them.

expires_at is Unix time in seconds (None when unknown). scope is the granted scope, space-delimited. terms_required and terms_url are set while the member has new STX terms to accept. to_dict() and from_dict() give a JSON-friendly form to persist.

Attribute Type Description
access_token str
refresh_token Optional[str]
expires_at Optional[float]
scope Optional[str]
terms_required bool
terms_url Optional[str]
expires_within(seconds: float) -> bool
Parameter Type Description
seconds float
from_dict(data: Dict[str, Any]) -> StoredTokens
Parameter Type Description
data Dict[str, Any]
to_dict() -> Dict[str, Any]

In-memory TokenStore. Fine for scripts, demos and tests; not durable.

delete(member_key: str) -> None
Parameter Type Description
member_key str
get(member_key: str) -> Optional[StoredTokens]
Parameter Type Description
member_key str
set(member_key: str, tokens: StoredTokens) -> None
Parameter Type Description
member_key str
tokens StoredTokens

One sign-in in progress, kept server-side under its state.

expires_at is Unix time in seconds. data is yours: a session id, a user id, a return URL, carried to the callback.

Attribute Type Description
code_verifier str
redirect_uri str
scope Optional[str]
expires_at float
data Optional[Dict[str, Any]]
from_dict(data: Dict[str, Any]) -> PendingAuthorization
Parameter Type Description
data Dict[str, Any]
to_dict() -> Dict[str, Any]

In-memory PendingAuthorizationStore. Expired entries are dropped.

put(state: str, pending: PendingAuthorization) -> None
Parameter Type Description
state str
pending PendingAuthorization
take(state: str) -> Optional[PendingAuthorization]
Parameter Type Description
state str

Member scopes, granted through consent.

App scopes, for client_credentials app tokens.

Auth provider for one connected member, over a TokenStore.

Attaches the member’s access token, refreshes it when near expiry and once on a 401 (storing the rotated pair), and treats a revoked grant as final: the stored tokens are deleted and STXGrantRevokedException raised. Refreshes run once per member across every client the same AsyncOAuthClient made.

auth_headers(method: str, path: str) -> Dict[str, str]
Parameter Type Description
method str
path str
on_unauthorized() -> bool
refresh(refresh_token: str) -> Optional[StoredTokens]

Refresh with rotation, once per member at a time. Returns the new tokens, or None after a transient failure. Raises STXGrantRevokedException (tokens deleted) or STXAccountPendingException (tokens kept).

Parameter Type Description
refresh_token str
scopes() -> List[str]

The granted scopes of the stored tokens.

tokens() -> StoredTokens

The member’s tokens, refreshed first when at or near expiry.

websocket_headers(reconnect: bool) -> Dict[str, str]
Parameter Type Description
reconnect bool

Auth provider acting as the app. A 401 re-mints once; every socket reconnect mints fresh, never reusing the token of a connection that just dropped.

auth_headers(method: str, path: str) -> Dict[str, str]
Parameter Type Description
method str
path str
on_unauthorized() -> bool
websocket_headers(reconnect: bool) -> Dict[str, str]
Parameter Type Description
reconnect bool