@digesty/miniapp-sdk
v0.0.2
Published
Browser SDK for Digesty Mini Apps.
Readme
@digesty/miniapp-sdk
Browser SDK for Digesty Mini Apps.
Use this package when:
- you want the framework-agnostic Mini App client
- you need embedded bootstrap, direct launch, callback exchange, or session restore
- you want to build your own framework adapter on top
Install
pnpm add @digesty/miniapp-sdkQuick Start
import { createMiniAppClient } from "@digesty/miniapp-sdk";
const client = createMiniAppClient({
appID: "your-app-id",
});
await client.initEmbedded();Minimal direct-launch example:
import { createMiniAppClient } from "@digesty/miniapp-sdk";
const client = createMiniAppClient({
appID: "your-app-id",
});
if (window.location.search.includes("launch_code=")) {
await client.handleCallback();
} else if (!client.restoreSession()) {
await client.startDirectLaunch();
}Config
type MiniAppClientConfig = {
appID: string;
apiURL?: string;
digestyOrigin?: string;
getLaunchURL?: (args: {
appID: string;
codeChallenge: string;
digestyOrigin: string;
}) => string;
storage?: StorageAdapter;
autoRefresh?: boolean;
};Defaults:
apiURLdefaults to"https://worker.digesty.vn"digestyOrigindefaults to"https://digesty.vn"autoRefreshdefaults tofalsegetLaunchURLdefaults to${digestyOrigin}/apps/${appID}/launch?code_challenge=...
Most apps can start with:
const client = createMiniAppClient({
appID: "your-app-id",
});Use staging explicitly:
const client = createMiniAppClient({
appID: "your-app-id",
digestyOrigin: "https://staging.digesty.vn",
});Use local dev explicitly:
const client = createMiniAppClient({
appID: "app_local_sdk_test",
apiURL: "http://localhost:8787",
digestyOrigin: "http://localhost:3000",
});Use getLaunchURL only when the Digesty launch route differs from the default:
const client = createMiniAppClient({
appID: "your-app-id",
getLaunchURL: ({ appID, codeChallenge, digestyOrigin }) =>
`${digestyOrigin}/miniapps/${appID}/consent?code_challenge=${encodeURIComponent(codeChallenge)}`,
});Main Methods
initEmbedded(): consume#digesty_launch_tokenand complete embedded bootstraprequestRefresh(): request a fresh embedded token from the parent Digesty windowstartDirectLaunch(): begin the direct consent flowhandleCallback(): exchange?launch_code=...for a launch tokenrestoreSession(): restore the last direct-launch session from storageclearSession(): clear stored direct-launch sessionsubscribe(listener): observeMiniAppStateonTokenUpdate(listener): observe successful token changes
Flows
Embedded
Use this when your app is running inside a Digesty iframe.
await client.initEmbedded();The SDK reads digesty_launch_token from the URL hash, validates the payload shape, then uses postMessage with digestyOrigin for handshake and refresh.
Direct
Use this when your app runs as a top-level site.
await client.startDirectLaunch();Digesty redirects back with launch_code in the query string. Then:
await client.handleCallback();The SDK exchanges the code against:
POST {apiURL}/api/v2/app-auth/apps/{appID}/launch/exchangeSecurity Model
This SDK does not verify JWT signatures in the browser. It only parses the token payload shape for UI state.
That means:
- browser
state.claimsis fine for rendering - backend authorization must not trust those claims unless the token was verified server-side
- if your backend receives a launch token, verify it against Digesty JWKS first
Backend Verification With JWKS
Backends should verify Digesty launch tokens against:
GET {apiURL}/api/v2/app-auth/jwksWith the default config, that is:
https://worker.digesty.vn/api/v2/app-auth/jwksMinimum checks:
- verify the EdDSA signature using the matching
kidfrom the JWKS - verify
iss === "digesty.ai" - verify
aud === "app:{appID}" - verify
app_id === appID - verify
modeif your endpoint expects only"embed"or only"direct" - verify
expandiataccording to your JWT library
Current launch token payload shape:
type LaunchTokenPayload = {
iss: "digesty.ai";
aud: string;
sub: string;
iat: number;
exp: number;
jti: string;
app_id: string;
mode: "embed" | "direct";
scopes: string[];
email?: string;
email_verified?: boolean;
name?: string;
picture?: string;
};Important notes:
subis a pairwise Digesty subject scoped to the app, not the global Digesty user ID- direct launch redirects carry
launch_code, not the final token - launch code exchange still happens over HTTPS, but server-side JWT verification is the right contract if your backend consumes the resulting token
Server-Managed Direct Callback
The SDK implements the browser-managed direct callback flow. PKCE verifier state lives in browser storage, and handleCallback() exchanges the code in the browser.
If your architecture wants the backend to own the callback instead:
- let your backend receive
launch_code - let your backend perform the exchange with Digesty
- let your backend create its own session
- set a
Secure,HttpOnlycookie - redirect the browser to a clean app URL
That is a valid architecture, but it is not implemented by this SDK today.
