aboutsummaryrefslogtreecommitdiff
path: root/docs/USER_GUIDE.md
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-21 03:55:15 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-21 03:55:15 +0200
commitf439beec17419ccbe0dc7643cc039079f15e04a0 (patch)
tree02863a95ba3d8af263a68586370319e5559b00a8 /docs/USER_GUIDE.md
parent56e0c351bb95cfdf63aa76ab8c5d725a694bad63 (diff)
docs: user guide, known limitations and M8 results; bump to 0.8.0v0.8.0
0.8.0 is the release candidate: 1.0.0 is tagged after the on-watch checklist (docs/TESTING.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs/USER_GUIDE.md')
-rw-r--r--docs/USER_GUIDE.md194
1 files changed, 194 insertions, 0 deletions
diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md
new file mode 100644
index 0000000..f4fe5f8
--- /dev/null
+++ b/docs/USER_GUIDE.md
@@ -0,0 +1,194 @@
+<!--
+ Author: cirakg & claude ai
+ Summary: How to install and use OTP Wallet: the Store beta, adding and importing entries, the PIN, daily use, the glance, moving watches, troubleshooting and known limitations.
+-->
+# OTP Wallet user guide
+
+OTP Wallet keeps one-time passwords (TOTP, HOTP and Steam Guard) and barcodes (loyalty cards, tickets, QR codes) on your Garmin watch, encrypted. Nothing leaves the watch: there is no account, no cloud and no network access. You add entries from the Garmin Connect app on your phone; the watch is the only place they are stored.
+
+## Contents
+
+- [Install](#install)
+- [Where the settings are](#where-the-settings-are)
+- [Add an authenticator code](#add-an-authenticator-code)
+- [Import from Aegis or otpauth links](#import-from-aegis-or-otpauth-links)
+- [Add a barcode or QR code](#add-a-barcode-or-qr-code)
+- [Change, move or delete an entry](#change-move-or-delete-an-entry)
+- [The PIN and locked entries](#the-pin-and-locked-entries)
+- [Daily use on the watch](#daily-use-on-the-watch)
+- [The glance](#the-glance)
+- [Options](#options)
+- [Moving to a new watch, and backups](#moving-to-a-new-watch-and-backups)
+- [Troubleshooting](#troubleshooting)
+- [Known limitations](#known-limitations)
+
+## Install
+
+Garmin's app settings only work for apps installed from the Connect IQ Store, so OTP Wallet is installed as a private beta that only your Garmin account can see:
+
+1. The developer uploads the signed package (`make package` builds `build/package/otp-wallet-<version>.iq`) on Garmin's developer site as a beta app.
+2. On your phone, open the Connect IQ Store app, find the beta under your apps, and install it on your watch.
+3. Each new version is a new upload; the Store updates the watch, and your entries stay (check this once with the [real-watch checklist](TESTING.md#real-watch-checklist)).
+
+A sideloaded build (copied over USB) runs, but gets no phone settings, so you can't add entries to it. Sideloaded debug builds are for testing with fake demo entries only.
+
+## Where the settings are
+
+In the Garmin Connect app: your watch, then **Connect IQ apps**, then **OTP Wallet**, then **Settings**. The settings are a set of forms. Each form has a switch at the bottom ("Add this entry", "Import now", "Apply"); the watch acts on a form only when its switch is on, and only when it receives the settings:
+
+- If OTP Wallet is open on the watch, it applies the forms within seconds of saving.
+- Otherwise it applies them the next time you open it.
+
+Each form has a **Result** field the watch writes back, and the watch shows the same lines on its **Settings results** screen (also in its menu). After a form is applied the watch turns its switch off and clears it, the secret field first. After a problem only the secret field is cleared, so you can correct the rest and send it again. Sending exactly the same form twice does nothing the second time.
+
+Your phone may or may not show the cleared fields and the Result text before you reopen the settings page; that depends on Garmin Connect (see [SETTINGS_SPIKE.md](SETTINGS_SPIKE.md)).
+
+## Add an authenticator code
+
+Use the **Add OTP** form with the details the website shows when you set up two-factor authentication (choose "can't scan the code?" or "enter the key manually" to see them):
+
+| Field | What to enter |
+| --- | --- |
+| Type | TOTP (almost every site), HOTP (counter based) or Steam |
+| Issuer (service) and Account | For example "GitHub" and your user name. At least one of them |
+| Secret | The key in Base32 (letters A–Z and digits 2–7). Spaces, hyphens and lower case are fine |
+| Algorithm, Digits, Period | Leave SHA1, 6 and 30 unless the site says otherwise |
+| Counter | HOTP only: the starting counter, usually 0 |
+| Group | Optional, shown in the list |
+| Require PIN to display | The code is only shown after you enter the app PIN |
+
+Turn on **Add this entry** and save. The result says, for example, "Added K7F2 GitHub (alice)", or exactly what to fix ("Secret: '1' is not a Base32 character (position 5)"). Check that the watch shows the same code as the website or your phone authenticator before you rely on it.
+
+## Import from Aegis or otpauth links
+
+The **Import** form takes the text of an **unencrypted Aegis export** (Aegis: Settings, Import & Export, Export, plain JSON) or any number of `otpauth://` links:
+
+1. Paste the text into **Text, part 1**. If it is longer than one field takes, continue in the next part; the watch joins parts 1 to 8 in order.
+2. Choose the mode: **Add to my entries** (default), or **Replace imported entries** (removes entries that came from earlier imports first; entries you added by hand are never touched).
+3. Turn on **Require PIN for these entries** if they should all be locked.
+4. Turn on **Import now** and save.
+
+The report lists how many entries were imported and every one that wasn't, with the reason: duplicates of entries you already have, unsupported types (mOTP, Yandex), or bad values. Aegis favourites stay favourites (see [the glance](#the-glance)); icons and notes are not imported.
+
+**Long exports.** If the text is still incomplete after joining the fields, the watch keeps what it got (encrypted) and says "Waiting for more: received ... characters". Paste the next part into the fields, turn **Import now** on again, and save. The waiting part expires after 24 hours and is limited to 32 KB; choose the mode **Cancel waiting import** to discard it. A compact export takes about 190 characters per entry; remove icons from the export if it is much larger.
+
+**Afterwards**, delete the exported JSON file from your phone, and keep such files out of cloud-synced folders. The import fields are cleared on the phone by the watch.
+
+**iPhone:** if Garmin Connect refuses the `&` in a link, write `;` instead; the watch accepts both.
+
+Google Authenticator's export links (`otpauth-migration://`) are not supported. Import them into Aegis first and export from there.
+
+## Add a barcode or QR code
+
+Use the **Add code** form:
+
+| Field | What to enter |
+| --- | --- |
+| Card name | For example "Gym card" |
+| Barcode type | QR, Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, ITF, Codabar, Data Matrix, PDF417 or Aztec |
+| Contents | The text or digits the code holds (as printed under the code, or what a scanner app reads from it) |
+| Error correction | 2D codes: Medium is right for most uses |
+| Check digit | EAN, UPC and ITF: "Add or verify" checks the last digit; "Fix if wrong" corrects it |
+| Show the text under the bars | The digits under linear codes |
+| Group, Require PIN to display | As for OTP entries |
+
+The watch encodes the code to check it, and warns if it won't fit your screen at a scannable size. 2D codes are drawn the first time you open them ("Encoding… 40%"); after that they open at once.
+
+## Change, move or delete an entry
+
+Use the **Manage entry** form with the entry's **ID**: four characters such as `K7F2`, shown at the bottom of each entry on the watch, under **Entry IDs** in the watch menu, and in the **About** group of the settings (the catalog). Case doesn't matter.
+
+| Action | Fields used |
+| --- | --- |
+| Edit details | New name, account or group; blank keeps a field, `-` clears it |
+| Move to position | The new position, 1 = top |
+| Require PIN / Don't require PIN | — |
+| Replace secret or contents | The new secret (Base32) or code contents |
+| Set HOTP counter | The counter |
+| Delete | — |
+| Mark as favourite (glance) / Remove favourite | — |
+
+**Changes to locked entries wait for you.** Anything that would change or reveal a locked entry (everything except moving it) is not applied when it arrives. The watch shows "Phone changes: N to confirm" at the top of its menu and in the list title. Open it, check the list, and choose **Confirm all** (it asks for the PIN, even if the app is unlocked) or **Reject all**. This way, someone with access to your phone alone can't unlock or rewrite your locked entries.
+
+## The PIN and locked entries
+
+- **Set PIN** in the watch menu creates it (4 to 10 digits; the watch warns below 6). You are also asked for one the first time an entry needs it.
+- Entering the PIN unlocks all locked entries until the app locks again: when you leave the app, after the auto-lock time (option), or with **Lock now** in the menu.
+- **Wrong PINs:** after 5 wrong PINs the watch makes you wait, longer with each further mistake. With the option **Erase locked entries after 10 wrong PINs**, the tenth wrong PIN erases the locked entries (unlocked entries stay).
+- **Change PIN** keeps your entries. **Reset PIN**, for a forgotten PIN, erases the locked entries and lets you set a new PIN; there is no other way back into them.
+- Locked entries are encrypted with a key that only your PIN opens. A short PIN can still be guessed by someone who copies the watch's storage, so choose 6 or more digits for anything important.
+
+## Daily use on the watch
+
+- **List:** your entries in your order. Unlocked TOTP and HOTP entries show the current code and a small countdown; locked entries show a lock; barcodes show an icon.
+- **Open an entry** (tap it, or START): the code in large digits with a countdown ring; in the last 5 seconds the next code is shown too. For HOTP, tap the code (or START) for the next one.
+- **Barcodes** open black on white, at the largest size that fits. They are shown at full brightness for about a minute on AMOLED watches (the screen's own limit; tap to brighten it again), and with the backlight on MIP watches. You can turn this off under Options.
+- **Menu** (hold MENU, or long-press the list on touch-only watches): Phone changes, Lock now, Set/Change/Reset PIN, Settings results, Entry IDs, Clock status, About (version, storage, self-test result).
+- **BACK** on the list leaves the app and locks everything.
+
+## The glance
+
+In the watch's glance loop, OTP Wallet shows the number of entries. With the option **Show the favourite code in the glance** on, it shows instead the current code of your first **favourite** TOTP or Steam entry that doesn't require the PIN, with a bar for the seconds left:
+
+- Mark an entry as favourite with Manage entry, "Mark as favourite (glance)" (Aegis favourites already are).
+- Locked entries and HOTP entries never appear in the glance.
+- The glance updates the code once you've opened the app after changing your favourites; turning the option off hides the code at once.
+- Anyone who can see your glance loop sees that code, so choose an entry for which that's acceptable ([SECURITY.md](SECURITY.md#glance-code)).
+
+## Options
+
+| Option | Default | Meaning |
+| --- | --- | --- |
+| Lock after | 1 min | How long locked entries stay open without input: immediately, 15 s, 30 s, 1, 2 or 5 minutes |
+| Erase locked entries after 10 wrong PINs | Off | See [the PIN](#the-pin-and-locked-entries) |
+| Time offset in seconds | 0 | Seconds added to the watch clock if your codes are consistently early or late (−120 to 120) |
+| Code size | Large | Size of the digits on the detail screen |
+| Theme | Dark | Dark or light screens (barcodes are always black on white) |
+| Show groups | On | The group in front of the account in the list |
+| Encrypt names on the watch | Off | Keeps names and accounts in the encrypted part too; locked entries then show only "Locked entry" and the About catalog only IDs |
+| Show the favourite code in the glance | Off | See [the glance](#the-glance) |
+| Full brightness while showing a barcode | On | See [daily use](#daily-use-on-the-watch) |
+
+## Moving to a new watch, and backups
+
+OTP Wallet never exports your secrets: they only flow into the watch. Your backup is your authenticator app or Aegis vault (and the recovery codes the websites gave you). To move to a new watch, install OTP Wallet there and import or add your entries again, then delete the app from the old watch (uninstalling removes all its data).
+
+## Troubleshooting
+
+| Problem | What to do |
+| --- | --- |
+| Codes are rejected | Open **Clock status** in the menu. The watch clock must be right to within a few seconds; sync the watch (GPS activity or phone sync). If it is always off by the same amount, set **Time offset** |
+| Nothing happens after saving a form | Open OTP Wallet on the watch; forms are applied when the app runs. Check that the form's switch was on |
+| "Already added" or "Already imported" | The watch has already applied exactly that form; change something to send a new one |
+| "Waiting for more" after an import | The JSON was incomplete: paste the rest and send again, or choose the mode "Cancel waiting import" |
+| "Damaged entry K7F2" | That entry's stored data can't be read. Delete it with Manage entry and add it again |
+| A barcode says "Too large for this screen" | The contents are too long for a scannable code on this watch. Use a shorter text, or a 2D symbology for long text |
+| A barcode doesn't scan | Turn brightness up (the option is on by default), hold the watch steady and flat, and try both closer and further away. Laser scanners at tills often can't read screens |
+| "Data from a newer version" | The app was downgraded; install the newest version again |
+| "Crypto self-test failed" | The watch's crypto didn't give the expected results; codes are hidden to be safe. Update the watch firmware and report it |
+
+## Known limitations
+
+- **Connect IQ limits**
+ - No unlocking with the watch's own passcode; the app has its own PIN.
+ - App settings only work with the Store version, which is why the app is a private beta rather than sideloaded.
+ - The phone may not show what the watch writes back (Result fields, cleared forms, the About catalog) until you reopen the settings.
+- **Import**
+ - Encrypted Aegis exports can't be decrypted on a watch (it would need 32 MiB of memory); export unencrypted.
+ - Google Authenticator export links aren't supported; mOTP and Yandex entries are skipped.
+ - Icons and notes aren't imported.
+ - Pasted text is limited to the eight import fields per sync, and a waiting import to 32 KB.
+- **Storage**
+ - At most 150 entries and about 100 KB in total.
+ - At most 16 phone changes can wait for the PIN at once.
+ - The About catalog shows up to 800 characters; the rest are under Entry IDs on the watch.
+- **Security**
+ - Locked entries are only as strong as the PIN against someone who copies the watch's storage; unlocked entries rely on the watch keeping its storage private.
+ - Secrets and the import text pass through Garmin Connect's settings on your phone.
+ - See [SECURITY.md](SECURITY.md) and [README section 8](../README.md#8-threat-model).
+- **Barcodes**
+ - Data Matrix uses ASCII and Base256 encoding only (no C40, Text, X12 or EDIFACT), and Aztec a simple mode choice. Their symbols are valid, but sometimes larger than another encoder's.
+ - PDF417 only fits short contents on small round screens (about 170 codewords on a 218-pixel screen).
+ - Large 2D codes take a while to encode the first time: seconds for typical cards, up to about a minute for the largest QR codes on the Forerunner 255 and 255S. After that they open from the cache.
+- **Glance:** only the first favourite TOTP or Steam entry without the PIN.
+- **No backup or export** from the watch, by design.