Customize Capsule

The Capsule modal is the easiest way to get integrated. The modal implements all session management and cookie logic needed for account creation, login, and account management.
The modal also has configuration options for colors, light/dark themes, integrated on/off ramps. and custom images. Docs coming soon- in the meantime, ask us for more information on how to add these!

Capsule Passkey Prompt

The passkey screen also supports custom images and colors. Docs coming soon- in the meantime, ask us for more information on how to add these!

User-Facing Emails

User-facing emails also offer support for custom banner images and redirect links.

[Advanced] Mobile Overrides

With Capsule, we offer flexibility into state management to fit more easily with the varied ways different applications may store information. While we provide default implementations for React Native using well-known libraries, we understand that each application has unique requirements. Hence, we allow and even encourage clients to customize these implementations to cater to their specific business and user needs.

Overview

Consider ReactNativeCapsuleWallet, our default implementation. This implementation is intentionally opinionated to provide a clear integration pathway. However, every component responsible for maintaining objects across sessions can be replaced using inheritance.
class ReactNativeCapsuleWallet extends CapsuleBaseWallet {
getCapsuleSigner(userId: string, ensureSessionActive: () => Promise<void>): CapsuleBaseSigner {
return new ReactNativeCapsuleSigner(userId, ensureSessionActive)
}
getSignersStorage(): SignersStorage {
return new ReactNativeSignersStorage()
}
getChallengeStorage(userId: string): ChallengeStorage {
return new ReactNativeSessionStorage(userId)
}
async getUserId(): Promise<string> {
return (await AsyncStorage.getItem(USER_ID_TAG)) as string
}
}
This design takes into account the need for persistent data storage, offering consistent keychain storage that helps prevent accidental key loss. Additionally, it supports session challenge functionality, which requires keychain interaction across sessions.
Although we provide default implementations, developers can extend our class and override the following methods as per their requirements:
  • getSignersStorage is responsible for returning an object that satisfies the SignersStorage interface, handling the persistence of the public address(es) associated with the wallet.
  • getChallengeStorage is responsible for returning an object that satisfies the ChallengeStorage interface. It provides a public key and signs the challenge given by the Capsule server (secp256r1).
  • getUserId is responsible for obtaining the userId. Here, we assume it stays in the local storage under a given tag. However, this will not work if there is more than one account.
  • getCapsuleSigner is responsible for returning an object that satisfies the CapsuleBaseSigner interface. Here, we also provide an implementation needed to persist (securely) the key share across sessions. However, the Wallet can easily replace it with its own opinionated class.
Let's take a look at ReactNativeCapsuleSigner:
const { CapsuleSignerModule } = NativeModules;
export class ReactNativeCapsuleSigner extends CapsuleBaseSigner {
getSignerModule(): SignerModule {
return CapsuleSignerModule;
}
getPrivateKeyStorage(account: string): PrivateKeyStorage {
return new ReactNativePrivateKeyStorage(account);
}
}
  • getPrivateKeyStorage is tasked with returning an object that adheres to the PrivateKeyStorage interface. This object is responsible for persisting the private key.
  • getSignerModule is tasked with returning an object that adheres to the SignerModule interface. This object is responsible for handling Multi-Party Computation (MPC) operations.

Suggestions for Customization

We acknowledge that our default implementations may not cover all your specific needs. We encourage you to explore them within the react-native directory of our codebase. Based on your requirements, feel free to extend our class or even the base, abstract class, and implement additional functionalities as needed. Remember, we're always here to assist you along your customization journey!