Delegated actions

Okto lets you securely request "on-behalf-of" permissions from users for their embedded wallets. This is known as delegated actions. It allows your application or backend to perform certain wallet operations without requiring a user signature prompt each time, so long as it adheres to user-approved policies.

What are delegated actions?

Delegated actions empower your application to take pre-defined actions using a user's embedded wallet, with the user's explicit consent. This means your application can, for example, initiate transactions or sign messages on behalf of the user, within clearly defined boundaries and under secure conditions.

Understanding Delegated Intent Flow

The diagram below shows how delegated actions work within the Okto ecosystem:

Okto Delegated Flow

Notice that in this flow, the user isn't directly involved in the transaction approval. Once the session is established and valid, the client app can make requests directly to the Okto Gateway without additional user input.

How to implement delegated actions

To implement delegated actions in your application:

  1. Capture the Session Key: During user authentication, capture the session private key that's provided in the login callback. This key is essential for performing delegated actions.

    Learn more about session keys and their management in our Session Management Guide

  2. Implementation Example: Here's how to capture the session key during Google OAuth login:

    // Using Google OAuth
    async function handleGoogleLogin(credentialResponse: any) {
        try {
            const user = await oktoClient.loginUsingOAuth({
                idToken: credentialResponse.credential,
                provider: "google",
            }, (sessionPrivateKey: string) => {
                console.log("Session Private Key:", sessionPrivateKey);
                // Store this key securely for delegated actions
                localStorage.setItem("sessionPrivKey", sessionPrivateKey);
            });
     
            console.log("Login successful:", user);
        } catch (error) {
            console.error("Login failed:", error);
        }
    }
  3. Creating the Okto Auth Token for delegated actions: Once you have the session key, you can generate an authorization token to make delegated actions:

import { secp256k1 } from "@noble/curves/secp256k1";
import { keccak_256 } from "@noble/hashes/sha3";
import { signMessage } from "viem/accounts";
 
// Define SessionKey class for handling key operations
class SessionKey {
  priv;
  constructor(privKey) {
    if (privKey) {
      this.priv = Uint8Array.from(
        Buffer.from(privKey.replace("0x", ""), "hex")
      );
    } else {
      this.priv = secp256k1.utils.randomPrivateKey();
    }
  }
  
  get privateKeyHexWith0x() {
    return `0x${Buffer.from(this.priv).toString("hex")}`;
  }
  
  get uncompressedPublicKeyHexWith0x() {
    return `0x${Buffer.from(secp256k1.getPublicKey(this.priv, false)).toString("hex")}`;
  }
  
  static fromPrivateKey(privateKey) {
    return new SessionKey(privateKey);
  }
}
 
// Generate an Okto Auth Token using session keys
async function getAuthorizationToken(sessionConfig) {
  const sessionPriv = sessionConfig?.sessionPrivKey;
  const sessionPub = sessionConfig?.sessionPubKey;
  
  if (!sessionPriv || !sessionPub) {
    throw new Error("Session keys are not set");
  }
  
  const data = {
    expire_at: Math.round(Date.now() / 1000) + 60 * 90, // 90 minutes expiry
    session_pub_key: sessionPub,
  };
 
  // Okto auth token is the session public key encrypted with the session private key
  const payload = {
    type: "ecdsa_uncompressed",
    data,
    data_signature: await signMessage({
      message: JSON.stringify(data),
      privateKey: sessionPriv,
    }),
  };
  
  return btoa(JSON.stringify(payload));
}
 
// Example usage with stored session key
async function performDelegatedAction() {
  // Retrieve the stored session private key
  const sessionPrivKey = localStorage.getItem("sessionPrivKey");
  const userSWA = oktoClient.userSWA; // Get from Okto client
  
  if (!sessionPrivKey || !userSWA) {
    console.error("Missing session keys or user SWA");
    return;
  }
  
  // Create session object
  const session = SessionKey.fromPrivateKey(sessionPrivKey);
  
  // Construct session config
  const sessionConfig = {
    sessionPrivKey: session.privateKeyHexWith0x,
    sessionPubKey: session.uncompressedPublicKeyHexWith0x,
    userSWA,
  };
  
  // Generate auth token
  const authToken = await getAuthorizationToken(sessionConfig);
  console.log("Okto session authToken:", authToken);
  
  // Now use this token for API calls
  // Example: fetch user portfolio
  const response = await fetch("https://sandbox-api.okto.tech/api/oc/v1/aggregated-portfolio", {
    headers: {
      "Authorization": `Bearer ${authToken}`
    }
  });
  
  const portfolioData = await response.json();
  return portfolioData;
}

How It Works

  1. User Consent: The user delegates their embedded wallet to your application when they login and this consent can be revoked at any time by logging out.
  2. Limited Scope: Delegation is governed by a policy engine that enforces limits (e.g., transaction count, spend limits) to protect the user.
  3. Session-Based Security: The delegated actions are bound to the session keys, which have a limited lifetime (10 days by default).

Policy Enforcement

Okto's policy engine may enforce transaction thresholds—such as daily or total spend—beyond which users need to re-confirm.

For more details please read our section on Policy engine

Security Considerations

When implementing delegated actions, keep these security best practices in mind:

  • Secure Storage: Store session keys securely. Never expose them in client-side code that could be accessed by malicious actors.
  • Transparent Communication: Clearly inform users when your application will use delegated actions and what those actions entail.
  • Regular Verification: Periodically check session validity before attempting delegated operations.

Example Usecases

Automated Trading

Schedule recurring token swaps or DeFi interactions without user prompts for each transaction

Subscription Payments

Handle recurring membership fees or subscription payments automatically using delegated permissions

Yield Management

Automate yield harvesting and reinvestment strategies based on predefined user conditions

On this page