Autheris

autheris.app
Autheris

Open-source 2FA authenticator for iPhone, iPad, Mac and Apple Watch. Secrets stay in the device Keychain, with no account, no analytics and optional iCloud Sync

Open Source

Autheris Source Code

Author

Nerdykidtech

Description

Privacy-first 2FA authenticator for iPhone, iPad, Mac and Apple Watch. TOTP and HOTP codes stored in the Keychain, with no account and no tracking.

#2fa#apple-watch#authenticator#hotp#ios#keychain#macos#otp#privacy#swift#swiftui#topt#two-factor-authentication#watchos

Homepage

https://autheris.app

Repository

  • LicenseMIT
  • Created18 Mar 26
  • Primary languageSwift
  • Size6,205 KB
  • Stars1
  • ForksNone
  • Watchers1

Language Usage

Language Usage

Project Health

  • Last commit7 days ago
  • Open issuesNone

Top Contributors

Recent Commits

  • Hunter Eddington(07 Oct 26)

    3.1 (build 28): reliability for iCloud sync and counter-based codes, new welcome (#9)

  • Hunter Eddington(04 Oct 26)

    3.0 (build 27): fold 2.9 into 3.0 in the release notes (#7) * Fold the 2.9 notes into 3.0's What's New 2.9 was withdrawn from review before release and replaced by 3.0, so nobody gets 2.9's notes on the App Store. 3.0's What's New now carries them after the Add to Autheris notes, in all seven locales. * Fold 2.9 into 3.0 in the changelogs 2.9 was withdrawn from review and never released; 3.0 replaced it in App Store Connect and carries its changes. The in-app catalog and CHANGELOG.md now list them under 3.0, matching the App Store notes, with 2.9's references to itself (the privacy switches turning back on, the larger Transfer QR Code) now naming 3.0. The submitted 3.0 build still shows 2.9 as its own entry; this ships with the next build. * 3.0 (build 27): ship the folded changelog Build 26 is in review with 2.9 as its own changelog entry. Build 27 is the same code with 2.9 folded into 3.0, to replace it.

  • Hunter Eddington(04 Oct 26)

    3.0 (build 26): Add to Autheris (#6) Other apps can now open Autheris with a new code through autheris://add?uri=<otpauth link>. A bare otpauth:// link goes to whichever authenticator iOS picks for the scheme, so a third-party "Add to Autheris" button needs a link only Autheris answers. The route only decodes: it hands the inner otpauth link to the same parser and the same ImportConfirmationView review as every link since 2.8, so nothing is added until the user taps Import, and only once App Lock is passed. Batches (otpauth-migration) are refused inside it. This is a public format that AutherisKit ships, so IncomingLinkTests now decodes the exact link AutherisKit builds; a change that breaks third-party apps fails here. Bumps the version to 3.0 (build 26), with release notes in the changelog, the in-app catalog and the App Store What's New for all seven locales.

  • Hunter Eddington(04 Oct 26)

    2.9 (build 25): security and reliability fixes (#5) * Don't load, save or sync the vault while the Keychain is locked A background launch on a locked phone read every Keychain item as missing, so the store started with an empty list, pushed it to the watch, and the first edit after unlocking saved it over the real vault. KeychainStore.read now tells a missing item from an unreadable one, and OTPDataStore waits until the vault has loaded before it saves, syncs or updates the watch, retrying when the device unlocks or the app becomes active. * Stop the privacy switches turning themselves off persist() read the three privacy switches with bool(forKey:), which reads an untouched switch as false, so they were mirrored into the Keychain as off and restored that way on the next launch. Read every key with its real default instead, and turn the switches back on once when restoring a blob written before this fix, which now carries a schema version. * Detect sync conflicts instead of overwriting newer changes Uploads used savePolicy .changedKeys, which compares no change tags, so a device working from a stale fetch overwrote a newer change and the conflict handling never ran. Uploads are now written onto the records the sync fetched and saved with .ifServerRecordUnchanged, so a conflict comes back with the server's copy and goes through the merge rules as documented. Tombstones used to be written onto a fresh record, where clearing an encrypted field that was never set is not a change, so a deleted code's encrypted details could stay in iCloud. They now start from the fetched record, and each sync also clears any that earlier versions left behind. * Fix code loss, silent adds, App Lock lockout and backup restore - Never drop a code because it shares a name. Saving filtered by label and account, so two codes with one name lost one, and a rename onto another code's name did exactly that. Storage now only drops repeated ids, the list hides only true copies (same name and secret), a rename onto a taken name is refused, and one case-insensitive name rule is used everywhere. - otpauth links with only the account in the path keep it, so a second account at one issuer can be added. 2FAS imports read the account too. - addCode reports a skip, and the scanner, form and link sheet say "Already on this device" instead of closing as if it worked. - Scanned transfer and Google Authenticator export QR codes go through ImportConfirmationView, like links, instead of being added straight away. - App Lock can only be turned on when the device can authenticate, and a lock screen on a device with no passcode unlocks instead of trapping the user, as reauthenticate already did. - Restoring an encrypted backup asks before replacing the vault, like a plain one, and codes a restore replaces go to Recently Deleted. - PBKDF2 for encrypted backups runs off the main actor. * Fix the code review of the 2.9 branch - Never save over codes that are stored but won't decode: the vault stays unloaded instead of starting empty. algorithm now decodes leniently, like kind, so one unknown value can't fail the whole vault. - Only the codes item can hold the vault up. An unreadable tombstones or trash item loads as empty and is never written over. Every edit is refused while the vault is unloaded, HomeView says the codes can't be read, and Add is disabled. - A Keychain read that succeeds without data is unreadable, not missing. - PreferencesStore.persist writes nothing until this process has read the stored copy, and the deferred read runs when the device unlocks, so the privacy repair can't be skipped by a locked first launch. - With no passcode, the lock screen also turns App Lock off. LocalAuthentication sits behind DeviceOwnerAuthenticating so this is tested. - The CloudKit push and tombstone scrub take a CloudRecordSaving, and tests drive the conflict path with a fake database. - Scanned batches go through IncomingLink.scannedBatch and an app-level ReviewImportAction, so they wait behind App Lock like links; HomeView's own overlay is gone. - The import card sets a light colour scheme for itself instead of the window. Cancelling a restore drops the decrypted codes. Copies are filtered in one pass, and reordering keeps hidden copies. - OTPAuthURLView, which nothing used, is deleted. * Report a refused change, and give unreadable codes a way out - addCodes returns nil and replaceAll returns false when the vault hasn't loaded. BackupView, the Settings file import and ImportConfirmationView now say the codes can't be read, instead of "Backup Restored" or "all duplicates". - Codes that are stored but won't decode can be set aside: copied to a timestamped Keychain item of their own, then the vault starts empty so a backup can be restored or iCloud can bring the codes back. HomeView offers it, after a confirmation, only in that case, never for a locked device. - No sync runs while the tombstones can't be read, and a silent push doesn't report new data while the vault is unloaded. - copyKey is a SHA-256 hash, so it doesn't carry the secret as text. - hasReadStoredPreferences is private(set) with a debug-only reset, and the tests that write the preferences item stop the host app's mirror. - Each window has its own id, and only the window an import or link arrived in shows its review or error. - The AddTokenView preview sets its own review action. * Keep the watch's codes on Start Over, and tidy the unavailable paths - Setting unreadable codes aside no longer sends Apple Watch an empty list: the watch's copy may be the only one the user can still read. The next real change updates it. The confirmation says so. - Unreadable codes are set aside under one Keychain account, otpCodes.unreadable, so repeated set-asides replace each other instead of piling up secrets nothing lists. docs/security.md describes it. - addCodes returns an ImportOutcome enum instead of an optional tuple. - The "can't read your codes" message is defined once, on OTPDataStore, and ImportConfirmationView's three result views share one card layout. - A link that can't be read shows its error in its own window without moving a review that is waiting in another. * Keep the watch option and test-only controls out of the public API - saveCodes() always updates the watch again. Skipping that, which only a start-over has a reason to do, is a private persistCodes(offerToWatch:). - isMirroringChanges and stopMirroringChanges(), used only by tests, are debug-only next to forgetStoredPreferencesWereRead(), and startMirroringChanges() has its doc comment back. * Fit far more codes in the Transfer QR Code The transfer QR held the full JSON export, about 430 bytes a code, so it gave up at the 9th code. TransferPayload adds a compact format (v=2 in the link): label, account, the secret as raw bytes, only settings that aren't the default, no ids or dates (import assigns its own), compressed. That's about 55 bytes a code, typically 50 to 130 codes per QR. The old format is still used whenever it fits, so a device on an older version can import a small transfer. A secret that isn't canonical Base32 travels as text, so every code arrives exactly as it left. Decoding checks every length against what's left and caps inflation. The transfer sheet now says whether the codes can't be read or don't fit, instead of a generic error. * Build the transfer link once, test capacity with real secrets, document it - Settings builds the transfer link when the sheet opens instead of on every redraw, and drops it when the sheet closes: it encodes and compresses the whole vault, and holds every secret. - The capacity tests use seeded random secrets and realistic email addresses. Patterned secrets compress far better than real ones and made the 50-code test easier to pass than any real vault. - docs/security.md describes the transfer QR code: both formats, that they hold every secret unencrypted, and how a compact payload is decoded as untrusted input. * Say in the security docs that Share sends the transfer QR out of the app The paragraph covered someone seeing or photographing the screen, but not the Share QR Code button, which saves or sends the image to Messages, Photos (and iCloud Photos), AirDrop or Files, where it stays unencrypted. * Stop the transfer sheet flashing "too large" as it opens The sheet was presented from a flag set in the same step as the link, and SwiftUI could draw its first frame before the link reached it. With no link, the sheet showed its fallback, "too large for a single QR code", until the next frame. It's now presented from the link itself with sheet(item:), so it can't appear without it. SwiftUI clears the item on dismiss, which still drops the link. * 2.9 (build 25) - Security and reliability fixes Releases this round of review fixes as 2.9, since 2.8 has shipped: the version bump, the in-app changelog, CHANGELOG.md, and a 2.9 App Store listing whose What's New covers them in every locale. * Split two view bodies that were too big for CI's compiler CI's Xcode 26.6 failed with "unable to type-check this expression in reasonable time" on SettingsView's body, which the alerts and sheets added for 2.9 had grown into one long modifier chain. It is now four properties in the same modifier order. AutherisApp's body had grown the same way (387 ms to type-check here, against 299 ms on main), so each window's contents move into window(_:), now 132 ms. Nothing changes what either screen does. * Keep CI's test results when the tests fail Eight tests crash the test runner on CI's Xcode 26.6 and iOS 26 simulator but pass locally, and a crash leaves no message in the filtered log. The result bundle holds the crash report and backtrace. * Run the tests that drop their own store or lock manager as async On CI (Xcode 26.6, iOS 26 simulator) releasing a main-actor object inside a synchronous test method aborts in swift_task_deinitOnExecutor: the runtime frees a task-local scope it never allocated. The crash reports from the result bundle show it in AppLockManager's deinit, called from testAnyOtherReasonKeepsTheLockAndSaysWhy. Inside a task the same release takes a different path. Xcode 27's XCTest doesn't hit it, on iOS 26.5 or 27.

  • Hunter Eddington(03 Oct 26)

    Bring docs/security.md up to date with 2.8 Adds sections for App Lock (grace period, the Mac Settings window, and re-authentication before sensitive actions), copied codes, backups (encryption envelope v2, file protection and exclusion from device backups, restore stamping), imports (confirmation, fresh ids and timestamps) and the Apple Watch relay. Removes the claim that backups are plain JSON with only sandbox protection, the duplicate "Security" heading and list, and fixes the front-page link, whose anchor changed with the README refresh. The README no longer says 2FAS counter-based entries are imported; they are skipped.

  • Hunter Eddington(03 Oct 26)

    Refresh the README A centred header with the icon, a one-line pitch, flat badges (including build status and license) and quick links. Features are grouped into codes, privacy and security, and platforms, and now cover 2.8: re-authentication for sensitive actions, stronger encrypted backups kept out of device backups. The security section becomes a table with a private vulnerability reporting link. Also drops statements that had gone stale: backups described as not encrypted, the Cloudflare Workers history note, "MVVM with Combine", "Swift 5.9+", and screenshot captions describing a counter-based code and countdown rings the images don't show.

  • Hunter Eddington(03 Oct 26)

    2.8 (build 24) - Add the code review fixes to 2.8 2.8 had not cleared review yet, so it is resubmitted with build 24 instead of shipping these as 2.9. The release notes in the app, CHANGELOG.md and the App Store listing now cover the import-link advisory together with the Mac App Lock fixes, re-authentication for sensitive actions, the backup, restore and sync fixes, and the import count fix.

  • Hunter Eddington(03 Oct 26)

    Turn on complete strict concurrency checking Every target is still Swift 5 with main-actor default isolation, but the concurrency checks were never enforced, so races only showed up in review. SWIFT_STRICT_CONCURRENCY is now complete for the app, tests and watch, and everything it reported is fixed: - LogoCacheManager wrote the logo cache from URLSession's queue. The write and the completion now hop to the main actor together. - The camera-permission and logo completions are @MainActor closures. - Pure parsers (OTPAuthURLParser, GoogleMigrationParser, WatchRelayStaging) and PlatformImage.from(cgImage:) are nonisolated. - The watch decodes an application context in the WCSession callback, so only the Sendable result crosses to the main actor. The relay re-activates its own session instead of capturing the callback's. - The preferences mirror observer asserts it is on the main actor, and the Mac AppLockManager's observers are readable from deinit. - Vision is imported @preconcurrency; its request and handler are only used on the one queue that performs them. - Test classes that exercise main-actor types are @MainActor.

  • Hunter Eddington(03 Oct 26)

    Drive every card from one TimelineView instead of a timer each Each OTPCardView published its own one-second Timer, and HomeView kept another whose empty onReceive only forced the whole screen to redraw. The list now has a single TimelineView ticking on whole seconds and hands its date down to the cards. Each card derives its remaining seconds and code from that date, via the new OTPCode.code(at:), so it no longer needs a timer or countdown state of its own.

  • Hunter Eddington(03 Oct 26)

    Test the watch relay's staged file handling Moves writing and pruning the staged payload into WatchRelayStaging, so they can be tested without a paired watch, and covers: the file's protection class, a new file per send, pruning finished transfers while keeping ones in flight (including a differently spelled in-flight URL), and pruning nothing while the transfers in flight are unknown. The protection check skips on the simulator, which records no protection class for any file; it runs on a device.

  • Hunter Eddington(03 Oct 26)

    Protect the watch relay's staged token file A token list too large for an application context is written as plaintext JSON to tmp/WatchRelay for transferFile. It used the default protection class, readable whenever the phone has been unlocked once since boot, and was only cleaned up at the next large transfer. It is now written with completeFileProtectionUnlessOpen. Not complete: transferFile reads in the background, and a transfer that has already opened the file has to be able to finish if the phone locks. Finished transfers are also pruned on every foreground, and pruning is skipped until the session is activated, when outstandingFileTransfers would make every staged file look finished.

  • Hunter Eddington(03 Oct 26)

    Sync, backup and security fixes from the code review (#4) * Stop sync from undoing deletions made on other devices When a merge adopted a remote tombstone, apply() put the deleted token straight back because it was still in the local list, so a deletion on one device never removed the token from another. It also replaced tombstones wholesale, losing any deletion made while the sync was in flight. apply() now only carries over tokens added after the sync snapshot, keeps tombstones written mid-sync, and drops tombstones cleared mid-sync (a re-add or a restore from Recently Deleted). Adds the first tests that drive OTPDataStore through a fake TokenSyncService. * Note the sync deletion fix in the changelog * Keep backup files out of device backups createBackup() wrote every secret as plain JSON to Documents/OTPBackups with no file protection, and Documents is copied into iCloud Backup and Finder backups. That got around the ThisDeviceOnly Keychain protection the codes themselves have. Encrypted .autheris backups had the same gap. Backups are now written with complete file protection and excluded from device backups, and the folder plus any backups written by earlier versions get the same treatment at launch. They stay in the folder so the in-app backup list keeps working. * Remove unused import and logo helpers importData(from:) had no callers and skipped the duplicate and tombstone checks addCode does, so calling it would have been a bug. Also drops the TokensImported notification nobody observed, and the unused logoURLByDomain, handleNewTokenAddition and handleTokenUpdate. * Read a backup picked from Files before its access is released handleFileImport opened the file's security scope, deferred closing it, and only showed the restore alert. The actual read happened when the user tapped Restore, after the scope had closed, so restoring from Files or iCloud Drive (and in the Mac sandbox) could fail and report "Incorrect password or corrupted backup". The backup is now read as soon as it is picked and held until the restore is confirmed, and restoreFromBackup takes the bytes instead of a URL. A file that can't be read says so instead of blaming the password. * Strengthen encrypted backup key derivation .autheris files are made to be shared, so they can be attacked offline, but the key came from 120,000 rounds of PBKDF2-HMAC-SHA256 and any non-empty password was accepted. New backups use envelope version 2, which records its iteration count and is written with 600,000 (OWASP's current figure). Version 1 files still decrypt at 120,000. The stored count is bounds-checked so a forged file can neither skip the work nor hang the app. Key derivation now uses CommonCrypto's CCKeyDerivationPBKDF instead of the hand-written loop, and new encrypted backups need a password of at least 10 characters. Includes a version 1 file written by the old code, to prove existing backups still open. * Keep tokens restored from a backup from being deleted again by sync A backup restore put tokens back with the modifiedAt they had when the backup was made. If one had been deleted since, the tombstone that delete left in iCloud was newer, so the next sync deleted it again. Restoring from Recently Deleted already stamps the token as edited now; a backup restore now does the same. * Confirm a backup restore instead of closing Backup & Restore A successful restore dismissed the sheet straight back to Settings with no sign that anything had happened. It now shows a "Backup Restored" alert and leaves the sheet open. * Ask for Face ID again before sensitive actions With App Lock on, the 30-second grace period means a phone unlocked moments ago opens straight into Autheris, and from there App Lock could be turned off, every secret exported by QR code or backup, or a setup key shown, with no further check. Adds AppLockManager.reauthenticate(reason:) and requires it for turning App Lock off, opening Backup, opening QR transfer, and View Secret. It is a no-op while App Lock is off, and on a device with no passcode. * Import codes through one store method that reports what it added Settings, the import-link sheet and the QR scanner each filtered by label and account and then called addCode, which also quietly skips a code whose id is already in use. Those skipped codes were still counted as added. They now all call OTPDataStore.addCodes(_:), which returns how many were added and skipped. Each imported code gets a new UUID and a fresh modifiedAt, so a payload can neither collide with an existing id nor carry a future timestamp that wins every sync conflict. IncomingLink.newTokens had no callers left and is removed. * Run one more sync when an edit lands mid-sync The CloudKit service refuses to start a sync while one is running, so an edit made during a sync scheduled a performSync that got nil back and gave up. The edit wasn't uploaded until the next foreground or push. OTPDataStore now runs one sync at a time itself: a sync requested while one is in flight sets needsResync, and one more sync runs as soon as the current one finishes. It is driven from the store rather than the service so the follow-up takes a fresh snapshot that includes the edit. The test fake now refuses overlapping syncs the way the real service does.

  • Hunter Eddington(03 Oct 26)

    Mac App Lock fixes and app state observer cleanup (#3) * Require App Lock to open the Mac Settings window App Lock only gated the main WindowGroup. The Settings scene is a separate window, so on a locked Mac pressing Command-comma opened preferences with QR transfer (every secret), unencrypted backups and the App Lock toggle itself. Settings now shows the lock screen while the app is locked, and its window follows the screen-capture exclusion like the main window does. * Note the Mac Settings App Lock fix in the changelog * Stop adding app state observers every time a window appears setupAppStateObservers() ran from the root view's onAppear and kept no tokens, so every new window on iPad and Mac added five more observers that were never removed. The UserDefaults one wrote the preferences to the Keychain once per observer for every defaults change. The four activation observers and the screen capture one are now onReceive modifiers, which end with the window. The preferences mirror moved to PreferencesStore.startMirroringChanges(), which installs its observer only once. * Re-lock the Mac app after switching away for 30 seconds App Lock's grace period started only on scenePhase == .background, which a Mac window reaches by being minimised or the app being hidden, not by another app taking focus. Switching away and back therefore never re-locked, despite the Privacy settings footer saying it would. AppLockManager now observes the app resigning and regaining active on the Mac, independent of which windows are open.

  • Hunter Eddington(03 Oct 26)

    Add PR build and test checks (#2) * Add PR build and test checks * Ad-hoc sign CI builds so CloudKit entitlements survive

  • Hunter Eddington(02 Oct 26)

    Run security audit monthly instead of daily

  • Hunter Eddington(02 Oct 26)

    Fix daily audit advisory creation Use the ADVISORY_TOKEN PAT since GITHUB_TOKEN can't create repository advisories, include the required vulnerabilities field, fail the job when the API rejects the request, and skip creating an advisory when no issues are found.

  • Hunter Eddington(02 Oct 26)

    2.8 - Confirm imports from links (GHSA-75h3-q43q-9338) Bumps the version to 2.8 (build 23) with release notes in the app, CHANGELOG.md and the App Store listing. Reported-by: NotAFlightRisk <https://github.com/NotAFlightRisk>

  • Hunter Eddington(02 Oct 26)

    Require confirmation and an unlocked app before importing from links autheris://import, otpauth:// and otpauth-migration:// links added codes to the vault the moment they arrived, without showing the Import/Cancel screen and while App Lock was engaged, so another app or a web page could plant entries. All three now parse through IncomingLink, which never writes to the vault; ImportConfirmationView shows exactly what would be added and imports only on Import. A link that arrives while the app is locked or before onboarding is finished waits until it is unlocked. Fixes GHSA-75h3-q43q-9338. Reported-by: NotAFlightRisk <https://github.com/NotAFlightRisk>

  • Hunter Eddington(02 Oct 26)

    Accept plain Aegis exports with a null slots/params header Aegis writes an unencrypted export with "header": {"slots": null, "params": null}, which the parser read as encrypted, so every real plain export was refused. A header whose values are all null now counts as plain; one with slots/params filled in is still refused.

  • Hunter Eddington(02 Oct 26)

    Make issuer colours and logo cache keys stable across launches Both came from Swift's hashValue, which is randomly seeded per launch: a service without a brand colour changed colour every start, and the logo cache key never matched the previous launch's, so every logo was re-fetched from logo.dev and old PNGs piled up. The fallback colour now uses 32-bit FNV-1a over the UTF-8 label, the same function Android uses, so both platforms agree. The cache key drops the hash (name_<company>), as on Android, and the old hash-suffixed files are renamed once on first access.

  • Hunter Eddington(02 Oct 26)

    Refactor report generation in run_opus_audit.py Updated report handling to safely gather text blocks and provide a default message if none are found.

  • Hunter Eddington(02 Oct 26)

    Add daily security audit workflow for iOS

  • Hunter Eddington(02 Oct 26)

    Add script for iOS security and privacy audit

  • Hunter Eddington(02 Oct 26)

    Revise security issue reporting instructions Updated contact information for reporting security issues to use GitHub's vulnerability report form and clarified the process.

  • Hunter Eddington(02 Oct 26)

    Add contact section for vulnerability reporting Added contact information for reporting security vulnerabilities, including details on what to include in the report.

  • Hunter Eddington(02 Oct 26)

    2.7 - New Screenshots

  • Hunter Eddington(30 Sept 26)

    Split the README: an app-facing front page, and the engineering in docs/ The README had grown to 717 lines, roughly 560 of them internals — the CloudKit schema, the localisation tooling, the release runbooks — sitting immediately behind a thirty-line landing page. Someone arriving from the App Store listing met CloudKit field types before they met what the app does. The front page is now 129 lines and answers two questions: what Autheris is, and how it keeps your codes safe. Security is rewritten in those terms rather than in its implementation — where the tokens live, what iCloud Sync sends, what the privacy screen covers, and the one request the app can make — with the mechanics one link away. The features list, screenshots, installation and download are unchanged. Nothing was rewritten or dropped in the move. The engineering sections were relocated verbatim into `docs/`, re-levelled one heading deeper so the hierarchy still reads, and every internal cross-reference was rewritten to its new home: a check across all 57 headings in the six files reports no broken references.

  • Hunter Eddington(30 Sept 26)

    Untrack the local tooling, and drop the assistant framing from the README Assistant configuration had been committed: 79 files of skills, agent definitions, IDE glue, and — the worst of it — session transcripts under `.reasonix/tasks/`, whose directory names carry the model that produced them. None of it is part of Autheris, and a clone was receiving one developer's setup with it. Untracked and ignored rather than deleted: the files stay in the working copy, so the tooling that reads them carries on working, and `git rm --cached` leaves that reversible. Also ignored are `Vaultic/CLAUDE.md` and `Vaultic/.mcp.json`, which stay on disk and stay excluded from the app target's membership — a synchronized folder copies every non-Swift file into the bundle, so that exclusion is what keeps them out of the shipped app, and it is why their names survive in `project.pbxproj` and in the bundle test that guards it. The README keeps the lesson from that corner — the scaffold whose `.dev.vars` shipped for several releases, and the three ways the exclusion list can be undone — without narrating whose guide said what.

  • Hunter Eddington(30 Sept 26)

    Ship 2.6: counter-based codes, done properly The listing has claimed HOTP support since 2.4. It was not true. `OTPAuthURLParser` never read the URL's *host*, so an `otpauth://hotp/` QR code was saved as a time-based token whose codes the service always rejected — silently, with nothing on screen to explain it — and both importers skipped HOTP entries outright. Reading the host is the whole fix; the rest of this release is what falls out of making the claim true. - `OTPKind` and `OTPCode.counter`, threaded through generation, sync (two new plain CloudKit fields, fingerprint `v3`), backups, QR export, imports, and the watch payload (`version 2`: a v1 watch must refuse a payload it cannot honour rather than render a counter-based token as a time-based one). - The card shows the counter where the countdown would be, with a **Next** button beside it. Advancing is explicit and never a side effect of copying, because a copy is not proof the service accepted the code and a spent counter takes away a code the user may still need to retype. - Three copies of the URL parsing became one. The duplicates had already drifted, and that drift is precisely what made the claim false. Also in this release: - A setup *link* can be pasted into the manual form, which used to reject one as "please enter a valid Base32 secret key" — a URL is not Base32, and on a Mac a link is often the only thing there is to copy. - The import-failure messages are translated. They were bare literals, a shape neither the extractor nor the localization coverage test can see. - `Vaultic/PrivacyInfo.xcprivacy`, the manifest the app never shipped, and the issuer-logo lookup is now a switch in Settings → Privacy. The README states plainly what that one network request discloses — the *codes* never leave the device, the list of services does unless it is turned off. - 43 new tests. The URL parser, both importers and the generator's HOTP/RFC 4226 vectors now pin the cases that used to fail quietly. And the repository's front page: the screenshots it has carried since 2.2 but never shown, iPhone and iPad ones produced from the real app, a collapsible table of contents for a 700-line README, and the `LICENSE` file the README has linked to since it was written.

  • Hunter Eddington(29 Sept 26)

    Document the iOS release path, and the four steps in it that fail quietly Releasing 2.5 meant rebuilding the iOS release path from scratch, because only the Mac one was written down. The archive, the export and the upload are all ordinary, but four of the steps mislead when they go wrong, and each cost real time to work out: - `asc release stage --metadata-dir` wants the metadata *root*; it resolves `version/<version>/` itself. Given a version directory it fails in `apply_metadata` — after `ensure_version` has already created the version — and leaves a checkpoint whose `metadataDir` matches nothing, so every later run stops on "checkpoint does not match current run arguments" instead. - A freshly uploaded build is refused a review submission until its export answer is set (`usesNonExemptEncryption`). It is a compliance position, not a build detail, so it belongs read from the previous build rather than answered fresh. - `asc xcode version view` cannot read this project at all: it reports an empty version with `modern: false`, because `MARKETING_VERSION` is per build configuration. The six settings get edited directly, and the built app is what confirms them. - `asc metadata push` has to be previewed. A release that only adds What's New should plan adds and nothing else; a `changes` or `deletes` entry means the local listing has drifted from the live one, and it is the only place that shows up before it is applied. `ExportOptions-iOS.plist` is new because the `ExportOptions.plist` already in the repository is the Mac one — same method, but it exports a `.pkg`, since which artifact comes out is decided by the archive's platform. Both files now say so.

Autheris Website

Website

Autheris — 2FA Authenticator for iPhone, iPad, Mac & Apple Watch

Free, open-source 2FA authenticator app for iPhone, iPad, Mac and Apple Watch. Codes stay in your Keychain. No account, no tracking, works offline.

Redirects

Does not redirect

Security Checks

2 security checks failed (63 passed)

  • Domain Recently Created
  • Domain Very Recently Created

Server Details

  • IP Address104.21.53.143
  • LocationSan Francisco,California,United States of America,NA
  • ISPCloudFlare Inc.
  • ASNAS13335

Associated Countries

  • USUS

Safety Score

Website marked as safe

100%

Blacklist Check

autheris.app was found on 0 blacklists

  • AntiSocial Blacklist
  • Artists Against 419
  • Badbitcoin
  • Bambenek Consulting
  • CERT Polska
  • CoinBlockerLists
  • CRDF
  • CryptoScamDB
  • EtherAddressLookup
  • EtherScamDB
  • Fake Website Buster
  • MetaMask EthPhishing
  • NABP Not Recommended Sites
  • OpenPhish
  • PetScams
  • PhishFeed
  • PhishFort
  • Phishing.Database
  • PhishStats
  • PhishTank
  • Phishunt
  • RPiList Not Serious
  • Scam.Directory
  • SecureReload Phishing List
  • Spam404
  • StopGunScams
  • Suspicious Hosting IP
  • ThreatFox
  • ThreatLog
  • TweetFeed
  • URLhaus
  • ViriBack C2 Tracker

Website Preview

Website preview

Autheris iOS App

App Info

2FA Authenticator - Autheris

Secure your accounts with Autheris — a privacy-first two-factor authentication (2FA) app for iPhone, iPad, Mac and Apple Watch. Autheris generates the time-based one-time passwords (TOTP) that protect your most important accounts, and keeps the secrets behind them on your device. No account, no sign-up, no ads. NOW ON APPLE WATCH • One Code at a Time — Your codes on your wrist, each with a live countdown. Turn the Digital Crown to move between them. • Read-Only by Design — There is no copy, no editing and no settings on the watch. Your iPhone stays the one place codes are managed. • Works Without Your iPhone — Codes are generated on the watch itself, so they keep counting down with your phone out of reach or switched off. KEY FEATURES • One-Tap Codes — Copy a code with a single tap. The clipboard clears itself after 60 seconds. • Pin and Reorder — Pin the codes you use most to the top, and drag the rest into whatever order suits you. • Recently Deleted — Delete a code by mistake? It stays on your device for 7 days, ready to restore. • QR Scanning — Add an account by scanning a QR code, or choose a screenshot from your photo library. • Time-Based and Counter-Based Codes — TOTP for almost every service, and HOTP for the ones that hand you a counter instead, each with SHA-1, SHA-256 or SHA-512 and 6 to 10 digits. If a service rejects your codes, the algorithm is editable per account. • Import — Bring your token generator accounts across from Google Authenticator, Aegis, andOTP or 2FAS. • Search — Find any account instantly, however long your list gets. • Issuer Icons — Familiar brand marks so you can spot an account at a glance. • Countdown Ring — A clear, colour-customisable ring shows how long each verification code has left. PRIVACY AND SECURITY • Face ID / Touch ID Lock — Locks when opened, and again after 30 seconds away. • Blurred When Backgrounded — Content blurs when you switch apps, and your codes are hidden in the app switcher. • Protected While Recording — Codes are covered whenever your screen is being recorded or mirrored. • Secrets Stay on Your Device — Codes and setup keys are kept in your device's Keychain and never leave it unless you export them or turn on iCloud Sync. • Encrypted Backups — Save an AES-256-GCM encrypted backup protected by a password only you know. • Optional iCloud Sync — Off by default. When you enable it, your secrets are end-to-end encrypted by CloudKit, and the developer cannot read them. • No Account, No Tracking — Nothing to sign up for, no analytics, no advertising. Autheris is open source. Install Autheris, add an account, and keep your second factor — and your 2-step login — under your own control.

Rating

Rated 5 out of 5 stars by 1 users

Version Info

  • Current Version3.0
  • Last Updated04 Oct 26
  • First Released20 Mar 26
  • Minimum iOS Version26.0
  • Device Models Supported132

App Details

  • IPA Size2.74 Mb
  • PriceFree (USD)
  • Age Advisory4+
  • Supported Languages7
  • DeveloperHunter Eddington
  • Bundle IDcom.eddingtontech.autheris

Screenshots

  • App screenshot
  • App screenshot
  • App screenshot
  • App screenshot
  • App screenshot
  • App screenshot

Autheris Reviews

More 2-Factor Authentication

About the Data: Autheris

Change History

Edit Autheris Data

You can edit Autheris's entry in this section of awesome-privacy.yml by submitting a PR to our GitHub repo.
Note that some of the information shown above has been aggregated from external sources, a list of these can be found data documentation.

Origin Data

Modify Data

API

You can access Autheris's data programmatically via our API. Simply make a GET request to:

https://api.awesome-privacy.xyz/v1/services/autheris

The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.

Share Autheris

Help your friends compare 2-Factor Authentication, and pick privacy-respecting software and services.
Share Autheris and Awesome Privacy with your network!