@sparkvault/sdk-mobile
v4.5.6
Published
Mobile SDK for SparkVault Identity, vault, folder, and ingot workflows
Downloads
3,321
Maintainers
Readme
SparkVault Mobile SDK
Mobile SDK for SparkVault Identity, vault, folder, and ingot workflows.
Install
npm install @sparkvault/sdk-mobileCreate a Client
import * as FileSystem from 'expo-file-system/legacy';
import { createSparkVaultMobileClient } from '@sparkvault/sdk-mobile';
export const sparkVault = createSparkVaultMobileClient({
tokenStorage,
apiBaseUrl: 'https://api.sparkvault.com/v1',
identityBaseUrl: 'https://auth.sparkvault.com',
identityAccountId: 'acc_00000000000000000000000000000000',
userAgent: 'SparkVault/1.0.0 (Mobile)',
fetch: xhrFetch,
fileReader: {
readAsBase64: (fileUri, { position, length }) =>
FileSystem.readAsStringAsync(fileUri, {
encoding: 'base64',
position,
length,
}),
},
fileDownloader: {
download: async (url, fileUri, options) => {
const resumable = FileSystem.createDownloadResumable(
url,
fileUri,
{},
progress => options?.onProgress?.({
bytesWritten: progress.totalBytesWritten,
bytesTotal: progress.totalBytesExpectedToWrite || undefined,
})
);
const result = await resumable.downloadAsync();
return result ? { uri: result.uri, status: result.status, headers: result.headers } : null;
},
getInfo: async (fileUri) => {
const info = await FileSystem.getInfoAsync(fileUri);
return { exists: info.exists, sizeBytes: info.exists ? info.size : undefined };
},
delete: (fileUri) => FileSystem.deleteAsync(fileUri, { idempotent: true }),
},
});Dependency contract
The SDK depends on tweetnacl for Ed25519 Identity JWT verification and declares react/react-native as peer dependencies for the optional native Identity dialog. Platform behavior stays behind adapters so the SDK is portable across React Native runtimes.
| Adapter | Required | Default if omitted |
|---------|----------|--------------------|
| tokenStorage | Yes | Throws at client construction |
| identityAccountId | Yes (must start with acc_) | Throws at client construction |
| fetch | No | Falls back to globalThis.fetch; throws if neither exists |
| fileReader | Only for ingots.uploadFromUri | Throws on first upload-from-URI call |
| fileDownloader | Only for ingots.downloadToFile | Throws on first file-download call |
| passkeyProvider | Only for passkey sign-in UI | Passkey is hidden from the Identity dialog |
| logger | No | No-op logger |
Modules
products.identity: Identity Product config, OTP/passkey login, JWKS/JWT verification, second-factor submission, and post-login backup/recommendation flows.account: First-party Core session — Identity-token exchange, signup completion, profile, and account APIs.vaults: Vault CRUD, unseal/seal, sharing, access retention, and upload portal/widget settings.folders: Folder CRUD, breadcrumbs, folder moves, and ingot moves.ingots: List/search/get, URI streaming upload/replace, rename/delete/move, sharing, read-only audit logs, SDK-managed file downloads, and the discretecreateUpload(Forge upload URL + token) /createDownloadLinkprimitives.health: Root API availability checks.sparks: SparkSync ephemeral secrets — list/get/create/delete and SparkLink sharing (share/getShare/unshare).entropy: HSM-backed entropy generation.pushTokens: Expo push-token registration/removal.billing: Subscription status and usage, Stripe portal session, and native in-app purchase receipt validation.
Identity Dialog
SparkVaultIdentityDialog is the mobile equivalent of the web SDK Identity popup. It fetches Identity Product config, derives email/phone input from enabled delivery methods, offers enabled mobile-supported methods (passkey, otp_email, otp_sms, otp_voice), applies configured branding and light/dark mode, and returns the raw signed Identity JWT plus JWKS metadata. Passkey authentication is discoverable and routes by the SVID in the WebAuthn user handle.
import * as Passkey from 'react-native-passkeys';
import {
SparkVaultIdentityDialog,
type MobilePasskeyProvider,
} from '@sparkvault/sdk-mobile/identity-dialog';
const passkeyProvider: MobilePasskeyProvider = {
isSupported: () => Passkey.isSupported(),
authenticate: async (options) => {
const credential = await Passkey.get({
challenge: options.challenge,
timeout: options.timeout,
rpId: options.rpId,
userVerification: options.userVerification,
});
return credential
? {
id: credential.id,
rawId: credential.rawId,
type: 'public-key',
response: {
clientDataJSON: credential.response.clientDataJSON,
authenticatorData: credential.response.authenticatorData,
signature: credential.response.signature,
// Required: the server resolves the SVID from the userHandle.
userHandle: credential.response.userHandle,
},
}
: null;
},
};
<SparkVaultIdentityDialog
client={sparkVault}
visible={visible}
passkeyProvider={passkeyProvider}
onCancel={() => setVisible(false)}
onSuccess={async (result) => {
await sparkVault.products.identity.verifyIdentityToken(result.token, { jwks: result.jwks });
const session = await sparkVault.account.exchangeIdentityToken(result.token);
// Continue only after local verification and Core exchange succeed.
}}
/>;Client-side JWT verification is an app integrity gate. Third-party backends must still verify the token server-side with the JWKS endpoint and key product records by the returned svid (sub is also the SVID for managed Identity tokens).
exchangeIdentityToken() is for SparkVault Core mobile sessions. Third-party mobile apps that use SparkVault Identity as their login provider should either verify the Identity JWT server-side and issue their own app session keyed by svid, or use the OIDC authorization-code flow with PKCE. Native apps must keep refresh tokens in OS secure storage; browser-only HttpOnly cookie guidance applies to web/BFF deployments.
Health Check
const status = await sparkVault.health.check();
const online = await sparkVault.health.isOnline();Ingot Upload
const session = await sparkVault.vaults.unseal(vaultId, { vmk });
await sparkVault.ingots.uploadFromUri({
vaultId,
vat: session.vat,
fileUri,
fileSize,
name: 'receipt.pdf',
contentType: 'application/pdf',
onProgress: (uploaded, total) => console.log(uploaded / total),
});
await sparkVault.ingots.replaceFromUri({
vaultId,
ingotId,
vat: session.vat,
fileUri,
fileSize,
name: 'receipt.pdf',
contentType: 'application/pdf',
});Uploads use Forge with tus v1.0.0 and read file chunks through the configured
fileReader adapter. Generated content should be staged to a file URI first so
all uploads use the same streaming path.
Ingot Download
const result = await sparkVault.ingots.downloadToFile({
vaultId,
ingotId,
vat: session.vat,
fileUri: cacheFileUri,
expectedSizeBytes,
onProgress: (downloaded, total) => console.log(downloaded / total),
});Downloads use the configured fileDownloader adapter for one canonical
streaming path across every supported file size. Production adapters should
honor abortSignal and timeoutMs, and should throw on transport failure
instead of writing an error response as a successful file.
