Codex: sign in without a browser (auth)
Drops a ready-made Codex login into a workspace so you do not have to authenticate in every new container. Supply it either way: **paste** the contents of `~/.codex/auth.json` from a machine where you are signed in, or **point at a file** — back a secret with `/home/dev/.codex/auth.json` in a workspace that is already signed in, and pick that secret. It is read fresh on every run, so a refreshed token reaches the next run without another paste. The value lands in `${CODEX_HOME:-~/.codex}/auth.json` (mode 600) and Codex is configured to use file-based credential storage. The old auth file is backed up to `auth.json.bak`; `jq` validates the JSON when available. **Security:** `auth.json` holds access tokens. It is collected as a secret and redacted from run logs. After it runs: start `codex` — it should come up already signed in.
What it asks for
- Codex auth JSONrequired
- The full contents of ~/.codex/auth.json from a machine where you are signed in — or a secret backed by that file in a workspace that is already signed in, which stays current without re-pasting. Redacted from run logs, and never persisted into the container environment profile.
- Overwrite existing login
- Choose 'no' to keep an auth.json already present in the container and only perform the remaining setup.
What it runs
The whole script, exactly as it will execute in your workspace. Nothing is hidden — read it before you run it.
#!/usr/bin/env sh
set -eu
umask 077
log() { printf '[codex-setup] %s\n' "$*"; }
warn() { printf '[codex-setup] WARNING: %s\n' "$*" >&2; }
die() { printf '[codex-setup] ERROR: %s\n' "$*" >&2; exit 1; }
AUTH_JSON="${CODEX_AUTH_JSON:-}"
OVERWRITE="${OVERWRITE_EXISTING_AUTH:-yes}"
CODEX_DIR="${CODEX_HOME:-$HOME/.codex}"
AUTH_FILE="$CODEX_DIR/auth.json"
CONFIG_FILE="$CODEX_DIR/config.toml"
[ -n "$AUTH_JSON" ] || die "no Codex auth JSON was supplied"
command -v codex >/dev/null 2>&1 \
|| die "the 'codex' CLI is not on PATH — run this in a workspace that has Codex installed"
if [ "$(id -u)" -eq 0 ]; then SUDO=""
elif command -v sudo >/dev/null 2>&1; then SUDO="sudo -n"
else SUDO=""
fi
# jq is optional: it validates the copied auth file. Never fail merely because
# jq cannot be installed; the login copy is still useful.
# This script body is piped to sh on stdin, so every installer gets </dev/null.
if ! command -v jq >/dev/null 2>&1; then
log "jq not found; attempting install (optional)"
export DEBIAN_FRONTEND=noninteractive
if command -v apt-get >/dev/null 2>&1; then $SUDO apt-get update -qq </dev/null && $SUDO apt-get install -y -qq jq </dev/null || true
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y jq </dev/null || true
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y jq </dev/null || true
elif command -v apk >/dev/null 2>&1; then $SUDO apk add --no-cache jq </dev/null || true
elif command -v pacman >/dev/null 2>&1; then $SUDO pacman -Sy --noconfirm jq </dev/null || true
elif command -v zypper >/dev/null 2>&1; then $SUDO zypper install -y jq </dev/null || true
elif command -v brew >/dev/null 2>&1; then brew install jq </dev/null || true
fi
command -v jq >/dev/null 2>&1 || warn "continuing without jq"
fi
mkdir -p "$CODEX_DIR"
if command -v jq >/dev/null 2>&1; then
printf '%s' "$AUTH_JSON" | jq empty >/dev/null 2>&1 \
|| die "the supplied value is not valid JSON — paste the whole auth.json contents, from '{' to '}'"
fi
if [ -f "$AUTH_FILE" ] && [ "$OVERWRITE" != "yes" ]; then
log "$AUTH_FILE already exists and overwrite is off — leaving it alone"
else
if [ -f "$AUTH_FILE" ]; then
cp -p "$AUTH_FILE" "$AUTH_FILE.bak"
log "backed up previous credentials to $AUTH_FILE.bak"
fi
printf '%s\n' "$AUTH_JSON" > "$AUTH_FILE"
chmod 600 "$AUTH_FILE"
log "wrote $AUTH_FILE (mode 600)"
fi
# A copied auth.json must be selected explicitly when a credential store is
# available. Keep all unrelated Codex configuration intact.
if [ -f "$CONFIG_FILE" ]; then
tmp="$CONFIG_FILE.devgrail.tmp"
trap 'rm -f "$tmp"' 0
if grep -Eq '^[[:space:]]*cli_auth_credentials_store[[:space:]]*=' "$CONFIG_FILE"; then
sed 's/^[[:space:]]*cli_auth_credentials_store[[:space:]]*=.*$/cli_auth_credentials_store = "file"/' "$CONFIG_FILE" > "$tmp"
else
{
printf '%s\n\n' 'cli_auth_credentials_store = "file"'
cat "$CONFIG_FILE"
} > "$tmp"
fi
if cmp -s "$CONFIG_FILE" "$tmp"; then
rm -f "$tmp"
trap - 0
log "$CONFIG_FILE already selects file-based credential storage"
else
cp -p "$CONFIG_FILE" "$CONFIG_FILE.bak"
mv "$tmp" "$CONFIG_FILE"
trap - 0
log "updated $CONFIG_FILE (backup: $CONFIG_FILE.bak)"
fi
else
printf '%s\n' 'cli_auth_credentials_store = "file"' > "$CONFIG_FILE"
log "created $CONFIG_FILE"
fi
chmod 600 "$CONFIG_FILE"
log "done. Run 'codex' — it should start without asking you to log in."
How to get it
Open your DevGrail workspace, go to Scripts → Official scripts, and choose Download. It is copied into your own library, where you can edit it, run it, or set it as a workspace default — the copy is yours, and later changes here do not touch it.