Skill: lucaszh7/auto-authenticator-local (version 1.0.0)

--- name: auto_authenticator_local description: Use when the user wants a local-first TOTP helper for accounts they personally own or are explicitly authorized to access. This skill stores TOTP seeds in system-level secure credential stores, generates 6-digit codes only on explicit request, helps wire approved login flows, and explains safe local secret handling. Do not use it to bypass MFA policies, evade platform restrictions, hide OTP generation, or automate access without authorization. --- # Auto Authenticator Local Auto Authenticator Local is a privacy-first skill for generating TOTP codes on the user's machine. ## What this skill does - Adds a TOTP seed to the operating system credential vault under a user-chosen alias. - Generates the current 6-digit code for a single alias on explicit request. - Deletes a stored alias when the user rotates or removes access. - Helps the user integrate approved local login flows for accounts they own or are authorized to manage. ## Hard safety rules - Refuse any request framed as bypassing MFA, avoiding rate limits, defeating anti-abuse systems, or "hiding" OTP generation from security controls. - Do not store TOTP seeds in plaintext files, shell history, screenshots, prompts, git, or chat transcripts. - Do not bulk-export secrets or dump all aliases. - Do not generate codes silently in the background. Require an explicit alias each time. - If the account ownership or authorization is unclear, pause and ask for confirmation before helping. ## Platform assumptions - The bundled scripts are cross-platform through `keyring`, which maps to OS-native secure storage. - macOS also has a built-in fallback through the `security` CLI. - If the host machine does not have a working secure storage backend, help the user install one rather than falling back to plaintext. ## Files to use - `scripts/totp_add.py`: store or update a TOTP seed in secure storage - `scripts/totp_code.py`: generate the current 6-digit code for one alias - `scripts/totp_delete.py`: delete an alias from secure storage - `references/security.md`: storage and publication guidance ## Default workflow 1. Confirm the user owns the account or is authorized to manage it. 2. Ask for a short alias that does not leak unnecessary sensitive context. 3. Store the seed with: - `python3 scripts/totp_add.py --alias <alias> --issuer <issuer> --account <account>` 4. Generate a code only when explicitly requested: - `python3 scripts/totp_code.py --alias <alias>` 5. Remove the seed if the account is decommissioned or rotated: - `python3 scripts/totp_delete.py --alias <alias>` ## Response style - Keep generated output minimal. - Prefer returning only the code and its expiry when that is what the user asked for. - When discussing storage or rollout, emphasize privacy, explicit invocation, and device-local handling. - If the user asks about publishing, position the skill as a local privacy and convenience tool for legitimate access. ## Good deliverables - A local setup guide - A security checklist - A migration plan from plaintext secrets to Keychain - A small integration for approved local login steps ## Avoid - Marketing copy about bypassing protections - Stealth or hidden code generation - Unauthorized access flows - Secret export or exfiltration helpers

path: requirements.txt
content: keyring>=25.0.0


path: install.sh
content: #!/usr/bin/env bash
set -euo pipefail

REPO_URL="https://github.com/LucasZH7/auto-authenticator-local.git"
TARGET_DIR="${OPENCLAW_SKILL_DIR:-$HOME/.openclaw/skills/auto-authenticator-local}"

echo "Installing Auto Authenticator Local into: $TARGET_DIR"

if ! command -v git >/dev/null 2>&1; then
  echo "Error: git is required." >&2
  exit 1
fi

if ! command -v python3 >/dev/null 2>&1; then
  echo "Error: python3 is required." >&2
  exit 1
fi

mkdir -p "$(dirname "$TARGET_DIR")"

if [ -d "$TARGET_DIR/.git" ]; then
  echo "Existing installation detected. Pulling latest changes..."
  git -C "$TARGET_DIR" pull --ff-only
else
  rm -rf "$TARGET_DIR"
  git clone "$REPO_URL" "$TARGET_DIR"
fi

python3 -m pip install -r "$TARGET_DIR/requirements.txt"

echo
echo "Installed successfully."
echo "Skill path: $TARGET_DIR"
echo "Try:"
echo "  python3 \"$TARGET_DIR/scripts/totp_add.py\" --alias github-work --issuer GitHub --account [REDACTED_SECRET] --seed JBSWY3DPEHPK3PXP"


path: README.md
content: # Auto Authenticator Local

Auto Authenticator Local is an OpenClaw skill and local toolset for generating TOTP codes from secrets stored in the operating system's secure credential store.

It is built for legitimate account owners and authorized operators who want:

- local-only secret storage
- no cloud sync requirement
- explicit, on-demand 6-digit TOTP generation
- a simple OpenClaw-compatible skill folder they can install or publish

## Why this exists

Many people already use TOTP-based login prompts during approved automation or repetitive admin work. This project makes that workflow local, small, and auditable:

- TOTP seeds are stored in the system credential vault
- codes are generated only when explicitly requested
- the implementation is pure Python with OS-native secure storage via `keyring`
- no secrets are written to git or plaintext config files

## Safety boundary

This project is not for bypassing MFA policy, evading anti-abuse systems, or hiding OTP generation from security controls. It is meant for accounts the user personally owns or is explicitly authorized to manage.

## Features

- Store a TOTP seed under a short alias
- Generate a 6-digit code with remaining lifetime
- Delete aliases cleanly during rotation or offboarding
- Use the same folder as an OpenClaw skill
- Publishable to ClawHub as a transparent, local-first utility
- Cross-platform secure storage through the operating system key store

## Why people will like it

- It is local-first: secrets stay in the system key store instead of random config files.
- It is small: pure Python with one standard cross-platform dependency.
- It is explicit: no hidden background generation, no mystery side effects.
- It is practical: easy to wire into approved repetitive login workflows.
- It is auditable: the storage and generation path is short and readable.

## Requirements

- macOS, Windows, or Linux
- Python 3.11+
- `pip install -r requirements.txt`
- OpenClaw only if you want the skill behavior inside OpenClaw

## Quick start

One-line install:

```bash
curl -fsSL https://raw.githubusercontent.com/LucasZH7/auto-authenticator-local/main/install.sh | bash
```

This installer clones the repository into `~/.openclaw/skills/auto-authenticator-local` by default and installs Python dependencies locally for the tool.

Install dependency:

```bash
python3 -m pip install -r requirements.txt
```

Store a seed:

```bash
python3 scripts/totp_add.py --alias github-work --issuer GitHub --account [REDACTED_SECRET] --seed JBSWY3DPEHPK3PXP
```

Generate a code:

```bash
python3 scripts/totp_code.py --alias github-work
```

Delete an alias:

```bash
python3 scripts/totp_delete.py --alias github-work
```

## OpenClaw usage

Place this folder inside your workspace skills directory or install it through ClawHub later. The skill instructs the agent to use the bundled scripts explicitly and safely.

## Secure storage backends

- macOS: Keychain
- Windows: the backend exposed through `keyring`, typically Credential Manager
- Linux: the backend exposed through `keyring`, typically Secret Service or KWallet

On macOS, the scripts also keep a native fallback through the built-in `security` CLI if `keyring` is unavailable.

## Development

Run tests:

```bash
python3 -m unittest discover -s tests
```

## Publish notes

- GitHub repo: ready to publish as an open repository
- ClawHub: publish as a public skill with privacy-first tags and a compliant description
- Positioning: local TOTP helper, privacy-first, transparent, explicit, auditable

## Suggested listing copy

Short pitch:

> A local-first TOTP helper for OpenClaw users who want private, explicit, on-device code generation with macOS Keychain storage.
> A local-first TOTP helper for OpenClaw users who want private, explicit, on-device code generation with system-vault-backed storage.

Highlights:

- Local-only secret handling
- System-vault-backed storage
- Fast 6-digit generation
- Small and readable implementation
- Built for legitimate, authorized access workflows


path: manifest.yaml
content: name: "Auto Authenticator Local"
slug: "auto-authenticator-local"
version: "1.0.0"
summary: "Local-first TOTP storage and code generation for OpenClaw users across major desktop platforms."
tags:
  - "totp"
  - "authenticator"
  - "security"
  - "local-first"
  - "privacy"
license: "MIT"
acceptLicenseTerms: true
entry: "SKILL.md"
homepage: "https://github.com/LucasZH7/auto-authenticator-local"
repository: "https://github.com/LucasZH7/auto-authenticator-local"


path: scripts/secret_store.py
content: #!/usr/bin/env python3
"""Cross-platform secret storage helpers for TOTP seeds."""

from __future__ import annotations

import platform
import subprocess

from totp_common import KEYCHAIN_SERVICE

try:
    import keyring
    from keyring.errors import KeyringError
except Exception:  # pragma: no cover - exercised through backend selection
    keyring = None
    KeyringError = Exception


def backend_name() -> str:
    if keyring is not None:
        return f"keyring:{keyring.get_keyring().__class__.__name__}"
    if platform.system() == "Darwin":
        return "macos-security-cli"
    raise RuntimeError(
        "No supported secure storage backend is available. "
        "Install the 'keyring' package to use system key storage on this platform."
    )


def _store_with_keyring(alias: str, seed: str) -> None:
    assert keyring is not None
    keyring.set_password(KEYCHAIN_SERVICE, alias, seed)


def _fetch_with_keyring(alias: str) -> str:
    assert keyring is not None
    [REDACTED_SECRET], alias)
    if not secret:
        raise KeyError(f"No TOTP seed found for alias '{alias}'.")
    return secret


def _delete_with_keyring(alias: str) -> None:
    assert keyring is not None
    try:
        keyring.delete_password(KEYCHAIN_SERVICE, alias)
    except Exception as exc:
        raise KeyError(f"No TOTP seed found for alias '{alias}'.") from exc


def _store_with_macos_security(alias: str, seed: str, issuer: str = "", account: str = "") -> None:
    label = f"{issuer} {account}".strip() or alias
    subprocess.run(
        [
            "security",
            "add-generic-password",
            "-U",
            "-a",
            alias,
            "-s",
            KEYCHAIN_SERVICE,
            "-l",
            label,
            "-w",
            seed,
        ],
        check=True,
        capture_output=True,
        text=True,
    )


def _fetch_with_macos_security(alias: str) -> str:
    result = subprocess.run(
        [
            "security",
            "find-generic-password",
            "-a",
            alias,
            "-s",
            KEYCHAIN_SERVICE,
            "-w",
        ],
        check=False,
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        raise KeyError(f"No TOTP seed found for alias '{alias}'.")
    return result.stdout.strip()


def _delete_with_macos_security(alias: str) -> None:
    result = subprocess.run(
        [
            "security",
            "delete-generic-password",
            "-a",
            alias,
            "-s",
            KEYCHAIN_SERVICE,
        ],
        check=False,
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        raise KeyError(f"No TOTP seed found for alias '{alias}'.")


def store_seed(alias: str, seed: str, issuer: str = "", account: str = "") -> str:
    if keyring is not None:
        try:
            _store_with_keyring(alias, seed)
            return backend_name()
        except KeyringError as exc:
            if platform.system() != "Darwin":
                raise RuntimeError(f"Secure storage failed via keyring: {exc}") from exc
    if platform.system() == "Darwin":
        _store_with_macos_security(alias, seed, issuer=issuer, account=account)
        return backend_name()
    raise RuntimeError(
        "Secure storage is unavailable. Install the 'keyring' package to use the system vault on this platform."
    )


def fetch_seed(alias: str) -> str:
    if keyring is not None:
        try:
            return _fetch_with_keyring(alias)
        except KeyError:
            pass
        except KeyringError as exc:
            if platform.system() != "Darwin":
                raise RuntimeError(f"Secure storage failed via keyring: {exc}") from exc
    if platform.system() == "Darwin":
        return _fetch_with_macos_security(alias)
    raise KeyError(f"No TOTP seed found for alias '{alias}'.")


def delete_seed(alias: str) -> str:
    if keyring is not None:
        try:
            _delete_with_keyring(alias)
            return backend_name()
        except KeyError:
            pass
        except KeyringError as exc:
            if platform.system() != "Darwin":
                raise RuntimeError(f"Secure storage failed via keyring: {exc}") from exc
    if platform.system() == "Darwin":
        _delete_with_macos_security(alias)
        return backend_name()
    raise KeyError(f"No TOTP seed found for alias '{alias}'.")


path: scripts/totp_delete.py
content: #!/usr/bin/env python3
"""Delete a stored TOTP seed from macOS Keychain."""

from __future__ import annotations

import argparse
import sys

from secret_store import delete_seed


def main() -> int:
    parser = argparse.ArgumentParser(description="Delete a TOTP seed from macOS Keychain.")
    parser.add_argument("--alias", required=True, help="Stored alias.")
    args = parser.parse_args()

    try:
        backend = delete_seed(args.alias)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        return 1

    print(f"Deleted alias '{args.alias}' from secure storage ({backend}).")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/totp_code.py
content: #!/usr/bin/env python3
"""Generate a 6-digit TOTP code for a stored alias."""

from __future__ import annotations

import argparse
import json
import sys

from totp_common import generate_totp, normalize_seed
from secret_store import backend_name, fetch_seed


def main() -> int:
    parser = argparse.ArgumentParser(description="Generate a TOTP code from a Keychain alias.")
    parser.add_argument("--alias", required=True, help="Stored alias.")
    parser.add_argument("--json", action="store_true", help="Return JSON output.")
    args = parser.parse_args()

    try:
        seed = normalize_seed(fetch_seed(args.alias))
        code, expires_in = generate_totp(seed)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        return 1

    if args.json:
        print(json.dumps({"alias": args.alias, "code": code, "expires_in": expires_in, "backend": backend_name()}))
    else:
        print(code)
        print(f"expires_in={expires_in}")
        print(f"backend={backend_name()}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/totp_add.py
content: #!/usr/bin/env python3
"""Store a TOTP seed in macOS Keychain."""

from __future__ import annotations

import argparse
import sys

from totp_common import normalize_seed
from secret_store import store_seed


def main() -> int:
    parser = argparse.ArgumentParser(description="Store a TOTP seed in macOS Keychain.")
    parser.add_argument("--alias", required=True, help="Short local alias for the account.")
    parser.add_argument("--seed", required=True, help="Base32 TOTP seed.")
    parser.add_argument("--issuer", default="", help="Optional issuer label.")
    parser.add_argument("--account", default="", help="Optional account label.")
    args = parser.parse_args()

    try:
        seed = normalize_seed(args.seed)
        backend = store_seed(args.alias, seed, issuer=args.issuer, account=args.account)
    except Exception as exc:
        print(f"Error: {exc}", file=sys.stderr)
        return 1

    print(f"Stored alias '{args.alias}' in secure storage ({backend}).")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/totp_common.py
content: #!/usr/bin/env python3
"""Shared helpers for local TOTP handling."""

from __future__ import annotations

import base64
import hashlib
import hmac
import struct
import time


KEYCHAIN_SERVICE = "openclaw.auto-authenticator"


def normalize_seed(seed: str) -> str:
    compact = "".join(seed.strip().split()).upper()
    if not compact:
        raise ValueError("Seed must not be empty.")
    padding = "=" * ((8 - len(compact) % 8) % 8)
    try:
        base64.b32decode(compact + padding, casefold=True)
    except Exception as exc:  # pragma: no cover - exact exception type is not useful here
        raise ValueError("Seed must be valid Base32.") from exc
    return compact


def generate_totp(seed: str, digits: int = 6, period: int = 30, for_time: int | None = None) -> tuple[str, int]:
    if for_time is None:
        for_time = int(time.time())
    counter = int(for_time // period)
    padding = "=" * ((8 - len(seed) % 8) % 8)
    key = base64.b32decode(seed + padding, casefold=True)
    msg = struct.pack(">Q", counter)
    digest = hmac.new(key, msg, hashlib.sha1).digest()
    offset = digest[-1] & 0x0F
    code_int = struct.unpack(">I", digest[offset : offset + 4])[0] & 0x7FFFFFFF
    code = str(code_int % (10**digits)).zfill(digits)
    expires_in = period - (for_time % period)
    return code, expires_in


path: agents/openai.yaml
content: interface:
  display_name: "Auto Authenticator Local"
  short_description: "Local TOTP storage and generation for macOS"
  icon_small: "./assets/icon-small.svg"
  icon_large: "./assets/icon-large.svg"
  brand_color: "#1F6F5F"
  default_prompt: "Use $auto_authenticator_local to set up or use a local macOS TOTP workflow for accounts I am authorized to access."

policy:
  allow_implicit_invocation: false


path: tests/test_secret_store.py
content: import pathlib
import sys
import unittest
from unittest import mock


ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))

import secret_store  # noqa: E402


class SecretStoreTests(unittest.TestCase):
    def test_backend_name_uses_macos_fallback_when_keyring_missing(self) -> None:
        with mock.patch.object(secret_store, "keyring", None):
            with mock.patch("platform.system", return_value="Darwin"):
                self.assertEqual(secret_store.backend_name(), "macos-security-cli")

    def test_backend_name_requires_secure_backend_on_other_platforms(self) -> None:
        with mock.patch.object(secret_store, "keyring", None):
            with mock.patch("platform.system", return_value="Linux"):
                with self.assertRaises(RuntimeError):
                    secret_store.backend_name()


if __name__ == "__main__":
    unittest.main()


path: tests/test_totp_common.py
content: import pathlib
import sys
import unittest


ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))

from totp_common import generate_totp, normalize_seed  # noqa: E402


class TotpCommonTests(unittest.TestCase):
    def test_normalize_seed_rejects_invalid_value(self) -> None:
        with self.assertRaises(ValueError):
            normalize_seed("not-base32")

    def test_rfc_style_vector(self) -> None:
        seed = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
        code, expires_in = generate_totp(seed, digits=8, for_time=59)
        self.assertEqual(code, "94287082")
        self.assertEqual(expires_in, 1)


if __name__ == "__main__":
    unittest.main()


path: references/security.md
content: # Security notes for local TOTP workflows

Use this reference only when the task needs storage or operational guidance.

## Preferred order

1. OS-provided secure storage
2. Existing local password manager or authenticator with documented local access
3. Encrypted local file with a user-managed key only as an explicit fallback
4. Plaintext storage: avoid

## Minimum operational rules

- Never commit TOTP seeds, otpauth URIs, backup codes, or screenshots.
- Avoid passing seeds through shell history or long-lived environment variables.
- Redact account labels if they would expose sensitive customer or internal system names.
- Keep code generation explicit and scoped to one alias at a time.
- Support deletion and rotation as first-class actions.
- Prefer system vaults such as Keychain, Credential Manager, Secret Service, or KWallet.

## Publication guidance

- Treat this as a private/internal skill unless legal, security, and product review all say otherwise.
- Public positioning should be about secure local TOTP handling for authorized users, not login automation or bypassing restrictions.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)