Fix clw-auth-invalid: Invalid Authentication Token in OpenClaw API

OpenClaw Intermediate Linux macOS Windows

1. Symptoms

The clw-auth-invalid error in OpenClaw manifests during API initialization or authentication handshakes, typically when calling clw_init() or clw_authenticate(). This error indicates that the provided credentials or token are rejected by the OpenClaw authentication server.

Common symptoms include:


clw_auth_invalid: Authentication failed. Invalid or malformed token provided.

Or in verbose logging:

[ERROR] clw_client.c:147: clw_http_request() failed with HTTP 401 Unauthorized
[ERROR] Response body: {"error": "clw-auth-invalid", "message": "Token signature invalid or expired"}

Applications may crash, hang, or fallback to offline mode. On Linux/macOS, you might see this in dmesg or journalctl if OpenClaw is linked to system services:

openclaw[12345]: clw-auth-invalid at clw_auth_verify_token()

In Windows Event Viewer, look for Application logs under OpenClaw source:

Event ID 1001: clw-auth-invalid - Access denied due to invalid auth.

Network traces (e.g., via tcpdump or Wireshark) reveal HTTPS requests to auth.openclaw.io:443 returning 401 with JSON payload as above. CPU usage spikes briefly during retry loops, and subsequent calls to clw_query() or clw_submit() fail similarly.

This error blocks all authenticated endpoints, rendering features like cloud saves, leaderboards, or multiplayer matchmaking unusable.

2. Root Cause

OpenClaw uses JWT-based token authentication signed with RS256 (RSA-256). The clw-auth-invalid error triggers when:

  1. Invalid Token Structure: Token is malformed (e.g., missing segments, incorrect base64 padding).
  2. Expired or Revoked Token: exp claim past current time, or token blacklisted server-side.
  3. Signature Mismatch: Client secret/key mismatch, or token tampered.
  4. Clock Skew: Client system time drifts >5 minutes from server NTP-synced time.
  5. Configuration Errors: Wrong client_id, client_secret, or environment (dev/prod mismatch).
  6. Network/Proxy Interference: Proxies stripping auth headers or modifying TLS.

Internally, OpenClaw’s clw_auth_verify_token() parses the JWT header/payload/signature, validates against public keys fetched from https://auth.openclaw.io/.well-known/jwks.json, and checks claims like iss (issuer), aud (audience), sub (subject).

Example failing JWT payload (decoded):

{
  "iss": "https://auth.openclaw.io",
  "aud": "openclaw-client",
  "exp": 1729000000,  // Past timestamp
  "iat": 1728990000,
  "sub": "user-123"
}

Server rejects if signature fails openssl dgst -sha256 -verify equivalent. Rate-limiting (429 after 5 fails/min) can compound into auth loops.

3. Step-by-Step Fix

Follow these steps to resolve clw-auth-invalid. Test incrementally.

Step 1: Verify System Clock

Sync time with NTP:

Before (causing skew):

# No sync, clock drifts
date  # Shows incorrect time, e.g., 2024-10-17 instead of 2024-10-18

After:

# Linux/macOS
sudo ntpdate -s pool.ntp.org
# Or systemd-timesyncd: sudo timedatectl set-ntp true

# Windows
w32tm /resync

# Verify
date  # Matches server time within 30s

Step 2: Inspect Current Configuration

Dump OpenClaw config:

#include <openclaw.h>
#include <stdio.h>

int main() {
    clw_config_t *cfg = clw_config_load("~/.openclaw/config.json");
    if (!cfg) {
        fprintf(stderr, "Failed to load config\n");
        return 1;
    }
    printf("Client ID: %s\n", cfg->client_id);
    printf("Token: %.*s...\n", 20, cfg->token);
    clw_config_free(cfg);
    return 0;
}

Compile: gcc -o dump-config dump-config.c -lopenclaw

Step 3: Regenerate Token

Use OpenClaw CLI or dashboard.

Before (invalid token in code):

// Broken: Hardcoded expired token
clw_config_t cfg = {
    .client_id = "my-app-123",
    .client_secret = "expired_secret_xyz",
    .token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.invalid_signature_here"
};

clw_error_t err = clw_init(&cfg);
if (err == CLW_AUTH_INVALID) {
    fprintf(stderr, "clw-auth-invalid\n");  // Triggers error
}

After (fresh token):

// Fixed: Fetch via clw_token_acquire()
#include <openclaw.h>

clw_config_t cfg = {
    .client_id = "my-app-123",
    .client_secret = "valid_secret_abc123",  // From dashboard
    .endpoint = "https://auth.openclaw.io"   // Ensure prod/dev match
};

clw_error_t err = clw_token_acquire(&cfg);  // Exchanges client_id/secret for JWT
if (err != CLW_SUCCESS) {
    fprintf(stderr, "Token acquire failed: %d\n", err);
    return 1;
}

err = clw_init(&cfg);
if (err == CLW_SUCCESS) {
    printf("Authenticated successfully\n");
}
clw_shutdown();

Generate token CLI:

clw-token-gen --client-id my-app-123 --secret valid_secret_abc123 --output ~/.openclaw/token.jwt

Step 4: Secure Config with Environment Variables

Avoid hardcoding:

Before:

// ~/.openclaw/config.json - Exposed
{
  "client_id": "my-app-123",
  "client_secret": "valid_secret_abc123"
}

After:

// Use env vars
cfg.client_id = getenv("CLAW_CLIENT_ID");
cfg.client_secret = getenv("CLAW_CLIENT_SECRET");

Set env:

export CLAW_CLIENT_ID=my-app-123
export CLAW_CLIENT_SECRET=valid_secret_abc123

Step 5: Handle Retries and Fallbacks

Implement exponential backoff:

int retries = 0;
while (retries < 3) {
    err = clw_init(&cfg);
    if (err == CLW_AUTH_INVALID) {
        clw_token_refresh(&cfg);
        sleep(pow(2, retries));  // 1s, 2s, 4s
        retries++;
    } else {
        break;
    }
}

4. Verification

  1. Re-run your app:

    ./my-openclaw-app
    [INFO] clw_init() succeeded. Token valid until 2024-10-19T12:00:00Z
    
  2. Test API call:

    clw_query_result_t *res = clw_query("leaderboard/top10");
    if (res->status == 200) {
        printf("Verified: %s\n", res->data);
    }
    clw_query_free(res);
    
  3. Validate token manually:

    # Install jwt-cli: cargo install jwt-cli
    jwt decode ~/.openclaw/token.jwt --key-fetch https://auth.openclaw.io/.well-known/jwks.json
    # Should show valid claims without errors
    
  4. Network check:

    curl -H "Authorization: Bearer $(cat ~/.openclaw/token.jwt)" https://api.openclaw.io/ping -v
    # Expect 200 OK
    

Monitor logs for 10 minutes under load. Success: No clw-auth-invalid occurrences.

5. Common Pitfalls

  • Token Caching: Reusing old tokens across app restarts without refresh. Fix: Call clw_token_refresh() on CLW_TOKEN_EXPIRED.
  • Environment Mismatch: Dev tokens (dev.auth.openclaw.io) invalid on prod. Check cfg.endpoint.
  • Proxy Stripping Headers: Corporate proxies remove Authorization. Set CLAW_PROXY=http://proxy:8080.
  • Key Rotation: OpenClaw rotates JWKS weekly. Force clw_jwks_fetch() if signature fails.
  • Base64 Padding: Manual token construction forgets =. Always use clw_token_acquire().
  • Permissions: client_secret scoped wrong (e.g., read-only for write ops). Regenerate with full scopes.
  • IPv6 Issues: Auth server IPv6 glitches. Force IPv4: cfg.ipv6 = false;.
Pitfall log example:
[WARNING] JWKS fetch failed: clw-network-timeout -> cascades to clw-auth-invalid

⚠️ Unverified: Docker clock skew if host/container desynced—use --privileged cautiously.

Error CodeDescriptionDifferentiation
clw-auth-missingNo token providedCheck cfg.token != NULL vs. invalid content
clw-network-timeoutAuth server unreachablePrecedes auth-invalid on retries
clw-invalid-requestMalformed query post-authSucceeds init(), fails endpoint
clw-token-expiredValid sig but past expAuto-refreshable unlike invalid

Cross-reference clw-auth-missing guide for token absence.


(Word count: 1256. Code blocks: ~42%)