Skip to main content
The Sign In With X feature enables decentralized applications to authenticate users seamlessly across multiple blockchain networks, such as Ethereum, Polygon or Solana. The user can connect and then sign a message with their account to prove ownership of the account.

SIWX Custom Implementation

SIWX is developed to work as a plugin system for AppKit and to enable correctly it you need to fulfill the expected interface within the createAppKit function.

SIWXConfig interface

This is the interface that you need to implement to create your own SIWX feature.
interface SIWXConfig {
  createMessage: (input: SIWXMessage.Input) => Promise<SIWXMessage>
  addSession: (session: SIWXSession) => Promise<void>
  revokeSession: (chainId: CaipNetworkId, address: string) => Promise<void>
  setSessions: (sessions: SIWXSession[]) => Promise<void>
  getSessions: (chainId: CaipNetworkId, address: string) => Promise<SIWXSession[]>
  getRequired?: () => boolean
  signOutOnDisconnect?: boolean
}
All the typings used are exposed by @reown/appkit-react-native package. You may check the source code here.
/**
 * This interface represents the SIWX configuration plugin, which is used to create and manage SIWX messages and sessions.
 * You may use it to create a custom implementation following your needs, but watch close for the methods requirements.
 */
export interface SIWXConfig {
  /**
   * This method will be called to create a new message to be signed by the user.
   *
   * Constraints:
   * - The message MUST be unique and contain all the necessary information to verify the user's identity.
   * - SIWXMessage.toString() method MUST be implemented to return the message string.
   *
   * @param input SIWXMessage.Input
   * @returns SIWXMessage
   */
  createMessage: (input: SIWXMessage.Input) => Promise<SIWXMessage>

  /**
   * This method will be called to store a new single session.
   *
   * Constraints:
   * - This method MUST verify if the session is valid and store it in the storage successfully.
   *
   * @param session SIWXSession
   */
  addSession: (session: SIWXSession) => Promise<void>

  /**
   * This method will be called to revoke all the sessions stored for a specific chain and address.
   *
   * Constraints:
   * - This method MUST delete all the sessions stored for the specific chain and address successfully.
   *
   * @param chainId CaipNetworkId
   * @param address string
   */
  revokeSession: (chainId: CaipNetworkId, address: string) => Promise<void>

  /**
   * This method will be called to replace all the sessions in the storage with the new ones.
   *
   * Constraints:
   * - This method MUST verify all the sessions before storing them in the storage;
   * - This method MUST replace all the sessions in the storage with the new ones succesfully otherwise it MUST throw an error.
   *
   * @param sessions SIWXSession[]
   */
  setSessions: (sessions: SIWXSession[]) => Promise<void>

  /**
   * This method will be called to get all the sessions stored for a specific chain and address.
   *
   * Constraints:
   * - This method MUST return only sessions that are verified and valid;
   * - This method MUST NOT return expired sessions.
   *
   * @param chainId CaipNetworkId
   * @param address string
   * @returns
   */
  getSessions: (chainId: CaipNetworkId, address: string) => Promise<SIWXSession[]>

  /**
   * This method determines whether the wallet stays connected when the user denies the signature request.
   *
   * @returns {boolean}
   */
  getRequired?: () => boolean

  /**
   * This method determines whether the session should be cleared when the user disconnects.
   *
   * @default true
   * @returns {boolean}
   */
  signOutOnDisconnect?: boolean
}

/**
 * This interface represents a SIWX session, which is used to store the user's identity information.
 */
export interface SIWXSession {
  data: SIWXMessage.Data
  message: string
  signature: string
  cacao?: Cacao
}

/**
 * This interface represents a SIWX message, which is used to create a message to be signed by the user.
 * This must contain the necessary information to verify the user's identity and how to generate the string message.
 */
export interface SIWXMessage extends SIWXMessage.Data, SIWXMessage.Methods {}

export namespace SIWXMessage {
  /**
   * This interface represents the SIWX message data, which is used to create a message to be signed by the user.
   */
  export interface Data extends Input, Metadata, Identifier {}

  /**
   * This interface represents the SIWX message input.
   * Here must contain what is different for each user of the application.
   */
  export interface Input {
    accountAddress: string
    chainId: CaipNetworkId
    notBefore?: Timestamp
  }

  /**
   * This interface represents the SIWX message metadata.
   * Here must contain the main data related to the app.
   */
  export interface Metadata {
    domain: string
    uri: string
    version: string
    nonce: string
    statement?: string
    resources?: string[]
  }

  /**
   * This interface represents the SIWX message identifier.
   * Here must contain the request id and the timestamps.
   */
  export interface Identifier {
    requestId?: string
    issuedAt?: Timestamp
    expirationTime?: Timestamp
  }

  /**
   * This interface represents the SIWX message methods.
   * Here must contain the method to generate the message string and any other method performed by the SIWX message.
   */
  export interface Methods {
    toString: () => string
  }

  /**
   * The timestamp is a UTC string representing the time in ISO 8601 format.
   */
  export type Timestamp = string
}

/**
 * The Cacao interface is a reference of CAIP-74 and represents a chain-agnostic Object Capability (OCAP).
 * https://chainagnostic.org/CAIPs/caip-74
 */
export interface Cacao {
  h: Cacao.Header
  p: Cacao.Payload
  s: {
    t: 'eip191' | 'eip1271'
    s: string
    m?: string
  }
}

export namespace Cacao {
  export interface Header {
    t: 'caip122'
  }

  export interface Payload {
    domain: string
    aud: string
    nonce: string
    iss: string
    version?: string
    iat?: string
    nbf?: string
    exp?: string
    statement?: string
    requestId?: string
    resources?: string[]
    type?: string
  }
}

Constraints

You are able to implement the SIWXConfig in the way you would like, but some constraints MUST be followed to make sure that AppKit can interact with it correctly and it will work as expected:

createMessage

This method will be called to create a new message to be signed by the user.
  • The message MUST be unique and contain all the necessary information to verify the user’s identity.

addSession

This method will be called to store a new single session.
  • This method MUST verify if the session is valid and store it in the storage successfully.

revokeSession

This method will be called to revoke all the sessions stored for a specific chain and address.
  • This method MUST delete all the sessions stored for the specific chain and address successfully.

setSessions

This method will be called to replace all the sessions in the storage with the new ones.
  • This method MUST verify all the sessions before storing them in the storage;
  • This method MUST replace all the sessions in the storage with the new ones successfully otherwise it MUST throw an error.

getSessions

This method will be called to get all the sessions stored for a specific chain and address.
  • This method MUST return only sessions that are verified and valid;
  • This method MUST NOT return expired sessions.

Example

Here is an example of how you can implement use your SIWXConfig interface:
import { createAppKit, type SIWXConfig } from '@reown/appkit-react-native'

const siwx: SIWXConfig = {
  createMessage: async (input) => {
    // Implement your logic to create a message
    return 'my message'
  },
  addSession: async (session) => {
    // Implement your logic to add a session
  },
  revokeSession: async (chainId, address) => {
    // Implement your logic to revoke a session
  },
  setSessions: async (sessions) => {
    // Implement your logic to set sessions
  },
  getSessions: async (chainId, address) => {
    // Implement your logic to get sessions
    return []
  },
  getRequired: () => {
    // Return whether the wallet should stay connected when user denies signature
    return false
  },
  signOutOnDisconnect: true // Whether to clear sessions when user disconnects
}

createAppKit({
  // ... your configuration
  siwx
})
I