NextJS Setup

Learn how to create a Next.js app and initialize it with the Okto SDK.

Quick Start Template Available!

Skip the manual setup and get started in minutes with our template repository. It includes pre-configured Okto SDK integration, authentication setup, and example components and operations.

Warning:Essential Setup Required
Show

Before you begin, set up your developer dashboard by making sure you have :

If you need help, reach out to us on our troubleshooting form and we will contact you.

Prerequisites

Before getting started, ensure you have the following:

  • Node.js (v18+) and npm/pnpm/yarn: Download Node.js
  • Okto API Keys: You need your NEXT_PUBLIC_CLIENT_PRIVATE_KEY and NEXT_PUBLIC_CLIENT_SWA. Obtain these from the Okto Developer Dashboard.
  • Google OAuth Credentials: Create OAuth 2.0 credentials in the Google Cloud Console to get your GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
  • Auth Secret: NextAuth requires a secret for signing tokens. Generate one by running:
openssl rand -base64 32
Tip:Setting up Google OAuth
Show
  1. Go to Google Cloud Console.
  2. Create OAuth 2.0 credentials for your project.
  3. Set the redirect URI to: [YOUR_APP_URL]/api/auth/callback/google (for example, http://localhost:3000/api/auth/callback/google during local development).
  4. Save your Client ID and Client Secret.

Need detailed instructions? Check our Google Console Setup Guide.

1. Create Your NextJS App

If you already have a NextJS app, you can skip this step and proceed directly to the next step to start integrating Okto.

Let's start by creating a brand new Next.js app! Open your terminal and run these commands:

bash
npx create-next-app@latest my-okto-app
cd my-okto-app
Tip:Configuration Options
Show

When prompted during setup, select:

  • TypeScript: Yes
  • ESLint: Yes
  • Tailwind CSS: Yes
  • Use src/ directory: No
  • App Router: Yes
  • Customize default import alias: No
Note:What this does
Show
  • Creates a new Next.js project named my-okto-app.
  • Switches you into the project directory.

2. Install Dependencies

Your Next.js app needs the Okto SDK and NextAuth to work. Let's install them! Run the command below for the package manager of your choice:

npm i @okto_web3/react-sdk@latest next-auth

3. Set up Environment Variables

Create a .env file in your project root and add the following environment variables:

.env
NEXT_PUBLIC_CLIENT_PRIVATE_KEY = YOUR_OKTO_CLIENT_PRIVATE_KEY
NEXT_PUBLIC_CLIENT_SWA = YOUR_OKTO_CLIENT_SWA
NEXT_PUBLIC_ENVIRONMENT = sandbox # or production
 
AUTH_SECRET = YOUR_AUTH_SECRET # Generate using: openssl rand -base64 32
 
# Google OAuth credentials (Required only if using Google Sign-In)
GOOGLE_CLIENT_SECRET = YOUR_GOOGLE_CLIENT_SECRET
GOOGLE_CLIENT_ID = YOUR_GOOGLE_CLIENT_ID
Warning:Important
Show
  • Replace all placeholder values (YOUR_...) with your actual keys.
  • Never commit your .env file to version control. Add it to your .gitignore.

4. Set Up the Okto Provider

Create a provider component to initialize the Okto SDK and authentication context. Create a file at app/components/providers.tsx with the following code:

app/components/providers.tsx
"use client";
import { SessionProvider } from "next-auth/react";
import { Hex, Hash, OktoProvider } from "@okto_web3/react-sdk"; 
import React from "react";
 
function AppProvider({ children, session }) {
    return (
        <SessionProvider session={session}>
        <OktoProvider
            config={{ 
                environment: "sandbox", 
                clientPrivateKey: process.env.NEXT_PUBLIC_CLIENT_PRIVATE_KEY as Hash, 
                clientSWA: process.env.NEXT_PUBLIC_CLIENT_SWA as Hex, 
            }} 
        > // [!code highlight]
            {children}
        </OktoProvider> // [!code highlight]
        </SessionProvider>
    );
}
export default AppProvider;
Info:Understanding the Provider
Show

The AppProvider wraps your app with:

  • SessionProvider for authentication.
  • OktoProvider to initialize the Okto SDK using your environment settings.

Remember that the "use client" directive is required for client-side components.

5. Configure Google Authentication

Set up NextAuth using Google as the provider. Create the file at app/api/auth/[...nextauth]/route.ts:

Tip:File Structure
Show

Create these folders in your app directory: app/ └── api/ └── auth/ └── [...nextauth]/ └── route.ts

app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"; 
import GoogleProvider from "next-auth/providers/google"; 
import type { AuthOptions } from "next-auth";
 
export const authOptions: AuthOptions = {
  secret: process.env.AUTH_SECRET, 
  providers: [ 
    GoogleProvider({ // Configure Google Provider 
      clientId: process.env.GOOGLE_CLIENT_ID!, // From .env 
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!, // From .env 
    }), 
  ],
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user, account }) {
      if (account) {
        token.id_token = account.id_token; 
      }
      return token;
    },
    async session({ session, token }) {
      //@ts-ignore
      session.id_token = token.id_token; 
      return session;
    },
  },
};
 
const handler = NextAuth(authOptions);
 
export { handler as GET, handler as POST };
Info:Authentication Overview
Show

This configuration:

  • Sets up NextAuth to use Google for authentication.
  • Utilizes JWT for session management.
  • Seeds the session with Google's id_token, which is later used by the Okto SDK.

6. Set up Root Layout

Update your root layout to include the AppProvider so that the authentication and Okto context are available throughout your app. Modify app/layout.tsx as follows:

app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import AppProvider from "./components/providers"; 
import { getServerSession } from "next-auth";
import { authOptions } from "./api/auth/[...nextauth]/route";
 
const inter = Inter({ subsets: ["latin"] });
 
export const metadata: Metadata = {
  title: "Okto React SDK with Google Auth",
  description: "Next.js app integrated with Okto SDK and Google Authentication",
};
 
export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const session = await getServerSession(authOptions);
  return (
    <html lang="en">
      <body className={inter.className}>
        <AppProvider session={session}>{children}</AppProvider> // [!code highlight]
      </body>
    </html>
  );
}
Note:Layout Details
Show

Using AppProvider ensures that every page in your application has access to both the session and Okto context.

7. Create a Sample Login Page (page.tsx)

Let's build a simple page to test out authentication and basic Okto operations. You will create two components—LoginButton and GetButton—and update your home page.

a. Create the Login Button Component

This component will trigger Google authentication. Create the file app/components/LoginButton.tsx:

components/LoginButton.tsx
"use client";
import { useSession, signIn, signOut } from "next-auth/react"; 
 
export function LoginButton() {
    const { data: session } = useSession(); // Get session data
 
    const handleLogin = () => { 
        signIn("google");   // Trigger Google sign-in 
    }; 
 
    return (
        <button
            className={`border border-transparent rounded px-4 py-2 transition-colors ${
                session
                ? "bg-blue-500 hover:bg-blue-700 text-white"
                : "bg-blue-500 hover:bg-blue-700 text-white"
            }`}
            onClick={handleLogin} 
        >
            Authenticate
        </button>
    );
}
Note:About the Login Button
Show

Using the signIn method from NextAuth, this button starts the Google authentication flow. No extra configuration is required on the client side.

b. Create the Get Button Component

This component is designed to call a function (such as logging out or fetching account details) and display the result in a modal.

Create the file app/components/GetButton.tsx:

components/GetButton.tsx
"use client";
import React, { useState } from "react";
import { useOkto } from "@okto_web3/react-sdk"; 
 
interface GetButtonProps {
    title: string;
    apiFn: any;
}
 
const GetButton: React.FC<GetButtonProps> = ({ title, apiFn }) => {
    const [modalVisible, setModalVisible] = useState(false);
    const [resultData, setResultData] = useState("");
    const oktoClient = useOkto();
 
    const handleButtonClick = () => {
        apiFn(oktoClient) 
        .then((result: any) => { 
            console.log(`${title}:`, result); 
            const resultData = JSON.stringify(result, null, 2); 
            setResultData(resultData !== "null" ? resultData : "No result"); 
            setModalVisible(true); 
        })
        .catch((error: any) => {
            console.error(`${title} error:`, error);
            setResultData(`error: ${error}`);
            setModalVisible(true);
        });
    };
 
    const handleClose = () => setModalVisible(false);
 
    return (
        <div className="text-center text-white">
            <button
                className="px-4 py-2 w-full bg-blue-500 text-white rounded"
                onClick={handleButtonClick}
            >
                {title}
            </button>
 
            {modalVisible && (
                <div className="fixed inset-0 bg-gray-800 bg-opacity-50 flex justify-center items-center">
                    <div className="bg-black rounded-lg w-11/12 max-w-2xl p-6">
                        <div className="flex justify-between items-center border-b pb-2 mb-4">
                            <h2 className="text-lg font-semibold">{title} Result</h2>
                            <button
                                className="text-gray-500 hover:text-gray-700"
                                onClick={handleClose}
                            >
                                ×
                            </button>
                        </div>
                        <div className="text-left text-white max-h-96 overflow-y-auto">
                            <pre className="whitespace-pre-wrap break-words text-white">
                                {resultData}
                            </pre>
                        </div>
                        <div className="mt-4 text-right">
                            <button
                                className="px-4 py-2 bg-gray-500 text-white rounded"
                                onClick={handleClose}
                            >
                                Close
                            </button>
                        </div>
                    </div>
                </div>
            )}
        </div>
    );
};
 
export default GetButton;
Note:About the Get Button
Show

This component accepts a SDK function as a prop. When clicked, it calls the function with the Okto client, displays the JSON response in a modal, and handles any errors.

c. Update the App Home Page

Integrate both buttons on your home page.

Replace the content of app/page.tsx with:

app/page.tsx
"use client";
import React, { useEffect, useMemo } from "react";
import { useSession, signOut } from "next-auth/react";
import { LoginButton } from "@/app/components/LoginButton"; 
import GetButton from "@/app/components/GetButton"; 
import {getAccount, useOkto } from '@okto_web3/react-sdk'; 
 
 
export default function Home() {
    const { data: session } = useSession(); 
    const oktoClient = useOkto(); 
 
    //@ts-ignore
    const idToken = useMemo(() => (session ? session.id_token : null), [session]);
 
    async function handleAuthenticate(): Promise<any> {
        if (!idToken) {
            return { result: false, error: "No google login" };
        }
        const user = await oktoClient.loginUsingOAuth({ 
            idToken: idToken, 
            provider: 'google', 
        }); 
        console.log("Authentication Success", user); 
        return JSON.stringify(user);
    }
 
    async function handleLogout() {
        try {
            signOut();
            return { result: "logout success" };
        } catch (error:any) {
            return { result: "logout failed" };
        }
    }
 
    useEffect(()=>{
        if(idToken){
            handleAuthenticate();
        }
    }, [idToken])
 
    return (
        <main className="flex min-h-screen flex-col items-center space-y-6 p-12 bg-violet-200">
            <div className="text-black font-bold text-3xl mb-8">Template App</div>
 
            <div className="grid grid-cols-2 gap-4 w-full max-w-lg mt-8">
                <LoginButton />
                <GetButton title="Okto Log out" apiFn={handleLogout} />
                <GetButton title="getAccount" apiFn={getAccount} />
            </div>
        </main>
    );
}
Tip:Testing Your Login Page
Show

After launching the app, use these buttons to:

  • Initiate Google authentication.
  • Trigger a logout.
  • Retrieve your account(list of wallets)details.

8. Run Your dApp

It's time to see your work in action. Inside the my-okto-app directory, run the appropriate command based on your package manager:

npm run dev

Open your browser and navigate to http://localhost:3000. You should see your "Template App" with buttons to:

  • Authenticate using Google.
  • Log out.
  • Retrieve your account details with the getAccount function.
Tip:Troubleshooting Tip
Show

If you encounter any errors when running npm run dev (or pnpm dev, yarn dev), check your terminal for error messages. Common issues include:

  • Environment Variable Errors: Double-check that you correctly set up your .env file and that all the YOUR_... placeholders are replaced with your actual keys and secrets.
  • Package Installation Errors: If you see errors related to missing packages, try re-running the install command (e.g., npm install) to make sure all dependencies are installed correctly.


Trying Out a User Operation

Let's implement a token transfer on Polygon Testnet Amoy to understand how user operations work in Okto.

1. Get Your Wallet Address

import { getAccount } from "@okto_web3/react-sdk";
 
const accounts = await getAccount(oktoClient);
const polygonAccount = accounts.data.find(
    account => account.network_name === "POLYGON_TESTNET_AMOY"
);
console.log("Your Polygon Amoy address:", polygonAccount.address);

2. Fund Your Wallet

Before transferring tokens, fund your wallet using the Polygon Amoy Faucet.

3. Review Network Information

Consult the Network Information Guide to ensure you have the correct CAIP-2 chain identifiers.

4. Implement Token Transfer

Create a new component called TokenTransfer.tsx to handle a token transfer:

app/components/TokenTransfer.tsx
"use client";
 
import { useOkto } from "@okto_web3/react-sdk";
import { tokenTransfer } from "@okto_web3/react-sdk"; 
import { useState } from "react";
 
export function TokenTransfer() {
    const oktoClient = useOkto();
    const [status, setStatus] = useState("");
 
    async function handleTransfer() {
        try {
            const transferParams = { 
                amount: BigInt("1000000000000000000"), // 1 POL (18 decimals) 
                recipient: "RECIPIENT_ADDRESS", 
                token: "", // Empty string for native token 
                caip2Id: "eip155:80002" // Polygon Amoy Testnet chain ID 
            }; 
            const jobId = await tokenTransfer(oktoClient, transferParams); 
 
            setStatus(`Transfer jobId! Result: ${jobId}`);
        } catch (error) {
            console.error("Transfer failed:", error);
            setStatus(`Transfer failed: ${error.message}`);
        }
    }
 
    return (
        <div className="p-4 bg-white rounded-lg shadow">
            <h2 className="text-xl font-bold mb-4">Token Transfer</h2>
            <button 
                onClick={handleTransfer}
                className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
            >
                Send 1 POL
            </button>
            <p className="mt-4 text-gray-600">{status}</p>
        </div>
    );
}

5. Add the Component to Your Home Page

Update your app/page.tsx to include the new TokenTransfer component:

app/page.tsx
// Add to your imports
import { TokenTransfer } from "@/app/components/TokenTransfer";
 
// Add inside your grid div
    <div className="col-span-2">
        <TokenTransfer />
    </div>

6. Test the Token Transfer

  • Run your dApp, open http://localhost:3000, and sign in with Google.
  • Then, navigate to the page where your Token Transfer component is displayed and click on the Send 1 POL button.
  • A modal will appear showing the transfer status (e.g., "Transfer executed! Result: …").

7. Verify The Transfer

Once complete, verify its success by:

  • Checking your updated balance using the getPortfolio method
  • Viewing the transaction details on the Polygon Amoy Explorer

Congratulations! You have successfully integrated the Okto SDK with your Next.js app and executed your first user operation.



SDK Reference

Get Commands

CommandDescriptionDocumentation
const account = await getAccount(oktoClient);Get user's wallet detailsMethod Overview
const chains = await getChains(oktoClient);List supported blockchain networksMethod Overview
const tokens = await getTokens(oktoClient);List supported tokensMethod Overview
const portfolio = await getPortfolio(oktoClient);Get user's token holdingsMethod Overview
const nfts = await getPortfolioNFT(oktoClient);Get user's NFT holdingsMethod Overview
const activity = await getPortfolioActivity(oktoClient);Get transaction historyMethod Overview
const orders = await getOrdersHistory(oktoClient);Get transaction order historyMethod Overview
const collections = await getNftCollections(oktoClient);Get NFT collectionsMethod Overview

User Operations (Intents)

Intents are pre-built action templates within the Okto SDK that simplify common Web3 tasks. They provide one-liner functions for complex blockchain interactions.

1. Token Transfer

Send tokens to another address. Learn more

const transferParams = {
  amount: BigInt("1000000000000000000"), // Amount in smallest unit
  recipient: "0xRecipientAddress...",     // Recipient wallet address
  token: "0xTokenAddress...",             // Token address ("" for native token)
  caip2Id: "eip155:1",                      // Target chain CAIP-2 ID
};
const result = await tokenTransfer(oktoClient, transferParams);

2. NFT Transfer

Transfer NFTs between addresses. Learn more

const nftParams = {
  caip2Id: "eip155:1",                           // Target chain CAIP-2 ID
  collectionAddress: "0xCollectionAddress...",    // NFT Collection address
  nftId: "NFTTokenID",                           // NFT identifier
  recipientWalletAddress: "0xRecipientAddress...",// Recipient address
  amount: 1n,
  nftType: "ERC721",                             // or "ERC1155"
};
const result = await nftTransfer(oktoClient, nftParams);

3. Raw Transaction (EVM)

Execute custom EVM contract calls. Learn more

import { encodeFunctionData } from 'viem';
 
// 1. Define Contract Interaction
const contractAddress = '0xContractAddress...';
const functionName = 'setValue';
const functionArgs = [123];
 
// 2. Encode Function Data
const functionData = encodeFunctionData({
  abi: [
    {
      "name": functionName,
      "type": "function",
      "stateMutability": "nonpayable",
      "inputs": [{ "type": "uint256", "name": "_value" }]
    }
  ] as const,
  functionName,
  args: functionArgs,
});
 
// 3. Execute Transaction
const rawTxParams = {
  caip2Id: "eip155:1",
  transaction: {
    to: contractAddress,
    data: functionData,
    // value: BigInt(0),  // Optional: for payable functions
  },
};
const result = await evmRawTransaction(oktoClient, rawTxParams);

Quick Start Template Available!

Skip the manual setup and get started in minutes with our template repository. It includes pre-configured Okto SDK integration, authentication setup, and example components and operations.

Additional Resources

Need help? Join our Discord community or email us at [email protected].