---
title: SDKs
description: Official Sudomimus SDKs — strongly typed clients for the Connect
  and Native APIs in TypeScript, Python, and C#.
editUrl: true
head: []
template: doc
sidebar:
  order: 1
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

import { CardGrid, LinkCard, Tabs, TabItem } from "@astrojs/starlight/components";

The Sudomimus SDKs are strongly typed clients generated from the public OpenAPI 3.1 contracts in [`sudomimus/sudomimus-spec`](https://github.com/sudomimus/sudomimus-spec): [`connect.yaml`](https://github.com/sudomimus/sudomimus-spec/blob/main/connect.yaml) (Connect protocol), [`native.yaml`](https://github.com/sudomimus/sudomimus-spec/blob/main/native.yaml) (`native-api` direct-issue), and [`device.yaml`](https://github.com/sudomimus/sudomimus-spec/blob/main/device.yaml) (`device-api` device authorization). The SDK source lives in [`sudomimus/sudomimus`](https://github.com/sudomimus/sudomimus) — TypeScript, Python, and C# in one monorepo. SDKs wrap the raw HTTPS calls with serialization, request/response types, JWT parsing, application public-key caching, signature verification helpers, and structured errors — everything you'd otherwise build by hand.

If you'd rather call the API directly, see [Web applications](/en-us/connect/flow/) for curl, Node.js, Python, and Go HTTP snippets.

## Available SDKs

All packages are currently at **alpha** stability — usable, with the API surface tracking the spec, but expect some churn before the first stable release.

<CardGrid>
<LinkCard
    title="TypeScript / JavaScript"
    description="@sudomimus/connect, @sudomimus/native, @sudomimus/token — for Node.js and browsers."
    href="https://github.com/sudomimus/sudomimus/tree/master/sdks/typescript/packages"
/>
<LinkCard
    title="Python"
    description="sudomimus-connect, sudomimus-native, sudomimus-token — sync (ConnectClient) and async (AsyncConnectClient)."
    href="https://github.com/sudomimus/sudomimus/tree/master/sdks/python/packages"
/>
<LinkCard
    title="C#"
    description="Sudomimus.Native and Sudomimus.Token. The Connect package is not yet shipped for C#."
    href="https://github.com/sudomimus/sudomimus/tree/master/sdks/csharp/src"
/>
</CardGrid>

The three packages per language split along responsibility:

- **`connect`** — full Connect API client (Establish, StatusPoll, Redeem, Refresh, Info, Introspect, Logout, RevokeAll). Use this in your application backend.
- **`native`** — Native API client (Steam ticket direct-issue, AccessKey direct-issue). Use this in desktop apps, games, CLIs.
- **`token`** — token-parsing utilities only (`verifyAccessToken`, `verifyRefreshToken`, the `kty` constants). Useful when a service only needs to verify tokens and doesn't call the API.

The `connect` and `native` packages already depend on `token` internally, so most integrations don't need to install it explicitly.

The Device API has a published [OpenAPI reference](/en-us/api/device/) for direct HTTP clients. A dedicated SDK package will appear here after it is introduced in the SDK repository.

Tabs below are synchronised: pick your language once and every block on the page switches with it.

## Install

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```bash
# pnpm
pnpm add @sudomimus/connect

# npm
npm install @sudomimus/connect

# yarn
yarn add @sudomimus/connect
```
</TabItem>
<TabItem label="Python">
```bash
# uv
uv add sudomimus-connect

# pip
pip install sudomimus-connect
```
</TabItem>
</Tabs>

## Initialise the client

The client needs to know how to sign `/establish` requests with your application's client-auth private key. Supply the key once at construction time; the SDK signs internally on every relevant call.

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
import { ConnectClient } from "@sudomimus/connect";

const client = new ConnectClient({
    baseUrl: "https://connect-api.sudomimus.com",
    // clientAuth: configure with your application's client-auth private key
    //             so the SDK can sign /establish and /revoke-all internally.
    //             See the package README for the exact option shape.
});
```
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import (
    ConnectClient,
    ConnectClientAuthWithKey,
)

with ConnectClient(
    client_auth=ConnectClientAuthWithKey(
        application_anchor="my-app",
        private_key_pem=open("client-auth-private.pem").read(),
    ),
) as client:
    ...
```

An async equivalent exists as `AsyncConnectClient` with the same method names.
</TabItem>
</Tabs>

## Establish — start a session

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
const inquiry = await client.establish({
    applicationAnchor: process.env.SUDOMIMUS_APPLICATION_ANCHOR!,
    returnMethods: [
        {
            type: "CALLBACK",
            payload: { callbackUrl: "https://your-app.com/auth/callback" },
        },
    ],
});

const { exposureKey, hiddenKey } = inquiry;
```
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import EstablishRequest

inquiry = client.establish(EstablishRequest(
    applicationAnchor="my-app",
))
# inquiry.exposureKey, inquiry.hiddenKey
```

Request fields are camelCase (`applicationAnchor`, `returnMethods`) because they're generated from the OpenAPI schema. Method names are snake_case.
</TabItem>
</Tabs>

## Status poll — check the session

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
const status = await client.statusPoll({ exposureKey, hiddenKey });

if (status.status === "REALIZED") {
    const { confirmationKey } = status;
    // hand off to redeem
}
```

The response is discriminated on `status` (`"PENDING"` or `"REALIZED"`); only `REALIZED` carries a `confirmationKey`.
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import StatusPollRequest

status = client.status_poll(StatusPollRequest(
    exposureKey=exposure_key,
    hiddenKey=hidden_key,
))
```
</TabItem>
</Tabs>

## Redeem — exchange for tokens

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
const tokens = await client.redeem({
    exposureKey,
    hiddenKey,
    confirmationKey,
});

const { accessToken, refreshToken } = tokens;
```
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import RedeemRequest

tokens = client.redeem(RedeemRequest(
    exposureKey=exposure_key,
    hiddenKey=hidden_key,
    confirmationKey=confirmation_key,
))
# tokens.accessToken, tokens.refreshToken
```
</TabItem>
</Tabs>

## Refresh / introspect / logout

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
// Refresh rotates the token — capture and persist the new one for next time.
const { accessToken, refreshToken: newRefreshToken } = await client.refresh({ refreshToken });
await store.saveRefreshToken(newRefreshToken);

const { status, recommendedRecheckSeconds } = await client.introspect({ accessToken });
// status: "active" | "revoked" | "expired" | "not_found"

await client.logout({ refreshToken });

const { revokedCount } = await client.revokeAll({ subject });
```

Endpoint semantics are documented in [Managing sessions](/en-us/guides/managing-sessions/). `/refresh` rotates the refresh token — it returns a fresh `accessToken` **and** a new `refreshToken`, and the presented one is consumed; persist the replacement and use it next time. `/refresh`, `/introspect`, and `/logout` are self-authenticating (the token is the credential); `/revokeAll` requires the client-auth credentials configured at construction time.
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import (
    RefreshRequest,
    IntrospectRequest,
    LogoutRequest,
    RevokeAllRequest,
)

fresh = client.refresh(RefreshRequest(refreshToken=tokens.refreshToken))
state = client.introspect(IntrospectRequest(accessToken=tokens.accessToken))
client.logout(LogoutRequest(refreshToken=tokens.refreshToken))
revoked = client.revoke_all(RevokeAllRequest(subject="sub_9SQ5535CRWNDDM2T"))
# revoked.revokedCount
```
</TabItem>
</Tabs>

## Info — fetch application metadata

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
const info = await client.info({
    applicationAnchor,
    locale: "en-US",
});

// info.applicationName, info.applicationPublicKey
```
</TabItem>
<TabItem label="Python">
```python
from sudomimus_connect import InfoRequest

info = client.info(InfoRequest(
    applicationAnchor="my-app",
    locale="en-US",
))
# info.applicationName, info.applicationPublicKey
```
</TabItem>
</Tabs>

## Verify access tokens

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
import { TokenError } from "@sudomimus/token";

try {
    const token = await client.verifyAccessToken(rawJwt);
    // token.body.subject, token.body.firstName, token.body.lastName?
} catch (error) {
    if (error instanceof TokenError) {
        // structured token verification failure
    }
    throw error;
}
```

`verifyAccessToken` parses the JWT, checks `kty === "Access"`, validates expiration, then calls `/info` for the `applicationPublicKey` (cached per `applicationAnchor`) and checks the signature. Use `verifyRefreshToken` for the matching `kty === "Refresh"` flow, and `clearPublicKeyCache()` to force a refetch after a key rotation.

Connect access tokens are verified per-application, not against a shared JWKS. See [Tokens and verification](/en-us/concepts/tokens-and-verification/) for the full picture.
</TabItem>
<TabItem label="Python">
```python
access = client.verify_access_token(tokens.accessToken)
# access.body.subject
```

`verify_refresh_token` is the matching refresh-token method.
</TabItem>
</Tabs>

## Handle API errors

<Tabs syncKey="sdk-lang">
<TabItem label="TypeScript">
```ts
import { ConnectApiError } from "@sudomimus/connect";

try {
    await client.redeem({ exposureKey, hiddenKey, confirmationKey });
} catch (error) {
    if (error instanceof ConnectApiError) {
        // error.status — HTTP status
        // error.reason — stable machine-readable code (when present)
        // error.body   — raw `{ reason?: string }` payload (when present)
    }
    throw error;
}
```

The `reason` field is omitted when the underlying failure symbol is marked `PRIVATE`; in that case only the HTTP status carries signal.
</TabItem>
<TabItem label="Python">
Python raises a typed exception with the same fields. See the [`sudomimus-connect` package README](https://github.com/sudomimus/sudomimus/tree/master/sdks/python/packages/sudomimus-connect) for the exact class name and attributes.
</TabItem>
</Tabs>

## C#

The C# SDK ships two packages today, both alpha:

- **`Sudomimus.Native`** — direct-issue client for `native-api` (Steam ticket, AccessKey).
- **`Sudomimus.Token`** — token-parsing utilities, the same role as `@sudomimus/token`.

A `Sudomimus.Connect` package is **not yet shipped** — for the Connect protocol from C#, call the HTTPS endpoints directly (see [Web applications](/en-us/connect/flow/) for the request shapes) and use `Sudomimus.Token` to verify the tokens you receive. Source: [`sdks/csharp/src`](https://github.com/sudomimus/sudomimus/tree/master/sdks/csharp/src).

## Source

<CardGrid>
<LinkCard
    title="SDK monorepo on GitHub"
    description="Source, issues, and release tags for every official SDK package."
    href="https://github.com/sudomimus/sudomimus"
/>
<LinkCard
    title="OpenAPI contracts"
    description="sudomimus/sudomimus-spec — the authoritative connect.yaml and native.yaml schemas the SDKs generate from."
    href="https://github.com/sudomimus/sudomimus-spec"
/>
</CardGrid>