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. Please note that this template is for development and testing purposes only. Be sure to customize and secure it before using in production.
Prerequisites
Before you begin, set up your developer dashboard by making sure you have :
- Created your Okto Developer Dashboard account
- Get your Okto credits from the dashboard
- Obtained your API keys from the dashboard
- Enabled the specific Chains and Tokens you plan to use in your application
- Optional: Enabled Sponsorship for the desired chains
If you need help, reach out to us on our troubleshooting form and we will contact you.
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
andNEXT_PUBLIC_CLIENT_SWA
. Obtain these from the Okto Developer Dashboard. - Okto Account Setup: Ensure you have sufficient Okto Credits, enable the required Chains and Tokens , and optionally Activate Sponsorship.
- Google OAuth Credentials (if using Google authentication): Create OAuth 2.0 credentials in the Google Cloud Console to get your
GOOGLE_CLIENT_ID
andGOOGLE_CLIENT_SECRET
. - Auth Secret: NextAuth requires a secret for signing tokens. Generate one by running:
openssl rand -base64 32
- Go to Google Cloud Console.
- Create OAuth 2.0 credentials for your project.
- Set the redirect URI to:
[YOUR_APP_URL]/api/auth/callback/google
(for example,http://localhost:3000/api/auth/callback/google
during local development). - Save your Client ID and Client Secret.
Need detailed instructions? Check our Google Console Setup Guide.
Sponsorship Setup (Optional)
To enable sponsorship for transactions via Okto, follow the steps below:
-
Enable Supported Chains: Ensure the chains you wish to sponsor transactions on are enabled in your Okto Dashboard under Chains & Tokens.
-
Create and Configure a Treasury Wallet: Create at least one Treasury Wallet in your Okto Dashboard.
- For each supported chain:
- The Treasury Wallet used as the
feePayerAddress
must have its corresponding destination chain address funded with a small amount of native tokens for one-time verification. - Refer to the Treasury Wallet Docs for setup and verification details.
- The Treasury Wallet used as the
-
Activate Sponsorship: Navigate to the Sponsorship section in the Okto Dashboard and enable sponsorship for each chain individually.
-
Fund the Sponsor Wallet: Deposit a sufficient amount of native tokens into your Sponsor Wallet for each chain where sponsorship is active. These tokens will be used to cover user transaction fees.
- Only native tokens of the respective chains can be loaded into sponsorship accounts.
- Each chain has a unique sponsorship address. You can find this address in your Okto dashboard.
- For testnets, you can use faucets to acquire tokens.
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:
npx create-next-app@latest my-okto-app
cd my-okto-app
When prompted during setup, select:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes
- Use
src/
directory: No - App Router: Yes
- Customize default import alias: No
- 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
pnpm add @okto_web3/react-sdk@latest next-auth
yarn add @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:
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
- 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:
"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;
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
:
Create these folders in your app directory: 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 };
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:
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>
);
}
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
:
"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>
);
}
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
:
"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;
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:
"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>
);
}
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
pnpm dev
yarn 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.
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 theYOUR_...
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:
"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:
// 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
Command | Description | Documentation |
---|---|---|
const account = await getAccount(oktoClient); | Get user's wallet details | Method Overview |
const chains = await getChains(oktoClient); | List supported blockchain networks | Method Overview |
const tokens = await getTokens(oktoClient); | List supported tokens | Method Overview |
const portfolio = await getPortfolio(oktoClient); | Get user's token holdings | Method Overview |
const nfts = await getPortfolioNFT(oktoClient); | Get user's NFT holdings | Method Overview |
const activity = await getPortfolioActivity(oktoClient); | Get transaction history | Method Overview |
const orders = await getOrdersHistory(oktoClient); | Get transaction order history | Method Overview |
const collections = await getNftCollections(oktoClient); | Get NFT collections | Method Overview |
Message Signing
Enables the creation of signatures for messages or object data. The signing process is initiated through the OktoClient instance.
Command | Description | Documentation |
---|---|---|
const signature = await oktoClient.signMessage(message); | Signs messages following the EIP191 standard | Method Overview |
const signature = await oktoClient.signTypedData(data); | Signs typed data following the EIP712 standard | Method 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. Please note that this template is for development and testing purposes only. Be sure to customize and secure it before using in production.
Additional Resources
Need help? Join our Discord community or email us at [email protected]
.