@ucap/sdk
Hand-written, zero-dependency TypeScript client for the UCap public API. Works in browsers, Node ≥ 18, Deno, Bun, and Cloudflare Workers.
Install
During the developer preview the SDK ships as a workspace package. Drop the packages/sdk folder into your monorepo, or grab the tarball from your partner contact.
# inside your monorepo
bun add @ucap/sdk@workspace:*
# or from a tarball
bun add ./ucap-sdk-0.1.0.tgzQuickstart — user OAuth
import { UcapClient, generateCodeVerifier, deriveCodeChallenge } from "@ucap/sdk";
const ucap = new UcapClient({
baseUrl: "https://phase2.ucap.africa",
clientId: process.env.UCAP_CLIENT_ID!,
});
// 1. Build the authorize URL
const verifier = generateCodeVerifier();
const challenge = await deriveCodeChallenge(verifier);
const state = crypto.randomUUID();
const url = ucap.startAuthorization({
redirectUri: "https://yourapp.com/callback",
scope: ["consumer.profile.read"],
state,
codeChallenge: challenge,
});
// → redirect the user to `url`
// 2. After the redirect back, exchange the code
const tokens = await ucap.exchangeCode({
code, // from req.query.code
redirectUri: "https://yourapp.com/callback",
codeVerifier: verifier, // pulled from session
});
// 3. Call the API
const profile = await ucap.me.getProfile(tokens.access_token);Server-to-server
const ucap = new UcapClient({
baseUrl: "https://phase2.ucap.africa",
clientId: process.env.UCAP_CLIENT_ID!,
clientSecret: process.env.UCAP_CLIENT_SECRET!,
});
const tokens = await ucap.clientCredentials({
scope: ["sessions.create", "sessions.read"],
});Error handling
Every non-2xx response throws UcapApiError with the server's code and message intact, plus the HTTP status.
import { UcapApiError } from "@ucap/sdk";
try {
await ucap.me.getProfile(token);
} catch (err) {
if (err instanceof UcapApiError && err.code === "insufficient_scope") {
// re-prompt the user with the right scopes
}
throw err;
}Surface
generateCodeVerifier()/deriveCodeChallenge(v)UcapClient#startAuthorization(opts)→ authorize URLUcapClient#exchangeCode(opts)→ tokensUcapClient#refresh(refreshToken)→ tokensUcapClient#clientCredentials(opts)→ tokensUcapClient#revoke(token)UcapClient#me.getProfile(token)UcapClient#me.listDocuments(token)UcapClient#me.listGrants(token)
