React Native SDK in Expo - `login` error

:classical_building: Content from Web3Auth Community

This topic was originally posted by marx on 8/4/2025.
This content has been migrated from our previous community forum to preserve valuable discussions.


Hey team, I am facing some 2 issues with the PnP @web3auth/react-native-sdk library.

Context - my Setup

// package.json - Relevant libraries 

“dependencies”: {
“expo”: “^52.0.40”,
“@web3auth/react-native-sdk”: “^8.0.0”,
},
“devDependencies”: {
“buffer”: “^6.0.3”,
“crypto-browserify”: “^3.12.1”,
“empty-module”: “^0.0.2”,
“process”: “^0.11.10”,
“react-native-get-random-values”: “^1.11.0”,
“readable-stream”: “^4.7.0”,
}

Issue #1 - base64FromArrayBuffer is not a function

I have copied the same exact code used in the Expo example’s (App.tsx) over to a Screen in my repo.

The code executed up till the await web3auth.login({ .. }) function where this error was thrown in the Console.

I then ran the example separately and it worked > opened the browser > login > retrieve User Info…etc.

I have set up my project as close as I can to the example as much as I can. Files like these are exactly the same (line by line) in my repo and the example:

  • globals.js
  • metro.config.js

But I still can’t get past this error.

Issue #2 - Custom JWT connection.

We run our own auth backend and have our own custom JWT auth. Users would have already been logged in/authenticated before fetching their Wallets.

We have also followed the Custom Auth guide and created our own Custom Connection in our Web3Auth Dashboard and verified that our token is indeed publicly verifiable using a tool like https://jwt.davetonge.co.uk/.

The problem is that it is not obvious how we can create & retrieve wallet info using the react-native-sdk with a custom connection. Can someone please help point us in the right direction?

Thanks for the detailed report, Marx! Here’s a summary of your issues and what the support team will need to assist you:


Issue #1: base64FromArrayBuffer is not a function Error

Context:

  • SDK: @web3auth/react-native-sdk
  • Version: ^8.0.0
  • Platform: React Native (using Expo)
  • Setup: You’ve matched the official Expo example line-by-line, including globals.js and metro.config.js.
  • Error: Occurs at await web3auth.login({ ... }). The same code works in the official example repo, but not in your project.

Dependencies from package.json:

"expo": "^52.0.40",
"@web3auth/react-native-sdk": "^8.0.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.1",
"empty-module": "^0.0.2",
"process": "^0.11.10",
"react-native-get-random-values": "^1.11.0",
"readable-stream": "^4.7.0"

Next Steps / Request:

  • Could you please share the exact stack trace or a screenshot of the error in your console? This will help pinpoint if it’s a polyfill, import, or bundler issue.
  • Double-check that your babel.config.js and app.json match the example as well, since subtle differences can affect Expo’s bundling.
  • If you’re using a custom Metro or Babel config, please share those snippets.

Reference:


Issue #2: Custom JWT Authentication with React Native SDK

Context:

  • You have a custom backend with JWT-based authentication.
  • You’ve set up a custom verifier in the Web3Auth Dashboard and confirmed your JWT is publicly verifiable.
  • You’re unsure how to use your JWT to create/retrieve wallet info with the SDK.

What You Need To Do:

  1. Configure loginConfig in your Web3Auth initialization:
    const web3auth = new Web3Auth(WebBrowser, {
      clientId: "YOUR_CLIENT_ID",
      network: WEB3AUTH_NETWORK.MAINNET, // or your network
      loginConfig: {
        jwt: {
          verifier: "YOUR_VERIFIER_NAME", // from Dashboard
          typeOfLogin: TypeOfLogin.JWT,
          clientId: "YOUR_CLIENT_ID",
        },
      },
    });
    
  2. Login with your JWT:
    await web3auth.login({
      loginProvider: LOGIN_PROVIDER.JWT,
      redirectUrl: `${scheme}://auth`,
      extraLoginOptions: {
        id_token: "YOUR_JWT_ID_TOKEN", // from your backend
        verifierIdField: "sub", // or the field you use as the user identifier
      },
    });
    
    • Make sure your JWT’s payload field (e.g., sub, email, etc.) matches the “Verifier ID” field set in your Dashboard.
    • If you use a custom JWKS endpoint, ensure it’s public and accessible.

References:

Request:

  • Please share your loginConfig and login code snippet if you’re still seeing issues.
  • If you get a specific error message when attempting JWT login, please include that (or a screenshot).

Summary for Support Team

  • SDK: @web3auth/react-native-sdk v8.0.0
  • Platform: React Native (Expo)
  • Issue 1: base64FromArrayBuffer is not a function at login, despite matching the example repo.
  • Issue 2: Needs guidance on using custom JWT auth with the SDK. Has custom verifier and valid JWT, but unclear on wiring it up.

Let us know if you can provide the requested code snippets or error screenshots for faster troubleshooting!

Note: This response was generated by an AI bot and may require further verification. The Web3Auth support team has tracked this issue and will be responding as soon as possible.

Additionally, we would recommend you to join our biweekly Office Hours to get this resolved even faster. Web3Auth Developer Office Hours

Hey @marx
Hello again
For issue 1 I believe you’ve followed the example line by line for metro.config and globals.js.
But can you please share App.tsx with me. I need to ensure some imports.

For issue 2, please try out the snippet sent by the bot reply just before this post. Let me know if that doesn’t help.

Issue 1

Hey Marhashi, thanks for the quick reply. Here’s my App.tsx. I’ve removed my clientId so it’s not shared publicly.

import React, { useState, useEffect } from "react";
import {
  Button,
  Dimensions,
  ScrollView,
  StyleSheet,
  Text,
  View,
  TextInput,
} from "react-native";
import Constants, { AppOwnership } from "expo-constants";
import * as Linking from "expo-linking";
import "react-native-get-random-values";
import "@ethersproject/shims";
import "../../../globals";
// IMP START - Quick Start
import * as WebBrowser from "expo-web-browser";
import * as SecureStore from "expo-secure-store";
import Web3Auth, {
  WEB3AUTH_NETWORK,
  LOGIN_PROVIDER,
  ChainNamespace,
} from "@web3auth/react-native-sdk";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";
// IMP END - Quick Start
import { ethers } from "ethers";
import { ACCESS_TOKEN_KEY } from "@/constants/constants";
import AsyncStorage from "@react-native-async-storage/async-storage";

// IMP START - Whitelist bundle ID
const redirectUrl =
//@ts-ignore
Constants.appOwnership == AppOwnership.Expo ||
Constants.appOwnership == AppOwnership.Guest
? Linking.createURL(“web3auth”, {})
: Linking.createURL(“web3auth”, { scheme: “web3authexpoexample” });
// IMP END - Whitelist bundle ID

// IMP START - Dashboard Registration
const clientId = “”; // get from https://dashboard.web3auth.io
// IMP END - Dashboard Registration

// IMP START - SDK Initialization
const chainConfig = {
chainNamespace: ChainNamespace.EIP155,
chainId: “0xaa36a7”,
rpcTarget: “https://1rpc.io/sepolia”,
// Avoid using public rpcTarget in production.
// Use services like Infura, Quicknode etc
displayName: “Ethereum Sepolia Testnet”,
blockExplorerUrl: “https://sepolia.etherscan.io”,
ticker: “ETH”,
tickerName: “Ethereum”,
decimals: 18,
logo: “https://cryptologos.cc/logos/ethereum-eth-logo.png”,
};

const ethereumPrivateKeyProvider = new EthereumPrivateKeyProvider({
config: {
chainConfig,
},
});

const web3auth = new Web3Auth(WebBrowser, SecureStore, {
clientId,
// IMP START - Whitelist bundle ID
redirectUrl,
// IMP END - Whitelist bundle ID
network: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET, // or other networks
privateKeyProvider: ethereumPrivateKeyProvider,
loginConfig: {
jwt: {
verifier: “talon-local”, // from Dashboard
typeOfLogin: “jwt”,
clientId: clientId,
},
},
});
// IMP END - SDK Initialization

export default function App() {
const [loggedIn, setLoggedIn] = useState(false);
const [provider, setProvider] = useState<any>(null);
const [console, setConsole] = useState<string>(“”);
const [email, setEmail] = useState<string>(“”);

useEffect(() => {
const init = async () => {
// IMP START - SDK Initialization
await web3auth.init();

  if (web3auth.connected) {
    // IMP END - SDK Initialization
    setProvider(ethereumPrivateKeyProvider);
    setLoggedIn(true);
  }
};
init();

}, );

const login = async () => {
const accessToken = await AsyncStorage.getItem(ACCESS_TOKEN_KEY);
try {
if (!web3auth.ready) {
setConsole(“Web3auth not initialized”);
return;
}
if (!email) {
setConsole(“Enter email first”);
return;
}

  setConsole("Logging in");
  // IMP START - Login - ERROR HERE
  await web3auth.login({
    loginProvider: LOGIN_PROVIDER.JWT,
    extraLoginOptions: {
      id_token: accessToken,
      verifier: "uuid",
    },
  });

  if (web3auth.connected) {
    // IMP END - Login
    setProvider(ethereumPrivateKeyProvider);
    uiConsole("Logged In");
    setLoggedIn(true);
  }
} catch (e: any) {
  setConsole(e.message);
}

};
…
// Other unrelevant code

Issue 2 - Custom JWT login

Sure, but I can’t tell if it’s working or not - login is still stuck at globa.base64FromArrayBuffer is not a function (it is undefined)

Issue 1

For what it’s worth, I’ve also tried an alternative approach where the necessary imports were initialized earlier but that did not work as well. Specifically:

// in package.json
{
...
  "main": "./AppEntry.tsx", // <-- [New] App Entry
...
}

// in AppEntry.tsx
import “react-native-get-random-values”;
import “@ethersproject/shims”;
import “./globals”;

import “expo-router/entry”;

I see that the Shims are injected from the console in BOTH approaches (importing in Entry AND importing in the Screen directly. Which validates that the polyfill code at least ran in both approaches.

Shims Injected:
- nextTick

But I’m still getting the same error so I dug further:

My investigations in the Web3Auth source code

The global.base64FromArrayBuffer is thrown from the file web3Auth.js. It is thrown exactly in:

async authHandler(...) {
  const loginUrl = utils.constructURL({
      baseURL: url,
      hash: {
        b64Params: auth.jsonToBase64(configParams) // <-- this func
      }
    });
};

Stepping deeper into web3auth > auth > dist > lib.cjs > utils > utils.js

var base64urlLib = require('base64url');

function jsonToBase64(json) {
return base64url.encode(JSON.stringify(json));
}

Stepping deeper into base64url > dist > base64url.js

function encode(input, encoding) {
    if (encoding === void 0) { encoding = "utf8"; }
    if (Buffer.isBuffer(input)) {
        return fromBase64(input.toString("base64"));
    }
    return fromBase64(Buffer.from(input, encoding).toString("base64")); <-- Error thrown here (Buffer.from())
}

Findings

  1. The issue is likely that Buffer is not polyfilled correctly in my setup
  2. [Issue #2] We do not need to construct and open a loginUrl to begin with since we are using a custom JWT auth - our Users are already authenticated with a Token with our own custom Auth. I also can’t seem to find a different pathway in web3Auth’s login() source code when loginConfig.jwt is defined.

Friendly bump @maharshi :slight_smile: , what do you think?

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.

Yes
i believe the same
The Issue#1 is due to some issue with polyfilling
For Issue #2

Steps to resolve:

  1. Verify JWT Setup in Web3Auth:
    Ensure your JWT is correctly configured with the Web3Auth Dashboard and is publicly verifiable. Confirm that the verifier and JWT fields (like sub or email) match the expected configuration.

  2. Modify Login Code:
    You seem to be on the right track with JWT login configuration. Here’s a refined example to ensure proper JWT authentication:

    const web3auth = new Web3Auth(WebBrowser, SecureStore, {
      clientId,
      redirectUrl,
      network: WEB3AUTH_NETWORK.SAPPHIRE_DEVNET,
      loginConfig: {
        jwt: {
          verifier: "your_verifier_name", // Ensure this matches what's in the Web3Auth Dashboard
          typeOfLogin: "jwt",
          clientId,
        },
      },
    });
    

    await web3auth.login({
    loginProvider: LOGIN_PROVIDER.JWT,
    extraLoginOptions: {
    id_token: accessToken, // Your JWT from custom backend
    verifierIdField: “sub”, // Or the field you use as the user identifier
    },
    });

  3. Check for Errors and Debugging:
    If you encounter errors, check if the JWT is properly formatted and ensure your backend is correctly issuing the token. You can use tools like JWT.io to decode and verify the token.

Hey @marhashi, can we mark this topic as unsolved?

Issue #1 - Closed

I managed to getaround the Polyfill issue by adding the polyfill code at the top of the file with the web3Auth funcs (App.tsx)

global.Buffer = require("buffer").Buffer;

Issue 2

The code suggested does not address the main problem of Custom JWT - Our Users are already authenticated with a token.

  • The Token is already verified. I’ve confirmed this with JWT.io.
  • The custom Auth is already created on our Web3 Auth Dashboard.

There’s no obvious function to use with react-native PNP to connect to wallets. There’s a useWeb3AuthConnect or connectTo/connect functions in the Web Web3Auth SDKs. IS there something similar we can use for Expo/React-native? @maharshi

Until the V10 web equivalent for React native SDK is not released, the syntax stays a little different.
For now here’s a reference for you
This example uses the Firebase login: web3auth-react-native-examples/rn-bare-firebase-example/App.tsx at main · Web3Auth/web3auth-react-native-examples · GitHub

Please join the office hours happening today for dedicated support: Web3Auth Developer Office Hours