Privacy Tools Guide

Migrating from Safari Keychain to Bitwarden: Complete Migration Guide

Apple’s Safari Keychain provides basic password management for macOS and iOS users, but developers and power users often need more advanced features. Bitwarden offers open-source transparency, cross-platform support, CLI tooling, and self-hosting options. This guide covers the technical process of moving your credentials from Safari Keychain to Bitwarden using command-line methods.

Understanding Safari Keychain Export Limitations

Safari stores passwords in the macOS Keychain, which uses a proprietary format. Apple does not provide a direct export feature through its graphical interface, forcing users to rely on workarounds.

The primary challenge is accessing the Keychain in a format Bitwarden can import. Safari Keychain entries contain the website URL, username, password, and notes field. However, the export process requires either manual extraction or third-party tools.

For developers comfortable with command-line tools, several approaches exist:

  1. Using the security command-line tool (macOS built-in)
  2. Python scripts for parsing Keychain exports
  3. CSV conversion workflows for Bitwarden import

Method 1: Using the macOS Security Command

The security command provides access to Keychain data programmatically. Create a script to extract all Safari passwords:

#!/bin/bash
# extract-safari-keychain.sh

OUTPUT_FILE="safari_passwords.csv"
echo "url,username,password,notes" > "$OUTPUT_FILE"

# Get all Safari passwords
security find-internet-password -s safari -g 2>/dev/null | \
while read -r line; do
    if [[ "$line" == *"server:"* ]]; then
        url=$(echo "$line" | sed 's/.*server: \(.*\)/\1/')
    elif [[ "$line" == *"acct:"* ]]; then
        username=$(echo "$line" | sed 's/.*acct: <.*> \(.*\)/\1/')
    elif [[ "$line" == *"password:"* ]]; then
        password=$(echo "$line" | sed 's/.*password: "\(.*\)"/\1/')
        echo "$url,$username,$password," >> "$OUTPUT_FILE"
    fi
done

This script queries the login Keychain for Safari credentials and formats them as CSV.

Method 2: Python-Based Extraction with Keyring

For more reliable extraction, use Python with the keyring library:

#!/usr/bin/env python3
# extract_keychain.py

import keyring
import csv
import subprocess

def get_safari_passwords():
    """Extract Safari passwords from Keychain"""
    passwords = []

    # Query Keychain for Safari entries
    result = subprocess.run(
        ['security', 'dump-keychain'],
        capture_output=True,
        text=True
    )

    # Parse the output for Safari passwords
    current_entry = {}
    for line in result.stdout.split('\n'):
        if 'server' in line.lower():
            current_entry['url'] = line.split('=')[-1].strip().strip('"')
        elif 'acct' in line.lower():
            current_entry['username'] = line.split('=')[-1].strip().strip('"')
        elif 'password' in line.lower() and 'password\00' not in line.lower():
            # Extract password value
            current_entry['password'] = line.split('=')[-1].strip().strip('"')

            if current_entry.get('url') and 'safari' in current_entry.get('url', '').lower():
                passwords.append(current_entry)
            current_entry = {}

    return passwords

def export_to_csv(passwords, filename='bitwarden_import.csv'):
    """Export to Bitwarden-compatible CSV format"""
    with open(filename, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['folder', 'favorite', 'type', 'name', 'notes',
                        'fields', 'login_uri', 'login_username',
                        'login_password', 'login_totp'])

        for entry in passwords:
            writer.writerow([
                '',  # folder
                '',  # favorite
                'login',  # type
                entry.get('url', ''),  # name
                '',  # notes
                '',  # custom fields
                entry.get('url', ''),  # URI
                entry.get('username', ''),  # username
                entry.get('password', ''),  # password
                ''  # TOTP
            ])

if __name__ == '__main__':
    passwords = get_safari_passwords()
    export_to_csv(passwords)
    print(f"Exported {len(passwords)} passwords to bitwarden_import.csv")

Install dependencies with:

pip install keyring

Method 3: Using Brett Terpstra’s Export Script

Many macOS users rely on Brett Terpstra’s Safari Password Exporter script, which provides a GUI for Keychain extraction. For command-line enthusiasts, the underlying mechanism works similarly.

Clone and run the exporter:

git clone https://github.com/tmestd/Safari-Password-Exporter.git
cd Safari-Password-Exporter
chmod +x SafariPasswordExporter.py
./SafariPasswordExporter.py

The tool generates a CSV file compatible with most password managers.

Preparing Data for Bitwarden Import

Bitwarden accepts CSV imports with specific column headers. Ensure your export follows this format:

Column Description
folder Optional folder name
favorite 0 or 1
type “login” for passwords
name Entry title
notes Additional notes
login_uri Website URL
login_username Username or email
login_password Password
login_totp TOTP seed (optional)

Clean your CSV before import:

# Remove empty lines and validate format
awk -F',' 'NF >= 8' safari_export.csv > bitwarden_import.csv

Importing into Bitwarden

Using the Web Vault

  1. Log into vault.bitwarden.com
  2. Navigate to SettingsImport Data
  3. Select Bitwarden (csv) as the format
  4. Upload your CSV file
  5. Click Import

Using Bitwarden CLI

For automation, use the Bitwarden CLI:

# Install CLI
brew install bitwarden-cli

# Login
bw login your@email.com

# Unlock vault
bw unlock

# Import the CSV
bw import bitwarden_csv bitwarden_import.csv

The CLI requires authentication, so you’ll need to complete the login flow interactively or use environment variables for scripted environments.

Handling TOTP Codes

Safari Keychain does not store TOTP seeds, so you’ll need to regenerate 2FA codes for each service. This is actually a security feature—migrating 2FA to a new device requires re-setup for each account.

For services requiring 2FA:

  1. Generate new TOTP codes in Bitwarden
  2. Update each account’s 2FA settings with the new code
  3. Test login on a secondary device before removing old 2FA

Bitwarden’s TOTP integration works with Google Authenticator, Authy, and hardware tokens.

Verification and Cleanup

After import, verify your data:

# List imported items using CLI
bw list items --folderid [folder-id] | jq '.[] | {name, login}'

Check for:

Delete the temporary CSV files afterward:

rm -f safari_export.csv bitwarden_import.csv

Security Considerations

When migrating passwords, follow these security practices:

Built by theluckystrike — More at zovo.one