Self-hosted service
Bubka/2FAuth avatar
Bubka/2FAuth

2FAuth: a self-hosted web app for TOTP and HOTP codes

A Web app to manage your Two-Factor Authentication (2FA) accounts and generate their security codes

4,171 stars302 forksPHPAGPL-3.0

At a glance

What is it?
2FAuth stores your two-factor accounts in a database you control and serves the codes through a browser, on any device. It is a Laravel and Vue application under AGPL-3.0, and the trade-off is that you now own the server and the backups.
Who is it for?
Adopt 2FAuth if you already run a server and want your OTP seeds in a database you can back up, and if you accept that a lost APP_KEY with encryption on means lost accounts. Skip it if you want a phone-only authenticator with no server to maintain, or if you need a project that is actively developed beyond the last push on 2026-09-02.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem 2FAuth solves, and who it is aimed at

The README is unusually direct about the motivation. The author lists four reasons for building it: most OTP apps show every account at once with countdowns, the accounts should live in a standalone database that can be backed up and restored, taking out a phone to read a code while sitting at a desktop is annoying, and self-hosting is a preference in itself. The smartphone-loss scenario is named explicitly.

That set of complaints defines the audience. 2FAuth is for someone who already has a server, is comfortable with Docker or a PHP deployment, and wants the OTP secrets to live somewhere they can copy, snapshot and restore. It is not a consumer app store product. The README describes it as a web based self-hosted alternative to OTP generators like Google Authenticator, designed for both mobile and desktop, and the interface is a browser page rather than a native client.

There is a second audience worth naming: households or small teams. Since version 4.0 the app supports multiple user accounts, and the README says you can allow public registration, restrict it by email domain, turn registration off, or limit it to SSO only. That is a different product shape from a single-user vault, and it changes what you have to think about when you deploy.

How the codes are generated and where the secrets sit

The generation layer is not homegrown. The README states that 2FAuth produces OTPs according to RFC 4226 for HOTP and RFC 6238 for TOTP using the Spomky-Labs/OTPHP PHP library, and that it also generates Steam Guard codes. So the algorithm side is a PHP library call, and the interesting engineering is in storage, import and the UI.

The application is a Laravel backend with a Vue 3 front end built by Vite. The repository layout confirms this: app/, routes/, config/, database/ and artisan on the server side, resources/ with vite.config.js and tsconfig.json on the client side. The package.json shows Vue 3.5, Pinia for state, vue-router, vue-i18n, axios, and vue-qrcode-reader for scanning. One detail stands out for anyone building from source: the @2fauth/ui, @2fauth/styles, @2fauth/stores and @2fauth/formcontrols dependencies are declared as file:../2FAuth-Components/packages/... paths, meaning the front end expects a sibling checkout of a separate components repository. A plain npm install against the repository alone will not resolve those.

On storage, the .env.example is explicit that APP_KEY is the encryption key for the database and sessions, that it must be kept secure, and that a new key can be generated while moving the former one to APP_PREVIOUS_KEYS so existing data can still be decrypted. Encryption of sensitive data is described in the README as an option that is disabled by default, and it is strongly recommended to back up APP_KEY when it is on. That is the whole security model in one sentence: the database may be encrypted, and the key is the single point of failure.

Installing 2FAuth with Docker and adding a first account

The README does not inline install commands. It links to four guides on docs.2fauth.app: self-hosted server, Docker CLI, Docker Compose and Heroku. The Dockerfile in the repository shows what the container builds: PHP 8.4 on Alpine 3.24, Composer 2.9, supervisord from qmcgaw/binpot, and PHP extensions for SQLite, MySQL/MariaDB and Postgres. The requirements section states PHP ^8.4, the Laravel server requirements, and any database supported by Laravel. Follow the Compose guide for the exact image tag and port; they are not reproduced in the README and I will not guess them.

What the repository does give you is the environment file. Copy .env.example to .env and set at minimum the app URL and a key. The artisan installer mentioned in the comments will generate the key for you:

bash
cp .env.example .env
php artisan 2fauth:install

The comments in .env.example say you can leave APP_KEY empty if you use php artisan 2fauth:install or php artisan key:generate, and that the wizards will set it. If you set it by hand instead, it must be a string of exactly 32 characters. The same file carries a warning that APP_URL must match the installation's external address, otherwise Webauthn will not work.

bash
APP_NAME=2FAuth
APP_ENV=production
APP_URL=https://2fa.example.com
APP_KEY=

With the app reachable, the flow the README describes is: create a user account and authenticate, then add accounts either by scanning and decoding a QR code or through an advanced form for entries with no QR code. Groups organize them. Codes are generated on demand. If you are migrating rather than starting fresh, the import guide covers 2FAuth JSON, Google Auth QR codes, Aegis JSON and plain text, and 2FAS JSON.

Where 2FAuth is the wrong tool

The most obvious limitation is operational, and the README's own framing points at it. Moving your 2FA accounts out of a phone and into a server means the server is now part of your login path. If it is down, unreachable, or you are offline, you have no codes. A phone app has no such dependency. Self-hosting buys you a backup story and pays for it with an availability story.

The encryption option is the second sharp edge. It is off by default, so a database compromise on a default install exposes whatever is in the tables. Turn it on and the README says to back up APP_KEY, and .env.example explains that rotating the key requires keeping the old one in APP_PREVIOUS_KEYS so existing data can still be decrypted. Lose the key without that fallback and the accounts are gone. This is a real failure mode, not a theoretical one, and it is the kind of thing that only bites after a restore.

Third, this is a browser application. There is no native mobile client in the repository, and no Android or iOS project directory. If your requirement is an app icon on a phone home screen that works without a network round trip to your own server, 2FAuth is not that. The README positions it as designed for mobile and desktop, which means a responsive web page, not an installed app.

Finally, the front-end build depends on a sibling components repository, as noted above. That matters if you intend to build from source rather than run the published container.

How 2FAuth differs from Authentik and from phone-based generators

The comparison people search for is 2FAuth against Authentik, and the difference is categorical rather than a matter of features. Authentik is an identity provider: it authenticates users into other applications, issues sessions, and enforces policy at the point of login. 2FAuth does none of that. It is a generator and a vault. It stores your existing 2FA accounts and shows you the six-digit codes so you can type them into whatever service is asking. Nothing in the README claims it can act as an OIDC or SAML provider, and the multi-user support is about who may log in to 2FAuth itself, not about federating your other services.

So the right question is not which one is better. If you want single sign-on across self-hosted apps, 2FAuth is not in that category. If you want a place to keep the TOTP seeds for accounts that already exist elsewhere, Authentik's role is different and the overlap is small.

Against Google Authenticator and similar phone apps, the difference is ownership and interface. The README's author explicitly wanted accounts in a standalone database that can be backed up and restored, and did not want to reach for a phone while at a desktop. The cost is that you maintain PHP, a database and a web server, and you take on the key-management problem described above. A phone app has no server to patch.

Maintenance, upgrades and what AGPL-3.0 means here

The last push to the default branch was on 2026-09-02, and the most recent release listed is v8.0.2 on the same day, following v8.0.1 on 2026-07-05 and v8.0.0 on 2026-07-01. The repository is not archived. Releases arrive in bursts rather than on a fixed cadence, and the README points contributors at a dev branch for pull requests, which tells you the workflow but not the schedule.

Upgrades are documented separately from installation: the README links to an upgrade guide on docs.2fauth.app rather than describing steps inline. Given that the app is a Laravel application with migrations in database/, you should expect the usual sequence of pulling the new code or image, running composer or the container build, and applying migrations. The README does not document rollback, and .env.example does not describe a downgrade path, so treat a major version bump as something to test against a copy of your database first.

On licensing: 2FAuth is AGPL-3.0. The practical consequence for most readers is that running it privately on your own server is unremarkable, but if you modify it and let other people interact with it over a network, the AGPL's source-disclosure terms are the part to read. That is a description of the licence family, not legal advice; if you plan to offer it as a service, talk to someone qualified. One repository detail is worth flagging for anyone building a distribution: the front-end packages are pulled from a sibling path rather than a registry, which is a packaging choice you would inherit.

Editorial conclusion

Adopt 2FAuth if you already run a server and want your OTP seeds in a database you can back up, and if you accept that a lost APP_KEY with encryption on means lost accounts. Skip it if you want a phone-only authenticator with no server to maintain, or if you need a project that is actively developed beyond the last push on 2026-09-02. Before importing anything real, verify three things: that APP_URL matches the external address you will actually browse to, because the README states Webauthn will not work otherwise; that you have a copy of APP_KEY outside the server; and that your chosen database driver is one Laravel supports, since the requirements point at Laravel's list rather than naming engines itself.

Frequently asked questions

How do I set up my 2FA authenticator with 2FAuth?

The README does not inline setup commands; it links to separate self-hosted server, Docker CLI, Docker Compose and Heroku guides on docs.2fauth.app. Once the app is reachable you create a user account, then add accounts by scanning a QR code or through the advanced form for entries without one.

Is the 2FAuth authenticator app safe?

2FAuth provides several security mechanisms, including a required user account, optional sign-in with a security key such as a Yubikey or Titan key, and optional encryption of sensitive data in the database. Encryption is disabled by default, and the README strongly recommends backing up APP_KEY when it is on.

Is there a free 2FA authenticator available?

2FAuth is free software released under AGPL-3.0, and the README points to a public demo at demo.2fauth.app with the credentials [email protected] and demo. You supply the server and the database it runs on.

Do I really need two-factor authentication for my 2FAuth accounts?

The README does not argue the general case for 2FA; it treats it as a given and focuses on where the secrets are stored. 2FAuth itself requires you to create a user account and authenticate before you can reach the stored accounts, and you can sign in with a security key and disable the traditional login form.

What is the difference between 2FAuth and Authentik?

They solve different problems. Authentik is an identity provider that authenticates users into other applications, while 2FAuth stores your existing 2FA accounts and generates TOTP, HOTP and Steam Guard codes for you to type elsewhere. Nothing in the 2FAuth README describes acting as an SSO provider.

What is a 2FAuth alternative if I do not want to self-host?

The README positions 2FAuth itself as a self-hosted alternative to OTP generators like Google Authenticator, so the direct swap in the other direction is a phone-based generator with no server to run. The README also lists import formats from Google Auth, Aegis, 2FAS and 2FAuth itself, which is the path you would take to move accounts either way.

Official sources

  1. Bubka/2FAuth on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bubka-2fauth.svg)](https://hysenlabs.com/projects/bubka-2fauth)