> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solanamobile.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Caching MWA Authorization

> Customize the authorization caching layer used by MobileWalletProvider to persist wallet connections across app sessions.

<Note>
  This guide is for **advanced users** who want to customize how wallet authorization details are cached and persisted.
  If you're using `MobileWalletProvider` with the default settings, authorization caching is already handled for you with `AsyncStorage`.
</Note>

## Overview

When a user authorizes your dApp with their wallet via MWA, the session returns an `auth_token` and account details. By caching these details, your app can stay "connected" across app restarts without prompting the user to re-authorize every time.

The [`MobileWalletProvider`](https://github.com/wallet-ui/wallet-ui) from `@wallet-ui/react-native-web3js` handles this automatically with a built-in `AsyncStorage` cache. You can swap in your own cache implementation (e.g for encrypted storage) by passing a custom `cache` prop.

## The `Cache` interface

The `cache` prop on `MobileWalletProvider` accepts any object that implements the `Cache<T>` interface:

```tsx theme={null}
interface Cache<T> {
    clear(): Promise<void>;
    get(): Promise<T | undefined>;
    set(value: T): Promise<void>;
}
```

* **`get()`** — Retrieves the cached authorization on app startup.
* **`set(value)`** — Stores the authorization after the user authorizes.
* **`clear()`** — Removes cached authorization on disconnect/deauthorize.

## Default: `AsyncStorage`

By default, `MobileWalletProvider` uses `@react-native-async-storage/async-storage` to persist authorization data. You don't need to configure anything for this to work:

```tsx theme={null}
import { MobileWalletProvider } from '@wallet-ui/react-native-web3js';

function App() {
  return (
    <MobileWalletProvider
      endpoint="https://api.mainnet-beta.solana.com"
      chain="solana:mainnet"
      identity={{
        name: 'My App',
        uri: 'https://myapp.com',
        icon: 'favicon.ico',
      }}
    >
      {/* cache defaults to AsyncStorage */}
      {children}
    </MobileWalletProvider>
  );
}
```

## Custom cache: `expo-secure-store`

If you want to store authorization details in encrypted storage (e.g for sensitive auth tokens), you can create a custom cache using `expo-secure-store`.

### Install `expo-secure-store`

```shell theme={null}
npx expo install expo-secure-store
```

### Create a Secure Store cache

```tsx theme={null}
import * as SecureStore from 'expo-secure-store';
import { Cache } from '@wallet-ui/react-native-web3js';
import { PublicKey, PublicKeyInitData } from '@solana/web3.js';

const STORAGE_KEY = 'authorization-cache';

function cacheReviver(key: string, value: unknown) {
  if (key === 'publicKey') {
    return new PublicKey(value as PublicKeyInitData);
  }
  return value;
}

export function createSecureStoreCache<T>(): Cache<T> {
  return {
    async get(): Promise<T | undefined> {
      const result = await SecureStore.getItemAsync(STORAGE_KEY);
      if (!result) return undefined;
      try {
        return JSON.parse(result, cacheReviver) as T;
      } catch {
        return undefined;
      }
    },
    async set(value: T): Promise<void> {
      await SecureStore.setItemAsync(STORAGE_KEY, JSON.stringify(value));
    },
    async clear(): Promise<void> {
      await SecureStore.deleteItemAsync(STORAGE_KEY);
    },
  };
}
```

<Note>
  The `cacheReviver` function is needed to properly deserialize `PublicKey` objects from the cached JSON string.
</Note>

### Pass it to `MobileWalletProvider`

```tsx theme={null}
import { MobileWalletProvider } from '@wallet-ui/react-native-web3js';
import { createSecureStoreCache } from './secure-store-cache';

const secureCache = createSecureStoreCache();

function App() {
  return (
    <MobileWalletProvider
      endpoint="https://api.mainnet-beta.solana.com"
      chain="solana:mainnet"
      identity={{
        name: 'My App',
        uri: 'https://myapp.com',
        icon: 'favicon.ico',
      }}
      cache={secureCache}
    >
      {children}
    </MobileWalletProvider>
  );
}
```

***

## Using the bare MWA library

<Accordion title="Manual caching with @solana-mobile/mobile-wallet-adapter-protocol-web3js">
  If you're using the lower-level `@solana-mobile/mobile-wallet-adapter-protocol-web3js` library directly (without `MobileWalletProvider`), you'll need to manage authorization caching yourself.

  ### Check for cached authorization

  When the dApp boots up, check the cache for a prior authorization:

  ```tsx expandable theme={null}
  const App = () => {
      const [currentAccount, setCurrentAccount] = useState<{
          authToken: string;
          pubkey: PublicKey;
      } | null>(null);

      useEffect(() => {
          (async () => {
              const [cachedAuthToken, cachedBase64Address] = await Promise.all([
                  AsyncStorage.getItem('authToken'),
                  AsyncStorage.getItem('base64Address'),
              ]);
              if (cachedBase64Address && cachedAuthToken) {
                  const pubkeyAsByteArray = toByteArray(cachedBase64Address);
                  const cachedCurrentAccount = {
                      authToken: cachedAuthToken,
                      pubkey: new PublicKey(pubkeyAsByteArray),
                  };
                  setCurrentAccount(cachedCurrentAccount);
              }
          })();
      }, []);

      /* ...*/
  }
  ```

  ### Cache on authorize

  Cache the authorization details when the user completes an `authorize` request:

  ```tsx expandable theme={null}
  const [currentAccount, setCurrentAccount] = useState<{
      authToken: string;
      pubkey: PublicKey;
  } | null>(null);

  const handleConnectPress = useCallback(() => {
      transact(async wallet => {
          const {accounts, auth_token} = await wallet.authorize({
              cluster: 'devnet',
              identity: {
                  name: 'My amazing app',
              },
          });
          const firstAccount = accounts[0];
          AsyncStorage.setItem('authToken', auth_token);
          AsyncStorage.setItem('base64Address', firstAccount.address);
          const pubkeyAsByteArray = toByteArray(firstAccount.address);
          const nextCurrentAccount = {
              authToken: auth_token,
              pubkey: new PublicKey(pubkeyAsByteArray),
          };
          setCurrentAccount(nextCurrentAccount);
      });
  }, []);
  ```

  ### Clear cache on deauthorize

  When the user disconnects, invalidate the cache:

  ```tsx theme={null}
  const handleDisconnectPress = useCallback(() => {
      transact(async wallet => {
          if (currentAccount == null) {
              throw new Error('There is no current account to deauthorize');
          }
          await wallet.deauthorize({auth_token: currentAccount.authToken});
          AsyncStorage.clear();
          setCurrentAccount(null);
      });
  }, [currentAccount]);
  ```
</Accordion>
