# X/Twitter Authentication Setup: Configuring AUTH_TOKEN and CT0 in last30days-skill

> Learn to configure AUTH_TOKEN and CT0 for X/Twitter authentication in the last30days-skill repository. Securely set up your Bird client for efficient X searches.

- Repository: [Matt Van Horn/last30days-skill](https://github.com/mvanhorn/last30days-skill)
- Tags: how-to-guide
- Published: 2026-03-25

---

**Place your `auth_token` and `ct0` cookies from x.com into `~/.config/last30days/.env` (or a project-local `.claude/last30days.env`), restrict file permissions to `600`, and the skill will automatically route X searches through the bundled Bird client instead of the xAI API.**

The **last30days-skill** repository supports headless X (Twitter) searches without browser automation by authenticating through session cookies. When configured correctly, the skill bypasses external APIs entirely, using a vendored Node.js-based Bird client to execute queries locally.

## What AUTH_TOKEN and CT0 Store

The skill recognizes two specific X session cookies that identify a logged-in account:

- **`AUTH_TOKEN`** – Maps to the `auth_token` cookie from **x.com**. In [`scripts/lib/bird_x.py`](https://github.com/mvanhorn/last30days-skill/blob/main/scripts/lib/bird_x.py), this value is injected into the Bird client via `set_credentials()` (lines 29-38) and later passed to subprocess environments through `_subprocess_env()` (lines 46-53).
- **`CT0`** – Maps to the `ct0` cookie from **x.com**. This anti-CSRF token accompanies `AUTH_TOKEN` in all authenticated requests.

When both values are present, `bird_x.is_bird_authenticated()` returns the literal string `"env AUTH_TOKEN"` (lines 85-96), signaling that the skill should prefer the local Bird backend over the xAI API.

## Configuration File Locations and Priority

According to [`scripts/lib/env.py`](https://github.com/mvanhorn/last30days-skill/blob/main/scripts/lib/env.py) (lines 15-31), the loader merges configuration from three sources with the following precedence: **shell environment > project file > global file**.

| Location | File Path | Use Case |
|----------|-----------|----------|
| **Global** | `~/.config/last30days/.env` | Apply credentials across all projects on your machine |
| **Project-specific** | `<repo-root>/.claude/last30days.env` | Override global settings for a single repository |
| **Shell** | N/A (export directly) | Temporary testing without persisting to disk |

The README provides a ready-to-copy snippet at lines 71-78 for quick global setup.

## Step-by-Step AUTH_TOKEN and CT0 Setup

Create the global configuration directory and file, then restrict permissions to prevent credential leaks (the loader warns if permissions are too broad, as implemented in [`env.py`](https://github.com/mvanhorn/last30days-skill/blob/main/env.py) lines 50-61):

```bash
mkdir -p ~/.config/last30days
cat > ~/.config/last30days/.env <<'EOF'
AUTH_TOKEN=YOUR_X_AUTH_TOKEN_HERE
CT0=YOUR_X_CT0_COOKIE_HERE
EOF
chmod 600 ~/.config/last30days/.env

```

Verify that the Bird client detects the injected credentials:

```bash
node ~/.claude/skills/last30days/scripts/lib/vendor/bird-search/bird-search.mjs --whoami

```

Expected output: `env AUTH_TOKEN`

Run a research query to confirm the setup:

```bash
python3 scripts/last30days.py "latest AI trends" --debug

```

For project-specific overrides, create `.claude/last30days.env` in your repository root with the same two key-value pairs.

## How Credentials Flow Through the System

The authentication pipeline follows a strict sequence defined in the source code:

1. **Configuration Loading** – `env.get_config()` (lines 15-31) reads and merges the global `~/.config/last30days/.env`, the project-local `.claude/last30days.env`, and the current process environment.
2. **Credential Injection** – The main entry point in [`scripts/last30days.py`](https://github.com/mvanhorn/last30days-skill/blob/main/scripts/last30days.py) (lines 40-46) calls `bird_x.set_credentials()`, which stores the values in a module-level `_credentials` dictionary (lines 33-38).
3. **Subprocess Preparation** – When executing searches, `_subprocess_env()` (lines 46-53) constructs a custom environment dictionary that includes the two cookies, ensuring the Bird Node.js process receives them as environment variables.
4. **Authentication Verification** – The UI and diagnostic dumps (`--diagnose`, implemented in [`last30days.py`](https://github.com/mvanhorn/last30days-skill/blob/main/last30days.py) lines 44-76) rely on `is_bird_authenticated()` to display the active auth source.

## Backend Selection Logic

As implemented in `env.get_missing_keys()` (lines 61-66), the skill evaluates available X backends in this order:

- **Bird (cookie auth)** – Used when `AUTH_TOKEN` and `CT0` are present and Node.js 22+ is available. This is the fastest method and requires no external API key.
- **xAI API** – Used when `XAI_API_KEY` is defined but cookies are missing.

If both authentication methods are available, Bird wins by default because it operates locally without rate-limiting concerns from external services.

## Troubleshooting Common AUTH_TOKEN and CT0 Issues

| Symptom | Root Cause | Resolution |
|---------|------------|------------|
| `bird_x.is_bird_authenticated()` returns `None` | Credentials missing from all config sources, or file permissions are too open (readable by others). | Verify `.env` exists with both variables and run `chmod 600 ~/.config/last30days/.env`. |
| Node reports "module not found" | Node.js 22+ is not in `PATH`. Bird requires Node 22 or newer. | Install Node 22+ (e.g., `brew install node@22`). |
| Skill uses xAI API despite valid cookies | Project-level `.claude/last30days.env` exists but lacks the variables, overriding the global config. | Add the two cookie lines to the project env file or delete it to inherit global settings. |
| Credential leak warning in console | `.env` file has group or world read permissions (e.g., `644`). | The loader warns at lines 50-61; correct with `chmod 600` on the file. |

## Summary

- Store `AUTH_TOKEN` and `CT0` in `~/.config/last30days/.env` (global) or `.claude/last30days.env` (project-local).
- Set file permissions to `600` to prevent credential leaks.
- The [`env.py`](https://github.com/mvanhorn/last30days-skill/blob/main/env.py) loader merges configs with priority: shell > project > global (lines 15-31).
- [`bird_x.py`](https://github.com/mvanhorn/last30days-skill/blob/main/bird_x.py) injects cookies into the Bird subprocess via `_subprocess_env()` (lines 46-53).
- Bird authentication is verified through `is_bird_authenticated()` returning `"env AUTH_TOKEN"`.
- If cookies are absent, the skill automatically falls back to `XAI_API_KEY` when available.

## Frequently Asked Questions

### What is the difference between AUTH_TOKEN and CT0?

**`AUTH_TOKEN`** is the session identifier from x.com's `auth_token` cookie, while **`CT0`** is the anti-CSRF token required for authenticated POST requests. Both must be present together in the `.env` file for the Bird client to function, as the [`bird_x.py`](https://github.com/mvanhorn/last30days-skill/blob/main/bird_x.py) wrapper (lines 29-38) expects both values when building the subprocess environment.

### Why does the skill ignore my .env file?

The loader silently skips unreadable files or those with overly permissive permissions. Ensure your `.env` file has mode `600` (owner read/write only). Additionally, check for a project-local `.claude/last30days.env` that might be overriding your global configuration with empty values, as project files take precedence over global settings according to [`env.py`](https://github.com/mvanhorn/last30days-skill/blob/main/env.py) lines 15-31.

### Can I use both X cookies and XAI_API_KEY together?

Yes. You can define all three variables simultaneously. The skill prioritizes the Bird client (cookies) when `AUTH_TOKEN` and `CT0` are present, as determined by `env.get_missing_keys()` (lines 61-66). If you want to force the xAI API instead, either remove the cookie variables from your environment or temporarily unset them before running the skill.

### How do I verify my X authentication is working correctly?

Run the diagnostic flag: `python3 scripts/last30days.py --diagnose`. This executes the check in [`last30days.py`](https://github.com/mvanhorn/last30days-skill/blob/main/last30days.py) (lines 44-76) and prints the authentication source detected by `bird_x.is_bird_authenticated()`. If you see `"env AUTH_TOKEN"`, the cookies are properly injected. If you see `None` or a fallback message, review your `.env` file location and permissions.