OTP Identity Challenge Skill
Purpose: Enable agents and skills to challenge users for fresh two-factor authentication proof before executing sensitive actions.
What This Is For
This skill provides identity verification for approval workflows. When your agent needs to execute a command with change-control concerns (deploying code, modifying infrastructure, accessing sensitive data, financial transactions), it can challenge the user to prove their identity with a time-based one-time password (TOTP).
This is not about securing your chat channel—it's about verifying identity before specific actions.
Use Cases
- •Deploy commands: Require fresh 2FA before
kubectl applyorterraform apply - •Financial operations: Verify identity before wire transfers or payment approvals
- •Data access: Challenge before exporting customer data or PII
- •Admin operations: Verify before user account modifications or permission changes
- •Change control: Enforce approval workflows with cryptographic proof of identity
How It Works
- •Your agent or skill calls
verify.shwith the user's ID and their 6-digit code - •The skill validates the code against your TOTP secret
- •If valid, verification state is recorded with a timestamp
- •Other scripts can check
check-status.shto see if verification is still fresh - •Verification expires after a configured interval (default: 24 hours)
Installation
Via ClawHub (recommended)
clawhub install otp
Manual
cd ~/.openclaw/skills git clone https://github.com/ryancnelson/otp-skill.git otp
Check Dependencies
After installation, verify required dependencies:
# Check what's available which jq && echo "✅ jq available" || echo "❌ Install: brew install jq" which python3 && echo "✅ python3 available" || echo "❌ Install: brew install python3" which oathtool && echo "✅ oathtool available" || echo "❌ Install: brew install oath-toolkit"
Note: oathtool is optional - the skill includes a built-in TOTP generator, but oathtool provides additional validation.
Setup
1. Generate a TOTP Secret
Use the included secret generator:
cd ~/.openclaw/skills/otp ./generate-secret.sh "your-email@example.com"
This will display:
- •A QR code to scan with your authenticator app
- •The base32 secret for manual entry
- •Configuration instructions
Alternative: Use any other TOTP secret generator. You need a base32-encoded secret.
2. Scan QR Code
Add the secret to your authenticator app:
- •Google Authenticator
- •Authy
- •1Password
- •Bitwarden
- •Any RFC 6238 compatible app
3. Store the Secret
Option A: In your OpenClaw config
# ~/.openclaw/config.yaml
security:
otp:
secret: "YOUR_BASE32_SECRET_HERE"
accountName: "user@example.com"
issuer: "OpenClaw"
intervalHours: 24 # Re-verify every 24 hours
Option B: In environment variable
export OTP_SECRET="YOUR_BASE32_SECRET_HERE"
Option C: In 1Password (recommended for security)
security:
otp:
secret: "op://vault/OpenClaw OTP/totp"
4. Test Your Setup
After configuring the secret, test that everything works:
# Get current code from your authenticator app (6 digits) ./verify.sh "testuser" "123456" # Replace with actual code # Should show: ✅ OTP verified for testuser (valid for 24 hours) # Check verification status ./check-status.sh "testuser" # Should show: ✅ Valid for 23 more hours # Test error case ./verify.sh "testuser" "000000" # Should show: ❌ Invalid OTP code
5. Optional: Run Test Suite
Full test suite available at: https://github.com/ryancnelson/otp-challenger
Usage
For Skill Authors
When your skill needs to verify user identity:
#!/bin/bash # In your sensitive-action.sh # Source the OTP skill source ../otp/verify.sh USER_ID="$1" OTP_CODE="$2" # Challenge the user if ! verify_otp "$USER_ID" "$OTP_CODE"; then echo "❌ OTP verification failed. Run: /otp <code>" exit 1 fi # Proceed with sensitive action echo "✅ Identity verified. Proceeding with deployment..." kubectl apply -f production.yaml
Checking Verification Status
#!/bin/bash source ../otp/check-status.sh if check_otp_status "$USER_ID"; then echo "✅ User verified within last 24 hours" else echo "⚠️ Verification expired. User must verify again." fi
For End Users
When prompted by a skill:
User: deploy to production Agent: 🔒 This action requires identity verification. Please provide your OTP code. User: /otp 123456 Agent: ✅ Identity verified. Deploying to production...
Scripts
- •
verify.sh <user_id> <code>- Verify OTP code and update state - •
check-status.sh <user_id>- Check if user verification is still valid - •
generate-secret.sh <account_name>- Generate new TOTP secret - •
get-current-code.sh <secret>- Get current valid code (testing only)
Configuration
Set these in your OpenClaw config or environment:
- •
OTP_SECRET- Base32 TOTP secret (required) - •
OTP_INTERVAL_HOURS- Verification expiry (default: 24) - •
OTP_GRACE_PERIOD_MINUTES- Grace period after expiry (default: 15) - •
OTP_STATE_FILE- State file path (default:memory/otp-state.json)
Security Considerations
What This Protects Against
- •Session hijacking: Even if someone steals your chat session, they can't execute protected actions without your physical device
- •Replay attacks: Codes are time-based and expire quickly
- •Unauthorized actions: Cryptographic proof that you authorized the specific action
What This Doesn't Protect Against
- •Compromised agent: If someone has shell access to your OpenClaw instance, they can read the secret
- •Phishing: Users can still be tricked into providing codes to malicious actors
- •Device theft: If someone has your authenticator device, they can generate codes
Best Practices
- •Store secrets securely: Use 1Password/Bitwarden references, not plaintext in config
- •Short expiry: Keep
intervalHoursreasonable (8-24 hours) - •Audit logs: Skills should log verification events
- •Scope carefully: Only require OTP for truly sensitive actions
- •Clear prompts: Always tell users WHY they're being asked for OTP
Technical Details
TOTP Implementation
- •Standard: RFC 6238 (Time-Based One-Time Password)
- •Algorithm: HMAC-SHA1 (standard TOTP)
- •Time window: 30 seconds (configurable)
- •Code length: 6 digits
- •Clock skew: ±1 window tolerance (90 seconds total)
State Management
Verification state is stored in memory/otp-state.json:
{
"verifications": {
"user@example.com": {
"verifiedAt": 1706745600000,
"expiresAt": 1706832000000
}
}
}
No secrets are stored in state—only timestamps.
Dependencies
Required:
- •jq - for JSON state file manipulation
- •python3 - for secure YAML config parsing
Optional:
- •oathtool - provides additional TOTP validation (skill has built-in generator)
- •Node.js - only needed for
totp.mjsstandalone CLI - •bats - for running test suite (see full repo)
Examples
Deploy Command with OTP
#!/bin/bash # skills/deploy/production.sh source ../otp/verify.sh USER="$1" CODE="$2" SERVICE="$3" # Require OTP for production deploys if ! verify_otp "$USER" "$CODE"; then echo "🔒 Production deployment requires OTP verification" echo "Usage: deploy production <service> --otp <code>" exit 1 fi echo "✅ Identity verified. Deploying $SERVICE to production..." # ... deployment logic ...
Payment Authorization
#!/bin/bash # skills/finance/transfer.sh source ../otp/check-status.sh USER="$1" AMOUNT="$2" RECIPIENT="$3" # Check if user verified recently if ! check_otp_status "$USER"; then echo "💳 Large transfer requires fresh identity verification" echo "Please verify with: /otp <code>" exit 1 fi echo "✅ Processing transfer of \$$AMOUNT to $RECIPIENT" # ... transfer logic ...
Philosophy
OTP should be invisible when not needed, obvious when required.
Don't force users to verify for every action—that trains them to treat it as a meaningless ritual. Only challenge when:
- •The action has real-world consequences
- •The risk justifies the friction
- •You need cryptographic proof of intent
Think of OTP like sudo—you use it before commands that matter, not every command.
Troubleshooting
"OTP verification failed"
- •Check your authenticator app has the correct secret
- •Verify system time is synchronized (NTP)
- •Try the code from the previous/next 30-second window
"Secret not configured"
- •Set
OTP_SECRETenvironment variable - •Or configure
security.otp.secretin OpenClaw config
"State file not found"
- •First verification creates the file
- •Check
memory/directory permissions
License
MIT
Contributing
Issues and PRs welcome at: https://github.com/ryancnelson/otp-challenger
See Also
- •RFC 6238 - TOTP specification
- •OpenClaw Approval Workflows
- •Security Best Practices