🛠️Configuring SSX

SSX Configuration Guide

Overview

SSX works on both server and client without configuration. However, you can access a robust feature set by enabling and configuring some available options.

Below are a few examples and explanations of the configuration options:

Enabling DAO Login

SSX enables an easy way for users to sign in on behalf of a Gnosis Safe multisig on your platform that they have been delegated access to. It provides an easy flow that users can take to either log in as themselves or on behalf of the multisig. Here is an example of how you enable that field:

const buttonHandlerWeb3ModalGnosis = async () => {
    const ssx = new SSX({
      enableDaoLogin: true,
    });
    await ssx.signIn();
};

Customizing Fields in the SIWE Message

SSX enables developers an easy way to configure the fields of their Sign-in with Ethereum (SIWE) message using the siweConfig option. This option allows you to overwrite the fields found in the SIWE message. This option can allow you to create SIWE messages that may not be valid in specific environments, so use this option with care.

const buttonHandlerWeb3ModalGnosis = async () => {
    const ssx = new SSX({
      siweConfig: {
        statement: "Sign in to use our service today!"
        requestId: "unique-id-for-specific-purpose",
      },
    });
    await ssx.signIn();
};

Config Options

SSX-Client Configuration Options

The configuration options for SSX are defined here and include: enableDaoLogin, providers, and siweConfig.

SSX has support for lookup on the DelegationRegistry Smart Contract, used by Gnosis Safe, built in. This enables a user to sign in on behalf of a Gnosis Safe, or any other address that has delegated access to that user. Enabling enableDaoLogin prompts the user to select if they want to sign in with their Externally Owned Account (their wallet) or on behalf of an address they are a delegee of. A detailed explanation of the DAO Login Workflow is available here.

const ssx = new SSX({
    enableDaoLogin: true,
});

This is an optional field to enable ENS resolution when signing in. After the sign-in, the ENS data will be available with all other session data. resolveEns can be a boolean (default to false) or an object.

/* resolve ENS domain and avatar on client */
const ssx = new SSX({
  resolveEns: true
});

// OR

/* resolve ENS domain and/or avatar on client or server */
const ssx = new SSX({
  resolveEns: {
    resolveOnServer: true, // false as default
    resolve: {
      domain: true,
      avatar: false
    }
  }
});

/* You can resolve ENS at any time even if you
 * don't want to enable ENS resolution globally */
 const ensData = await ssx.resolveEns("0xADDRESS", {
    domain: false,
    avatar: true,
  });

resolveLens

This is an optional field to enable Lens profile resolution when signing in. After a user signs-in, the Lens data will be available with all other session data. resolveLens can be a boolean (default to false) or 'onServer'.

This feature is available for Polygon Mainnet and Mumbai Testnet. Visit the Lens docs for more information.

/* resolve Lens profiles on client */
const ssx = new SSX({
  resolveLens: true
});

// OR

/* resolve Lens profiles on server */
const ssx = new SSX({
  resolveLens: 'onServer'
});

/* You can resolve Lens profiles at any time even if you
 * don't want to enable Lens resolution globally */
 const lensProfiles = await ssx.resolveLens("0xADDRESS");

siweConfig

siweConfig is a field that lets you set default values for SIWE messages. These values will overwrite fields that are automatically generated by SSX and could lead to invalid messages if misconfigured. Valid options can be found here.

const ssx = new SSX({
    siweConfig: { requestId: "some_id" },
});

providers

SSX acts as a super-provider for your dapp to make multiple resources available to your dapp with minimal configuration: a web3 provider (to connect to your wallet), an RPC provider (to connect to blockchains) and a server provider (to connect to a server using ssx).

Dapps interact with the Ethereum network by accessing the Ethereum JavaScript provider API, which is usually injected into the browser by an Ethereum wallet. SSX works with any wallet by connecting to the wallet's implementation of Web3Provider, which is passed to the config as seen below.

SSX then manages this wallet connection, creates and displays the Sign-in with Ethereum message, and handles signed messages.

const ssx = new SSX({
    providers: { web3: { driver: await web3modal.connect() } },
});

providers.server

The server field is an optional reference to a corresponding server running ssx-server. Providing the host field enables automatic communication with the server to establish sessions upon successful SIWE signing.

ssx and ssx-server have default paths configured for the endpoints (nonce: '/ssx-nonce', login: '/ssx-login' and logout: '/ssx-logout'), but you can override it by providing the property routes. It isn't necessary to override all of them, you can only override one of them.

For more information on configuring ssx-server, check out the SSX Quickstart:

const ssx = new SSX({
    providers: { 
        server: { 
            host: 'http://localhost:3001' 
            routes: {
                nonce: '/ssx-custom-nonce',
                login: '/ssx-custom-login',
                logout: '/ssx-custom-logout',
            }
        } 
    }
});

Additionally, you can override the configuration of the API Request for any of the routes. This allows you make any custom request to an endpoint to get the nonce, login, or logout.

const ssx = new SSX({
    providers: { 
        server: { 
            host: 'http://localhost:3001' 
            routes: {
                nonce:  {
                    url: '/ssx-custom-nonce',
                    method: 'post'
                }
            }
        } 
    }
});

For issues talking to custom endpoints, the options available in the Axios Request Config are valid configuration options and can be used to modify the requests that ssx sends.

SSX Server supports all JSON RPC providers that are currently supported by ethers, requiring only the credentials from the desired provider to instantiate it. The SSX library provides valid enumerated options for various RPC providers, but developers can also just use the valid strings, as seen below. A list of supported RPC providers can be found here.

import { SSX, SSXRPCProviders, SSXInfuraProviderNetworks } from '@spruceid/ssx-server';

const ssx = new SSX({
    providers: {
      rpc: {
        service: SSXRPCProviders.SSXInfuraProvider,
        network: SSXInfuraProviderNetworks.MAINNET,
        apiKey: process.env.INFURA_API_KEY ?? "",
      },
    },
});

// OR 

const ssx = new SSX({
    providers: {
      rpc: {
        service: "infura",
        network: "homestead",
        apiKey: process.env.INFURA_API_KEY ?? "",
      },
    },
});

// RPC usage example
const rpcExample = async () => {
  await ssx.signIn();
  const address = ssx.address()
  const userbalance = await ssx.provider.getBalance(address);
  const currentBlock = await ssx.provider.getBlockNumber();
}

SSX-Server Configuration Options

The configuration options for ssx-server are defined here and include: signingKey, useSecureCookies, and providers.

SSX Server supports multiple server configurations. To explore setting a specific server environment with SSX, check out Configuring SSX Server

This is an optional, string field. It is the key that is used to sign cookies to prevent cookie tampering on the client. The server will issue unsigned cookies if this field is not provided. It is recommended for production environments.

const ssx = new SSXServer({
  signingKey: process.env.SSX_SIGNING_KEY,
});

This is an optional, boolean field. It adds extra protection to your cookies by changing their attributes to be more secure. This defaults to true in production environments.

Setting this tofalse is insecure and not recommended for production environments!

const ssx = new SSXServer({
  useSecureCookies: true,
});

providers

If you are using enableDaoLogin at your front-end application you will need to also setup a provider for the SSXServer. By doing so you will also have access to that provider in any of your routes by getting req.ssx.provider, which will also make it easier if you have to make any RPC calls to a node.

Metrics is an optional, object field. It contains the service, ssx, and the apiKey that is used when sending metrics to the SSX Dashboard. This ties your server instance and its metrics and logs to your platform account.

import { SSXServer } from "@spruceid/ssx-server";

const ssx = new SSXServer({
  providers: {
    metrics: { service: "ssx", apiKey: process.env.SSX_API_KEY },
  },
});

SSX Server supports all JSON RPC providers that are currently supported by ethers, requiring only the credentials from the desired provider to instantiate it.

import { SSXServer } from "@spruceid/ssx-server";

const ssx = new SSXServer({
  providers: {
    rpc: { service: "infura", apiKey: process.env.INFURA_API_KEY },
  },
});

// later...
const currentBlock = await ssx.provider.getBlockNumber();

This optional field is for managing the session store. It includes a sessionOptions field and a store connector function. Under the hood, SSX connects to session stores that implement express-session's EventEmitter API and uses the same configuration options to do so. These fields are automatically set by your SSX configuration

The store connector is a function that is run on initialization that initializes and connects to the session store being used. It should return a configured instance of a store. An example implementation using SSX and Redis of this is available here.

If providers.sessionConfig is not provided, SSX Server defaults to using an in-memory store that resets with the server. It is recommended to use a compatible persistent store. Check out Scaling SSX Server to learn more.

import { SSXServer } from "@spruceid/ssx-server";

const ssx = new SSXServer({
  providers: {
    sessionConfig: {
      sessionOptions: {
        // ex: Recognize cookies signed by other keys
        secret: [process.env.SSX_SIGNING_KEY, process.env.OTHER_COOKIE_KEY]
      },
      store: (session) => {
        // ex: dynamodb for session store [connect-dynamodb](https://www.npmjs.com/package/connect-dynamodb)
        const DynamoDBStore = require('connect-dynamodb')(session);
        const dynamoDBoptions = {}; // configure to connect
        return new DynamoDBStore(dynamoDBoptions)
      },
    },
  },
});

Last updated