Skip to main content
Nuabase is designed to let your frontend application call LLMs directly, without routing every request through your own backend API. This reduces latency and server load while keeping your API keys secure.

Architecture

Instead of exposing your API_KEY to the browser (which is insecure), you use a Short-lived Access Token.
  1. Login: User logs into your app as usual.
  2. Token Request: Your frontend requests a Nuabase Token from your backend.
  3. Sign: Your backend uses your Signing Key Secret to generate a JWT for that specific user.
  4. Call: Your frontend uses this token to initialize the Nuabase SDK and make requests.

Step 1: Backend - Generate Tokens

You need to expose an endpoint (e.g., POST /api/nuabase-token) that returns a token for the currently authenticated user.
# Gemfile
# gem 'nuabase'

class NuabaseController < ApplicationController
  before_action :authenticate_user!

  def token
    # Initialize the generator with your secret and the user's ID
    generator = Nuabase::NuaTokenGenerator.new(
      signing_key_secret: ENV['NUABASE_SIGNING_KEY_SECRET'],
      user_id: current_user.id.to_s
    )

    # Generate the token (valid for 3 minutes by default)
    render json: generator.generate
  end
end
Never expose your NUABASE_SIGNING_KEY_SECRET to the client. It must only be used on your server.

Step 2: Frontend - Initialize SDK

In your frontend application, you initialize the Nua client by providing a fetchToken function. This function is called automatically whenever the SDK needs a fresh token.
import { Nua } from 'nuabase';
import { z } from 'zod';

const nua = new Nua({
  // The SDK calls this to get a valid token
  fetchToken: async () => {
    const response = await fetch('/api/nuabase-token', {
      method: 'POST',
      // Include your app's auth headers if needed
      headers: { 'Content-Type': 'application/json' }
    });
    
    if (!response.ok) throw new Error('Failed to fetch token');
    
    const data = await response.json();
    return data.access_token;
  }
});

Step 3: Make Requests

Once initialized, you can define and call functions just like in the server-side workflow.
const SuggestReply = z.object({
  text: z.string(),
  tone: z.enum(['Professional', 'Casual'])
});

const suggestReply = nua.createFn({
  prompt: "Draft a reply to this email.",
  output: { name: "reply", schema: SuggestReply }
});

// Usage in a Component
async function handleReply() {
  const result = await suggestReply(emailContent);
  if (result.isSuccess) {
    setDraft(result.data.text);
  }
}

Security & abuse prevention

Since requests come directly from the client, Nuabase uses the userId embedded in the token to enforce limits.
  • Budgets: Set a maximum monthly spend per user.
  • Rate Limits: Limit the number of requests per minute per user.
You can configure these limits in the Nuabase Console.