Skip to the content.

YubiKey TOTP Sync Guide

Date: 2025-11-21
Updated: 2025-12-22 (see Provisioning alternative below)
Purpose: Complete guide for syncing TOTP accounts between YubiKeys


Quick Note: Profile-Based Provisioning (New)

Version 0.3.2+ introduced profile-based provisioning as an alternative to manual syncing:

See YubiKey TOTP Provisioning Guide for profile-based setup with tag-based account filtering.


Overview

The Bastion tool provides powerful commands to sync TOTP accounts between YubiKeys, enabling easy setup of redundant YubiKeys with the same accounts.

Key Features

Password Auto-Loading: Automatically retrieves OATH passwords from 1Password vault
Batch Syncing: Copy all accounts from one YubiKey to another in one command
Smart Conflict Resolution: Handles existing accounts intelligently
Idempotent Operations: Safe to run multiple times, produces consistent results
Progress Tracking: Clear feedback on what’s being synced
Automatic Updates: Keeps 1Password vault items in sync with hardware


Prerequisites

Before syncing, your YubiKeys should be linked to their corresponding 1Password crypto wallet items. This enables automatic password retrieval.

# Link all connected YubiKeys automatically
bsec 1p link yubikey --all

# Or link a specific YubiKey
bsec 1p link yubikey 12345678

# Link with specific 1Password UUID (if auto-search doesn't work)
bsec 1p link yubikey 12345678 abc123example456def789ghi

What linking does:

1Password Item Requirements:

2. Ensure Cache is Current

# Refresh the cache to see current accounts on all YubiKeys
bsec refresh yubikey

Sync Commands

Basic Sync: One YubiKey to Another

Copy all TOTP accounts from a source YubiKey to a target YubiKey:

# Sync from YubiKey 12345678 to YubiKey 34567890
bsec sync yubikey --from 12345678 --to 34567890

What happens:

  1. Reads the cache to find all accounts on source YubiKey
  2. Extracts the 1Password UUIDs for those accounts
  3. Checks if target YubiKey is linked to 1Password
  4. Auto-loads OATH password from 1Password (if linked)
  5. Migrates each account to the target YubiKey
  6. Updates the oath_accounts field in the target YubiKey’s 1Password item
  7. Updates the yubikey_serials field in each account’s 1Password item

Sync to All Other YubiKeys

Copy accounts to all YubiKeys except the source:

# Sync from YubiKey 12345678 to all other YubiKeys in cache
bsec sync yubikey --from 12345678 --to all

Use case: You’ve set up one YubiKey with all your accounts and want to copy them to your backup YubiKeys.

Interactive Selection

If you don’t specify --to, the tool prompts you:

bsec sync yubikey --from 12345678

# Prompts:
# Available target YubiKeys:
#   34567890 (Backup #1) - 5 accounts
#   56789012 (Backup #2) - 0 accounts
#
# Sync to which YubiKeys? (comma-separated serials or 'all') [all]:

Password Handling

When YubiKeys are linked to 1Password:

bsec sync yubikey --from 12345678 --to 34567890

# Output:
# Checking YubiKey 34567890 for password in 1Password...
#   Found 1Password UUID: abc123example456def789ghi
# ✓ Loaded OATH password from 1Password for YubiKey 34567890
# ✓ All target YubiKeys use the same OATH password (auto-loaded from 1Password)
#
# Starting sync...

No password prompts! The tool automatically uses the stored password.

Multiple Different Passwords

If target YubiKeys have different OATH passwords stored in 1Password:

Warning: Target YubiKeys have different OATH passwords
Will use stored passwords per YubiKey

Syncing: 1Password
✓ Added to YubiKey 34567890
✓ Added to YubiKey 56789012

The tool uses the correct password for each YubiKey automatically.

Manual Password Entry

If YubiKeys are not linked to 1Password:

bsec sync yubikey --from 12345678 --to 34567890

# Output:
# Warning: 1 YubiKey(s) not linked to 1Password:
#   • 34567890
#
# To link these YubiKeys and store passwords in 1Password:
#   1. Run: bsec 1p link yubikey --serial 34567890
#   2. Or run: bsec 1p link yubikey --all to link all connected YubiKeys
#
# Linking allows automatic password retrieval for future migrations.
#
# Would you like to continue with manual password entry? [Y/n]:

If you proceed, you’ll be prompted once for the OATH password:

No OATH passwords found in 1Password for target YubiKeys
Enter YubiKey OATH password (or press Enter if none): 

Pro tip: Link your YubiKeys first to avoid password prompts!


What Gets Updated

1. YubiKey Hardware

Each TOTP account is added to the target YubiKey(s) with:

2. 1Password Account Items

For each synced account, the tool updates:

yubikey_serials field (appends, doesn’t replace):

Before: 12345678
After:  12345678,34567890

yubikey_oath_name field (if not present):

Value: "1Password:user@example.com"

3. 1Password YubiKey Items

The crypto wallet item for each target YubiKey gets updated:

oath_accounts field (comma-separated list):

1Password:user@example.com, Gmail:user@example.com, AWS:user@example.com, ...

This provides visibility into what’s on each YubiKey directly in 1Password.


Sync Workflow Example

Scenario: Setting Up Redundant YubiKeys

You have:

Goal: Copy all 17 accounts to both backup YubiKeys.

Step 1: Ensure Cache is Current

bsec refresh yubikey
bsec 1p link yubikey --all

This searches 1Password for items with matching serial numbers and links them.

Step 3: Sync to All Backups

bsec sync yubikey --from 12345678 --to all

Output:

Found 17 accounts on source YubiKey 12345678

Will sync 17 accounts to 2 YubiKey(s)
  → 34567890 (Backup #1)
  → 56789012 (Backup #2)

Proceed with sync? [Y/n]: y

Starting sync...

✓ Loaded OATH password from 1Password for YubiKey 34567890
✓ Loaded OATH password from 1Password for YubiKey 56789012
✓ All target YubiKeys use the same OATH password (auto-loaded from 1Password)

Will migrate 17 unique accounts

Syncing: 1Password
✓ 1Password
Syncing: Gmail
✓ Gmail
[... 15 more accounts ...]

Sync complete: 17/17 accounts synced

Updating YubiKey crypto wallet items...
  Checking YubiKey 34567890...
    Found 17 OATH accounts in cache
✓ Updated YubiKey 34567890 crypto wallet with 17 OATH accounts
  Checking YubiKey 56789012...
    Found 17 OATH accounts in cache
✓ Updated YubiKey 56789012 crypto wallet with 17 OATH accounts

Step 4: Verify

Check the 1Password items:

  1. Each account (e.g., “1Password”) now has:
    • yubikey_serials = "12345678,34567890,56789012"
  2. Each YubiKey crypto wallet item now has:
    • oath_accounts = "1Password:user@example.com, Gmail:user@example.com, ..."

Troubleshooting

“Source YubiKey not found in cache”

bsec refresh yubikey

The source YubiKey must be in the cache. Connect it and refresh.

“YubiKey not linked to 1Password”

bsec 1p link yubikey --serial 34567890

Or update the 1Password crypto wallet item to include the serial number in the SN field.

“No 1Password linked accounts found on YubiKey”

The accounts on the source YubiKey must have been migrated using the Bastion tool (not added manually). Only accounts with 1Password UUID mappings can be synced.

To check which accounts have mappings:

# View the cache
cat yubikey-slots-cache.json | grep -A 5 "12345678"

Duplicate Accounts on Target

The sync command is idempotent - it detects existing accounts using:

  1. The yubikey_oath_name custom field in 1Password
  2. UUID mapping in the cache
  3. Direct OATH name matching

If an account already exists, it’s replaced with the updated version. Safe to run multiple times!

Different OATH Passwords

If your YubiKeys have different OATH passwords:

  1. Link each YubiKey to its 1Password item
  2. Ensure the password field is set correctly in each item
  3. The sync command will use the appropriate password for each YubiKey

Advanced Usage

Sync Specific Accounts Only

The sync command copies all accounts from the source. If you want to sync specific accounts:

# Migrate individual accounts
bsec 1p migrate yubikey "Account Name"

# When prompted for target YubiKeys, select the ones you want

Re-sync After Changes

If you’ve updated TOTP secrets in 1Password:

# Re-sync will update existing accounts
bsec sync yubikey --from 12345678 --to all

The tool detects existing accounts and replaces them with updated versions.

Audit Slot Usage

After syncing, check how many slots are used:

bsec 1p audit yubikey

Output shows slot usage per YubiKey (32 max for OATH-TOTP).

Clean Stale Cache Entries

If you’ve manually removed accounts from YubiKeys:

bsec clean yubikey

This syncs the cache with actual hardware state.


Field Reference

1Password Custom Fields

These fields are automatically created/updated by the Bastion tool:

In Account Items (Login category)

yubikey_oath_name (text):

yubikey_serials (text):

In YubiKey Items (Crypto Wallet category)

SN (text):

oath_accounts (text):

password (password):


Best Practices

Always run bsec 1p link yubikey --all before your first sync to enable password auto-loading.

2. Sync in One Direction

Pick one YubiKey as the “source of truth” and sync from it to others. Don’t sync in multiple directions as this can cause confusion.

3. Verify After Syncing

Check the oath_accounts field in 1Password to confirm all accounts were added.

4. Keep Cache Fresh

Run bsec refresh yubikey regularly, especially after manually adding/removing accounts.

5. Test TOTP Codes

After syncing, generate a test code from each YubiKey to ensure it’s working:

ykman --device 34567890 oath accounts code "1Password:user@example.com"

6. Document YubiKey Roles

Use clear role names when linking YubiKeys:

This makes it clear which YubiKey is which in audit outputs.


# Link YubiKeys to 1Password
bsec 1p link yubikey --all

# Refresh cache
bsec refresh yubikey

# Migrate single account
bsec 1p migrate yubikey "Account Name"

# Audit slot usage
bsec 1p audit yubikey

# Clean cache
bsec clean yubikey

# View help
bsec sync --help

Summary

The bsec sync yubikey command makes it trivial to set up redundant YubiKeys:

  1. Set up one YubiKey with all your accounts
  2. Link all YubiKeys to 1Password: bsec 1p link yubikey --all
  3. Sync to backups: bsec sync yubikey --from SOURCE --to all
  4. Done! All YubiKeys now have the same TOTP accounts

With automatic password loading and smart conflict resolution, syncing is fast and error-free.