Skip to main content
RoZod automatically handles all Roblox security requirements, including CSRF tokens, hardware-backed authentication, and challenge responses. You don’t need to implement any of this manually.

Automatic security features

XCSRF tokens

Automatic CSRF token retrieval, caching, and retry logic

Hardware-backed auth

Full HBA signature support for enhanced security

Challenge handling

Built-in support for captcha and 2FA challenges

Cookie security

Secure cookie parsing, validation, and rotation

XCSRF token management

Roblox requires CSRF tokens for all write operations (POST, PUT, PATCH, DELETE). RoZod handles this automatically.

How it works

  1. Initial request: RoZod makes the request without a token
  2. Token response: Roblox returns a 403 with x-csrf-token header
  3. Automatic retry: RoZod caches the token and retries the request
  4. Subsequent requests: Cached token is included automatically
import { fetchApi } from 'rozod';
import { postGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv1';

// XCSRF token is handled automatically
const result = await fetchApi(postGroupsGroupidWallPosts, {
  groupId: 123456,
  body: { message: 'Hello, world!' }
});
RoZod automatically retries up to 3 times if CSRF token validation fails. This handles token expiration seamlessly.

Token caching

Tokens are cached per cookie:
// Internal RoZod logic (for reference)
const csrfTokenMap: Record<string, string> = {};

// Tokens are keyed by SHA-256 hash of the cookie
const csrfKey = await getSHA256Hash(cookieValue);
csrfTokenMap[csrfKey] = csrfToken;
This allows using different tokens for different accounts in cookie pools.
You don’t need to manage tokens yourself. RoZod handles all caching and rotation automatically.

Hardware-backed authentication (HBA)

Roblox uses hardware-backed authentication signatures for enhanced security. RoZod automatically generates these signatures.

Automatic HBA handling

RoZod uses the roblox-bat library to generate HBA signatures:
import { fetchApi } from 'rozod';
import { getUsersUserdetails } from 'rozod/lib/endpoints/usersv1';

// HBA signatures are generated automatically
const userInfo = await fetchApi(getUsersUserdetails, { userIds: [123456] });
The following headers are automatically included:
  • x-hba-client-token: Browser agent token
  • x-hba-signature: ECDSA signature of request
  • x-hba-timestamp: Request timestamp
HBA signatures are generated using ECDSA P-256 cryptography and include request method, URL, and body in the signature.

Browser vs server HBA

RoZod automatically detects the environment:
  • Browser: Uses Web Crypto API with on-site detection
  • Node.js/Bun/Deno: Uses crypto module with automatic key generation

Custom HBA keys (advanced)

For Node.js environments requiring custom crypto keys:
import { changeHBAKeys } from 'rozod';

// Generate custom ECDSA P-256 key pair
const keyPair = await crypto.subtle.generateKey(
  { name: 'ECDSA', namedCurve: 'P-256' },
  true,
  ['sign', 'verify']
);

changeHBAKeys(keyPair);
Custom HBA keys are rarely needed. Only use this if you have specific cryptographic requirements.

Challenge handling

Roblox may present authentication challenges like captchas or 2FA. RoZod detects these and invokes your handler.

Configure challenge handler

Set up a global challenge handler:
import { setHandleGenericChallenge } from 'rozod';

setHandleGenericChallenge(async (challenge) => {
  console.log('Challenge type:', challenge.challengeType);
  console.log('Challenge ID:', challenge.challengeId);
  
  if (challenge.challengeType === 'captcha') {
    // Solve captcha (e.g., using a service or user interaction)
    const solution = await solveCaptcha(challenge.challengeId);
    
    return {
      challengeType: challenge.challengeType,
      challengeId: challenge.challengeId,
      challengeBase64Metadata: solution
    };
  }
  
  // Return undefined to skip challenge
  return undefined;
});
See Challenge handling for detailed implementation guides and examples.

Challenge flow

  1. Initial request: RoZod makes the request
  2. Challenge response: Roblox returns challenge headers
  3. Handler invocation: Your challenge handler is called
  4. Automatic retry: RoZod retries with challenge solution
// RoZod automatically includes challenge headers:
headers.set('rblx-challenge-type', challengeData.challengeType);
headers.set('rblx-challenge-id', challengeData.challengeId);
headers.set('rblx-challenge-metadata', challengeData.challengeBase64Metadata);
RoZod retries up to 3 times for challenges. Returning undefined from the handler skips the challenge and stops retries.
RoZod implements secure cookie handling: Safely extracts .ROBLOSECURITY cookies:
// Internal RoZod logic (for reference)
function extractRoblosecurityFromSetCookie(setCookieHeader: string): string | undefined {
  // Handles both with and without _| prefix
  const match = setCookieHeader.match(/\.ROBLOSECURITY=(_\|[^|]+\|_)?([^;]+)/);
  return match ? (match[1] ? match[1] + match[2] : match[2]) : undefined;
}
RoZod validates cookies before use:
  • Checks for proper .ROBLOSECURITY format
  • Handles warning prefixes (_|WARNING:-DO-NOT-SHARE-THIS...)
  • Detects expired or invalid cookies
RoZod automatically detects when Roblox rotates cookies:
import { configureServer } from 'rozod';

configureServer({
  cookies: process.env.ROBLOX_COOKIE,
  onCookieRefresh: async ({ oldCookie, newCookie, poolIndex }) => {
    // Persist new cookie value
    await db.updateCookie(poolIndex, newCookie);
    console.log('Cookie rotated!');
  }
});
See Cookie rotation for detailed information on handling cookie rotation.

Request signing

For authenticated requests, RoZod automatically:
  1. Adds authentication headers: Cookie or API key based on endpoint
  2. Includes user agent: Realistic browser user agents in server environments
  3. Generates HBA signatures: Hardware-backed authentication signatures
  4. Adds CSRF tokens: For write operations
  5. Sets credentials mode: credentials: 'include' for cross-origin requests
// Internal RoZod logic (for reference)
const response = await fetch(url, {
  method: 'POST',
  credentials: 'include',
  headers: {
    'cookie': `.ROBLOSECURITY=${cookie}`,
    'user-agent': selectedUserAgent,
    'x-csrf-token': cachedToken,
    'x-hba-client-token': hbaClientToken,
    'x-hba-signature': hbaSignature,
    'x-hba-timestamp': timestamp,
  },
  body: JSON.stringify(data)
});

Error handling

Handle security-related errors:
import { fetchApi, isAnyErrorResponse } from 'rozod';
import { postGroupsGroupidWallPosts } from 'rozod/lib/endpoints/groupsv1';

const result = await fetchApi(postGroupsGroupidWallPosts, {
  groupId: 123456,
  body: { message: 'Hello!' }
});

if (isAnyErrorResponse(result)) {
  if (result.message.includes('Token Validation Failed')) {
    // CSRF token issue (RoZod retried 3 times)
    console.error('CSRF validation failed after retries');
  } else if (result.message.includes('challenge')) {
    // Challenge not handled
    console.error('Authentication challenge required');
  }
}

Security best practices

.ROBLOSECURITY cookies provide full access to Roblox accounts. Never commit them to version control, share them, or expose them in logs.
Store all sensitive credentials (cookies, API keys) in environment variables or secret management systems.
Log security-related errors to detect issues like expired cookies, invalid tokens, or failed challenges.
Create separate Roblox accounts for bots/services instead of using personal accounts. This provides better isolation.
Respect Roblox’s rate limits to avoid account restrictions or bans. Use cookie pools for high-volume applications.

Debugging security issues

Enable verbose logging

Log all security-related operations:
import { fetchApi } from 'rozod';

const result = await fetchApi(endpoint, params, {
  // Use returnRaw to inspect headers
  returnRaw: true
});

console.log('Response headers:', result.headers);
console.log('CSRF token:', result.headers.get('x-csrf-token'));

Check HBA signatures

Verify HBA headers are included:
// Make a request and inspect raw response
const response = await fetchApi(endpoint, params, { returnRaw: true });

// Check request headers (in browser DevTools or by logging)
console.log('HBA client token:', response.headers.get('x-hba-client-token'));
console.log('HBA signature:', response.headers.get('x-hba-signature'));

Test challenge handling

Verify your challenge handler is working:
import { setHandleGenericChallenge } from 'rozod';

setHandleGenericChallenge(async (challenge) => {
  console.log('Challenge received:', challenge);
  // Test without solving to see the error
  return undefined;
});

Next steps

Challenge handling

Implement captcha and 2FA handlers

Cookie rotation

Handle automatic cookie rotation

Error handling

Handle security-related errors

Server authentication

Configure server-side authentication

Build docs developers (and LLMs) love