Skip to main content

Authentication

Chucky uses JWT (JSON Web Tokens) for authentication. Tokens are created server-side with your HMAC secret and include budget limits for each user.

Token Architecture

1

Request Token

Your client (browser) requests a token from your backend server
2

Create JWT

Your server creates a JWT signed with your HMAC secret, including user ID and budget limits
3

Return Token

Server returns the signed JWT to the client
4

Use SDK

Client uses the token to connect to Chucky Cloud via the SDK
Never expose your HMAC secret to clients. Always create tokens on your server.

Creating Tokens

Basic Token

Get your Project ID and HMAC Secret from your project settings at app.chucky.cloud.
import { createToken, createBudget } from '@chucky.cloud/sdk';

const token = await createToken({
  userId: 'user-123',
  projectId: process.env.CHUCKY_PROJECT_ID,  // From portal project settings
  secret: process.env.CHUCKY_HMAC_SECRET,    // From portal project settings
  budget: createBudget({
    aiDollars: 1.00,
    computeHours: 1,
    window: 'day',
  }),
});
The Project ID and HMAC Secret are separate values found in your project settings at app.chucky.cloud. The Project ID is used in JWT tokens, while the HMAC Secret is used for signing (never exposed in tokens).

Token Options

OptionTypeRequiredDescription
userIdstringYesUnique identifier for the user
projectIdstringYesYour project ID from portal settings
secretstringYesYour HMAC secret from portal settings
budgetTokenBudgetYesBudget configuration
expiresInnumberNoToken validity in seconds (default: 3600)
permissionsobjectNoOptional permission constraints
sdkConfigobjectNoSDK configuration overrides

Budget Configuration

Budgets control how much each user can spend. Two types of limits:
  • AI Budget: Cost limit for Claude API calls (in dollars)
  • Compute Budget: Time limit for sandbox execution (in hours)

Budget Helper

import { createBudget } from '@chucky.cloud/sdk';

const budget = createBudget({
  aiDollars: 5.00,        // $5 AI budget
  computeHours: 2,        // 2 hours compute
  window: 'day',          // Reset window
  windowStart: new Date() // Optional: when window started
});

Budget Windows

WindowDescription
hourResets every hour
dayResets every 24 hours
weekResets every 7 days
monthResets on billing anchor day

Raw Budget Format

If you need more control, you can specify the raw budget format:
const token = await createToken({
  userId: 'user-123',
  projectId: process.env.CHUCKY_PROJECT_ID,
  secret: process.env.CHUCKY_HMAC_SECRET,
  budget: {
    ai: 5_000_000,          // 5 USD in microdollars
    compute: 7200,          // 2 hours in seconds
    window: 'day',
    windowStart: new Date().toISOString(),
  },
});
AI budget is specified in microdollars (1 USD = 1,000,000 microdollars) for precision.

Token Permissions

Restrict what users can do with their token:
const token = await createToken({
  userId: 'user-123',
  projectId: process.env.CHUCKY_PROJECT_ID,
  secret: process.env.CHUCKY_HMAC_SECRET,
  budget: createBudget({ aiDollars: 1, computeHours: 1, window: 'day' }),
  permissions: {
    tools: ['search', 'calculator'],    // Only these tools allowed
    blockedTools: ['shell', 'write'],   // These tools blocked
    maxTurns: 10,                        // Max conversation turns
    model: 'claude-sonnet-4-5-20250929', // Force specific model
  },
});

Permission Options

OptionTypeDescription
toolsstring[]Whitelist of allowed tool names
blockedToolsstring[]Blacklist of blocked tool names
maxTurnsnumberMaximum conversation turns
modelstringForce a specific model

SDK Config Overrides

Override client-side SDK options from the token (server-enforced):
const token = await createToken({
  userId: 'user-123',
  projectId: process.env.CHUCKY_PROJECT_ID,
  secret: process.env.CHUCKY_HMAC_SECRET,
  budget: createBudget({ aiDollars: 1, computeHours: 1, window: 'day' }),
  sdkConfig: {
    model: 'claude-sonnet-4-5-20250929',
    systemPrompt: 'You are a helpful assistant.',
    maxTurns: 5,
    maxBudgetUsd: 0.50,
    allowedTools: ['safe_tool'],
    disallowedTools: ['dangerous_tool'],
  },
});
SDK config overrides take precedence over any options passed by the client.

Token Utilities

Decode Token (No Verification)

import { decodeToken } from '@chucky.cloud/sdk';

const decoded = decodeToken(token);
console.log(decoded.sub);    // User ID
console.log(decoded.iss);    // Project ID
console.log(decoded.budget); // Budget config

Verify Token

import { verifyToken } from '@chucky.cloud/sdk';

const isValid = await verifyToken(token, process.env.HMAC_SECRET);
if (!isValid) {
  throw new Error('Invalid token signature');
}

Check Expiration

import { isTokenExpired } from '@chucky.cloud/sdk';

if (isTokenExpired(token)) {
  // Token has expired, create a new one
  const newToken = await createToken({ ... });
}

Token Payload Structure

The JWT payload contains:
interface TokenPayload {
  // Standard JWT claims
  sub: string;           // User ID
  iss: string;           // Project/Issuer ID
  exp: number;           // Expiry timestamp (Unix seconds)
  iat: number;           // Issued at timestamp

  // Chucky-specific
  budget: {
    ai: number;          // AI budget in microdollars
    compute: number;     // Compute budget in seconds
    window: string;      // Budget window type
    windowStart: string; // ISO 8601 timestamp
  };

  // Optional
  permissions?: { ... };
  sdkConfig?: { ... };
}

Best Practices

Use short expiration times (1 hour or less) and refresh tokens as needed. This limits exposure if a token is compromised.
Create a new token for each user session rather than reusing tokens. This provides better audit trails and security.
Start with small budgets and increase based on user needs. You can always create a new token with a larger budget.
Restrict tools and models based on user trust level. Free users might get limited tools, while premium users get full access.

Example: Token Endpoint

Here’s a complete example of a token endpoint:
// pages/api/token.ts (Next.js example)
import { createToken, createBudget } from '@chucky.cloud/sdk';

export async function POST(req: Request) {
  // Verify user is authenticated (your auth system)
  const user = await getCurrentUser(req);
  if (!user) {
    return new Response('Unauthorized', { status: 401 });
  }

  // Get user's tier for budget limits
  const tier = user.subscriptionTier || 'free';
  const budgets = {
    free: { ai: 0.10, compute: 0.1 },
    pro: { ai: 5.00, compute: 2 },
    enterprise: { ai: 50.00, compute: 10 },
  };

  const { ai, compute } = budgets[tier];

  const token = await createToken({
    userId: user.id,
    projectId: process.env.CHUCKY_PROJECT_ID,
    secret: process.env.CHUCKY_HMAC_SECRET,
    expiresIn: 3600,
    budget: createBudget({
      aiDollars: ai,
      computeHours: compute,
      window: 'day',
    }),
    permissions: tier === 'free' ? {
      maxTurns: 5,
      blockedTools: ['shell', 'write_file'],
    } : undefined,
  });

  return Response.json({ token });
}