# Using Openfort signer

:::info
If you want to check out a live sample app using Openfort signers, check out the [live demo with RapidFire](https://commerce.fort.dev/).
:::

## Configure Authentication Methods

Navigate to the **auth providers** page on the [Openfort dashboard](https://dashboard.openfort.io) by selecting your project and then clicking **Auth providers Methods** in the side bar in the [users page](https://dashboard.openfort.io/players). Select the account types you'd like users to be able to login with. For more information on how to enable social logins, check out the [dashboard docs](/docs/configuration/social-login).

:::note

As soon as you enable each provider from your dashboard, it will automatically appear as an option in the authentication page.

:::
From the [Openfort Dashboard](https://dashboard.openfort.io) for select your desired app, navigate to the [developers page](https://dashboard.openfort.io/api-keys) in the top bar. On the de tab, find the API keys section. Get your Openfort API keys, you will need it in the next step.

You will find two keys:

* **Publishable Key**: This value can be safely exposed in a client-side environment.
* **Secret Key**: This value should never be exposed in a client-side environment. It should be kept secure and used only in a server-side environment. Learn more on how to use it in the [server-side guide](/docs/products/server). You can [further secure it](/docs/configuration/api-keys) for production applications.

To generate non custodial wallets, you will need to create a Shield instance. At the [API keys page](https://dashboard.openfort.io/api-keys), scroll down to the Shield section and click on the **Create Shield keys** button.
A **one time pop-up** will appear with a variable called **encryption share**. Its very important that you store it safely. You will not be able to see it again.

Then, in your page, you will see two Shield keys:

* **Publishable Key**: This value can be safely exposed in a client-side environment.
* **Secret Key**: This value should never be exposed in a **client**-side environment.

## Creating your wallet UI

The **wallet UI** is how information is shown to wallet users. Under your **`wallet UI` folder**, install the latest version of [Ecosystem SDK](https://www.npmjs.com/package/@openfort/ecosystem-js) using your package manager of choice. Remember to comply with the requirements to benefit from code splitting.

<HoverCardLayout>
  <HoverCardLink description="Find your ecosystem ID in the dashboard settings section" href="https://dashboard.openfort.io/settings/project/overview" title="Get ecosystem ID" subtitle="Dashboard settings" icon={Settings} color="#0EA5E9" />
</HoverCardLayout>

#### Create React App

:::code-group

```tsx [index.tsx]
// Set your publishable key, shield publishable key and ecosystem id. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.openfort.io/api-keys
// See your ecosystem ID here: https://dashboard.openfort.io/settings/project/overview
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter, useNavigate } from 'react-router-dom';
import { WagmiProvider } from 'wagmi';
import { QueryClientProvider } from '@tanstack/react-query';

import * as Wagmi from './lib/Wagmi';
import * as Query from './lib/Query'
import { EcosystemProvider, OpenfortProvider, RecoveryMethod } from '@openfort/ecosystem-js/react';

async function getShieldSession(accessToken:string):Promise<string> {
  // When using AUTOMATIC embedded wallet recovery, an encryption session is required.
  // Sample encryption session generation backend: https://github.com/openfort-xyz/ecosystem-sample/tree/main/wallet-ui/backend
  const response = await fetch(`${process.env.REACT_APP_BACKEND_URL}/api/protected-create-encryption-session`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${accessToken}`
    }
  });

  if (!response.ok) {
    throw new Error('Failed to fetch shield session');
  }

  const data = await response.json();
  return data.session;
}

const ProtectedRoute = ({ component, ...args }: any) => {
  const Component = withAuthenticationRequired(component, {
    onRedirecting: () => <Loading />,
  });
  return <Component {...args} />;
};

export default function Providers({children}: {children: React.ReactNode}) {
const nav = useNavigate()
return (
  <EcosystemProvider
    appName='Rapidfire ID'
    navigateTo={(appState) => {
      nav({
        pathname: appState?.to,
        search: appState?.search
      })
    }}
    theme='midnight'
    logoUrl='https://purple-magnificent-bat-958.mypinata.cloud/ipfs/QmfQrh2BiCzugFauYF9Weu9SFddsVh9qV82uw43cxH8UDV'
  >
    <WagmiProvider config={Wagmi.config}>
      <QueryClientProvider
        client={Query.client}
      >
        <OpenfortProvider
          // If you're using third party authentication with Openfort (i.e. your own auth or providers like Firebase), set thirdPartyAuthentication to true.
          thirdPartyAuthentication={false}
          ecosystemId={process.env.REACT_APP_OPENFORT_ECOSYSTEM_ID}
          onRedirectCallback={(appState) => {
            return nav(appState?.returnTo || window.location.pathname);
          }}
          overrides={{}}      
          publishableKey={process.env.REACT_APP_OPENFORT_PUBLIC_KEY}
          // To choose your recovery method, set the recoveryMethod to either 'AUTOMATIC' or 'PASSWORD'
          // Learn more about configure embedded signers: https://openfort.io/docs/products/embedded-wallet/react/wallets/
          embeddedSignerConfiguration={
            {
              shieldPublishableKey: process.env.REACT_APP_SHIELD_PUBLIC_KEY,
              recoveryMethod: RecoveryMethod.AUTOMATIC,
              // If you're using AUTOMATIC recovery, you need to provide an encryption session. 
              // If you're only using PASSWORD recovery, you can remove this function.
              getEncryptionSessionFn(getAccessToken) {
                return getShieldSession(getAccessToken);
              }
            }
          }
        >
          {children}
        </OpenfortProvider>
      </QueryClientProvider>
    </WagmiProvider>
  </EcosystemProvider>
);
}
```

```tsx [App.tsx]
import { 
  WalletGrantPermissions,
  WalletSendCalls, 
  EthRequestAccounts, 
  EthSendTransaction, 
  EthSignTypedDataV4, 
  PersonalSign, 
  WalletShowCalls,
  withAuthenticationRequired,
  Settings,
  UnsupportedMethod,
  LoginMethods,
  Recover
} from '@openfort/ecosystem-js/react';
import { Route, Routes } from 'react-router-dom';
import Loading from './Loading';


const ProtectedRoute = ({ component, ...args }: any) => {
  const Component = withAuthenticationRequired(component, {
    onRedirecting: () => <Loading />,
  });
  return <Component {...args} />;
};

function App() {
  return (
    <Routes>
      {/* Required endpoints for EIP-1193 methods */}
      <Route path='/sign/personal-sign' element={<ProtectedRoute component={PersonalSign} />} />
      <Route path='/sign/eth-sign-typed-data-v-4' element={<ProtectedRoute component={EthSignTypedDataV4} />} />
      <Route path='/sign/eth-send-transaction' element={<ProtectedRoute component={EthSendTransaction} />} />
      <Route path='/sign/wallet-grant-permissions' element={<ProtectedRoute component={WalletGrantPermissions} />} />
      <Route path='/sign/wallet-show-calls' element={<ProtectedRoute component={WalletShowCalls} />} />
      <Route path='/sign/wallet-send-calls' element={<ProtectedRoute component={WalletSendCalls} />} />
      <Route path='/sign/eth-request-accounts' element={<ProtectedRoute component={EthRequestAccounts} />} />
      <Route path='/sign/settings' element={<ProtectedRoute component={Settings} />} />
      <Route path='/sign/' element={<ProtectedRoute component={Loading} />} />
      <Route path='*' element={<UnsupportedMethod />} />
      
      {/* OpenfortProvider specific methods for EmbeddedSigner recovery (password based) and authentication */}
      <Route path='/sign/authenticate' element={<LoginMethods />} />
      <Route path='/sign/recover' element={<Recover />} />
    </Routes>
  );
}

export default App;
```

```tsx [Loading.tsx]
import { Layout } from '@openfort/ecosystem-js/react';
import React from 'react';

const Loading: React.FC = () => {
  return (
    // Not how its wrapped in the Layout component, to ensure the styles are applied
    <Layout>
      <svg
        width="20"
        height="20"
        viewBox="0 0 20 20"
        className="animate-spin"
      >
        <circle 
          cx="25" 
          cy="25" 
          r="20" 
          fill="none" 
          stroke="#ffffff" 
          strokeWidth="5"
          strokeLinecap="round"
          strokeDasharray="80"
          strokeDashoffset="60"
        />
      </svg>
      
      {/* Adding custom styles */}
      <style
        dangerouslySetInnerHTML={{
          __html: `
            .animate-spin {
              animation: spin 1s linear infinite;
            }
            
            @keyframes spin {
              from {
                transform: rotate(0deg);
              }
              to {
                transform: rotate(360deg);
              }
            }
          `
        }}
      />
    </Layout>
  );
};

export default Loading;
```

```ts [lib/Wagmi.ts]
// Configure your wagmi instance with the chains you want to support: https://wagmi.sh/react/guides/chain-properties
import { http, createConfig } from 'wagmi'
import { baseSepolia, polygonAmoy } from 'wagmi/chains'

export const config = createConfig({
  chains: [polygonAmoy, baseSepolia],
  transports: {
    [polygonAmoy.id]: http(),
    [baseSepolia.id]: http(),
  },
})

declare module 'wagmi' {
  interface Register {
    config: typeof config
  }
}
```

```ts [lib/Query.ts]
import { QueryClient } from '@tanstack/react-query'

export const client = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 1000 * 60 * 60 * 24, // 24 hours
      retry: 0,
    },
  },
})
```

:::

### Configure Supported Chains

As you can see above, its required that you configure [Wagmi](https://wagmi.sh) and the chains you plan on enabling for your wallet.

Note that, to enable transaction simulation through asset changes, the **Ecosystem SDK** internally requires the [`eth_simulateV1`](https://github.com/ethereum/execution-apis/pull/484) [JSON-RPC method](https://github.com/ethereum/execution-apis/pull/484), so you will need to provide an RPC endpoint that supports this method (or disable simulation through the EcosystemProvider using `disableTransactionSimulation`).

## Sample Openfort authentication

<HoverCardLayout>
  <HoverCardLink description="Sample wallet UI with all the necessary screens" href="https://github.com/openfort-xyz/ecosystem-sample/tree/main/wallet-ui/frontend" title="Wallet UI Sample" subtitle="GitHub repository" icon={Layout} color="#10B981" />
</HoverCardLayout>

## Using a custom auth provider

Openfort's global wallets are fully-compatible with any authentication provider that supports JWT-based, stateless authentication.

* Use a custom authentication provider (easy to integrate alongside your existing stack).

## Sample third-party authentication

<HoverCardLayout>
  <HoverCardLink description="Complete sample using Firebase as an authentication provider for the global wallet" href="https://github.com/openfort-xyz/ecosystem-sample/tree/feat/third-party-auth" title="Wallet SDK Sample" subtitle="GitHub repository" icon={Code} color="#8B5CF6" />
</HoverCardLayout>
