Moving Passwords From Firefox (Lockwise) to KeePassXC

Update 2021-03-27: Good news, it seems KeepassXC 2.7.0 learned to import Firefox timestamps. 😀

Go to about:logins in Firefox.

Click on the three dots in the top right corner, select “Export Logins…” and save your passwords info a CSV file (e.g. exported_firefox_logins.csv).

There’s one complication: Firefox will save dates as Unix timestamps (with millisecond resolution) which KeePassXC doesn’t understand, so we’ll have to help it out.

Save the following script into a file (e.g. firefox_csv_date_fix.py).

#!/usr/bin/env python3
#
# Author: Riyad Preukschas <riyad@informatik.uni-bremen.de>
# License: Mozilla Public License 2.0
# SPDX-License-Identifier: MPL-2.0


import csv
import sys

from datetime import datetime


def main():
    if len(sys.argv) != 2:
        print("Usage: {} <exported_firefox_logins.csv>".format(sys.argv[0]), file=sys.stderr)
        exit(1)

    csv_file_name = sys.argv[1]

    with open(csv_file_name, 'rt') as f:
        # field names will be determined from first row
        csv_reader = csv.DictReader(f)
        # read all rows in one go
        rows = list(csv_reader)

    # add new columns with Iso-formatted dates
    for row in rows:
        row['timeCreatedIso'] = datetime.fromtimestamp(int(row['timeCreated'])/1000).isoformat()
        row['timeLastUsedIso'] = datetime.fromtimestamp(int(row['timeLastUsed'])/1000).isoformat()
        row['timePasswordChangedIso'] = datetime.fromtimestamp(int(row['timePasswordChanged'])/1000).isoformat()

    # write out the updated rows
    csv_writer = csv.DictWriter(sys.stdout, fieldnames=rows[0].keys())
    csv_writer.writeheader()
    csv_writer.writerows(rows)


if __name__ == '__main__':
    main()

Call it giving it the path of the exported_firefox_logins.csv file and redirect the output into a new file:

python3 ./firefox_csv_date_fix.py ./exported_firefox_logins.csv > ./fixed_firefox_logins.csv

It will add new columns (named: old column name + “Iso”) with the dates converted to the ISO 8601 format KeePassXC wants.

We can now use the fixed_firefox_logins.csv file to import the logins into KeePassXC.

Select Database -> Import -> CSV File... from the menu.

It will ask you to create a new database. Just do it you can get the data into your default database later (e.g. call it firefox_logins.kdbx for now).

In the import form select “First line has field names” and match up KeePassXC’s fields with the columns from the CSV:

KeePassXC FieldFirefox CSV ColumnNotes
GroupNot Present
TitleurlFirefox doesn’t have a title field so we use the URL for it.
Usernameusername
Passwordpassword
URLurl
NoteshttpRealmI’m not sure how KeePassXC deals with HTTP authentication. There’s no special field for it, so I decided to keep it in the Notes field.
TOTPNot Present
IconNot Present
Last ModifiedtimePasswordChangedIsothe “Iso” part is important!
CreatedtimeCreatedIsothe “Iso” part is important!

Have a look at the preview at the bottom. Does the data look sane? 🤨

Sadly KeePassXC doesn’t let us import Firefox’s timeLastUsedIso field into its Accessed field. 😑

All your imported Logins will be inside the “Root” group. I’d suggest creating a new group (e.g. “Firefox Import”) and moving all imported Logins into it.

You can now open your default database and use the Database -> Merge From Database ... menu item, select the firefox_logins.kdbx file to include it’s contents into the current database. You’ll see a new “Firefox Imports” group show up.

You can now move the single entries into the appropriate groups if you want (e.g. “KeePassXC-Browser Passwords” if you use the browser extension).

7 thoughts on “Moving Passwords From Firefox (Lockwise) to KeePassXC”

  1. Thank you Riyad, I installed KeePassXC today and was looking for an easy way to import the data from Firefox. Very helpful!

    Note that Firefox >= 79 is required to export the Lockwise database to CSV.

  2. Note that you can do all of this also without the Python script, but you will lose the Last modified and Created information. Also you will have to open the CSV file and count some columns for import.

    1. You are right 😀, but I find (at least) the “Last modified” column very important for proper password hygiene.

  3. Thanks a lot for the solution. For some reason, any “[” in the provided code is shown to me as the unicode decimal code “[”. So everything after the “#” was interpreted as a comment and the script didn’t work. I don’t know if this is on purpose, but I needed to change that manually. I found your guide on google and I am a beginner in programming, so I actually needed some time to find it out (and also how to use it). Now it works fine.

Leave a Reply

Your email address will not be published.