• HomeHome
    • 2FAS Pass Mobile App
    • 2FAS Pass Browser Extension
    • Pricing
    • 2FAS Auth Mobile App
    • 2FAS Auth Browser Extension
    • Donate
  • About usAbout
  • Help CenterHelp Center
  • Get the appsGet the apps
  • HomeHome
    • 2FAS Pass Mobile App
    • 2FAS Pass Browser Extension
    • Pricing
    • 2FAS Auth Mobile App
    • 2FAS Auth Browser Extension
    • Donate
  • About usAbout
  • Help CenterHelp Center
  • Get the appsGet the apps

We believe in making
the Internet a safer
and more secure place. For everyone.

Open-source and Source-available 2FAS apps are essential to our mission of revolutionizing the security standards of protecting online accounts.


                      import UIKit
                      import Common
                      
                      final class TokensViewController: UIViewController {
                          var presenter: TokensPresenter!
                          var addButton: UIBarButtonItem? {
                              navigationItem.rightBarButtonItem
                          }
                          private(set) var gridView: GridView!
                          private(set) var gridLayout: UICollectionViewFlowLayout!
                          private(set) var dataSource: UICollectionViewDiffableDataSource<GridSection, GridCell>!
                          
                          let headerHeight: CGFloat = 50
                          let emptySearchScreenView = GridViewEmptySearchScreen()
                          let emptyListScreenView = GridViewEmptyListScreen()
                          
                          private var configuredWidth: CGFloat = 0
                          var searchBarAdded = false
                          
                          let searchController = CommonSearchController()
                          
                          override func loadView() {
                              gridLayout = UICollectionViewFlowLayout()
                              gridView = GridView(frame: .zero, collectionViewLayout: gridLayout)
                              self.view = gridView
                              gridView.configure()
                          }
                          
                          override func viewDidLoad() {
                              super.viewDidLoad()
                              
                              setupView()
                              setupEmptyScreensLayout()
                              setupEmptyScreensEvents()
                              setupDelegates()
                              setupDataSource()
                              setupDragAndDrop()
                              setupNotificationsListeners()
                          }
                          
                          // MARK: - App events
                          
                          override func viewWillLayoutSubviews() {
                              super.viewWillLayoutSubviews()
                              configureLayout()
                          }
                          
                          override func viewWillAppear(_ animated: Bool) {
                              super.viewWillAppear(animated)
                              presenter.viewWillAppear()
                              startSafeAreaKeyboardAdjustment()
                          }
                          
                          override func viewWillDisappear(_ animated: Bool) {
                              super.viewWillDisappear(animated)
                              stopSafeAreaKeyboardAdjustment()
                          }
                          
                          deinit {
                              NotificationCenter.default.removeObserver(self)
                          }
                      }
                      
                      private extension TokensViewController {
                          func setupView() {
                              extendedLayoutIncludesOpaqueBars = true
                              view.backgroundColor = Theme.Colors.Fill.background
                              title = T.Commons.tokens
                              accessibilityTraits = .header
                          }
                          
                          func setupDelegates() {
                              searchController.searchBarDelegate = self
                              gridView.delegate = self
                          }
                          
                          func setupDataSource() {
                              dataSource = UICollectionViewDiffableDataSource(
                                  collectionView: gridView,
                                  cellProvider: { collectionView, indexPath, item in
                                      if item.cellType == .serviceTOTP {
                                          if collectionView.isEditing {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewEditItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewEditItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  additionalInfo: item.additionalInfo,
                                                  serviceTypeName: item.serviceTypeName,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  canBeDragged: item.canBeDragged
                                              )
                                              return cell
                                          } else {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  secret: item.secret,
                                                  serviceTypeName: item.serviceTypeName,
                                                  additionalInfo: item.additionalInfo,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  useNextToken: item.useNextToken
                                              )
                                              return cell
                                          }
                                      } else if item.cellType == .serviceHOTP {
                                          if collectionView.isEditing {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewEditItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewEditItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  additionalInfo: item.additionalInfo,
                                                  serviceTypeName: item.serviceTypeName,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  canBeDragged: item.canBeDragged
                                              )
                                              return cell
                                          } else {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewCounterItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewCounterItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  secret: item.secret,
                                                  serviceTypeName: item.serviceTypeName,
                                                  additionalInfo: item.additionalInfo,
                                                  iconType: item.iconType,
                                                  category: item.category
                                              )
                                              return cell
                                          }
                                      }
                                      let cell = collectionView.dequeueReusableCell(
                                          withReuseIdentifier: GridEmptyCollectionViewCell.reuseIdentifier,
                                          for: indexPath
                                      ) as? GridEmptyCollectionViewCell
                                      return cell
                                  })
                              dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath
                                  -> UICollectionReusableView? in
                                  let header = collectionView.dequeueReusableSupplementaryView(
                                      ofKind: kind,
                                      withReuseIdentifier: GridSectionHeader.reuseIdentifier,
                                      for: indexPath
                                  ) as? GridSectionHeader
                                  header?.setIsEditing(collectionView.isEditing)
                                  header?.dataSource = self
                                  if let data = self?.dataSource.snapshot().sectionIdentifiers[indexPath.section] {
                                      header?.setConfiguration(data)
                                  }
                                  return header
                              }
                          }
                          
                          func setupDragAndDrop() {
                              gridView.dragDelegate = self
                              gridView.dropDelegate = self
                              gridView.dragInteractionEnabled = presenter.enableDragAndDropOnStart
                          }
                          
                          func setupEmptyScreensLayout() {
                              view.addSubview(emptySearchScreenView, with: [
                                  emptySearchScreenView.leadingAnchor.constraint(equalTo: gridView.frameLayoutGuide.leadingAnchor),
                                  emptySearchScreenView.trailingAnchor.constraint(equalTo: gridView.frameLayoutGuide.trailingAnchor),
                                  emptySearchScreenView.topAnchor.constraint(equalTo: gridView.frameLayoutGuide.topAnchor),
                                  emptySearchScreenView.bottomAnchor.constraint(equalTo: gridView.frameLayoutGuide.bottomAnchor)
                              ])
                              emptySearchScreenView.isHidden = true
                              emptySearchScreenView.alpha = 0
                              
                              view.addSubview(emptyListScreenView, with: [
                                  emptyListScreenView.leadingAnchor.constraint(equalTo: gridView.frameLayoutGuide.leadingAnchor),
                                  emptyListScreenView.trailingAnchor.constraint(equalTo: gridView.frameLayoutGuide.trailingAnchor),
                                  emptyListScreenView.topAnchor.constraint(equalTo: gridView.safeTopAnchor),
                                  emptyListScreenView.bottomAnchor.constraint(equalTo: gridView.safeBottomAnchor)
                              ])
                              emptyListScreenView.isHidden = true
                              emptyListScreenView.alpha = 0
                          }
                          
                          func configureLayout() {
                              guard let screenWidth = UIApplication.keyWindow?.bounds.size.width,
                                    configuredWidth != screenWidth else { return }
                              
                              configuredWidth = screenWidth
                              
                              let cellHeight = Theme.Metrics.servicesCellHeight
                              
                              let minimumCellWidth: CGFloat = Theme.Metrics.pageWidth
                              let itemsInRow = Int(screenWidth / minimumCellWidth)
                              let margin: CGFloat = 0
                              
                              let marginsWidth = margin * CGFloat(itemsInRow - 1)
                              let screenWidthWithoutMargins = screenWidth - marginsWidth
                              let elementWidth = floor(screenWidthWithoutMargins / CGFloat(itemsInRow))
                              
                              gridLayout.itemSize = CGSize(width: elementWidth, height: cellHeight)
                              gridLayout.minimumInteritemSpacing = margin
                              
                              gridLayout.headerReferenceSize = CGSize(width: 100, height: headerHeight)
                              
                              gridLayout.minimumLineSpacing = 0
                          }
                          
                          func setupEmptyScreensEvents() {
                              emptyListScreenView.pairNewService = { [weak self] in self?.presenter.handleShowCamera() }
                              emptyListScreenView.import2FAS = { [weak self] in
                                  AnalyticsLog(.onboardingBackupFile)
                                  self?.presenter.handleImport2FAS()
                              }
                              emptyListScreenView.importGA = { [weak self] in
                                  AnalyticsLog(.onboardingGA)
                                  self?.presenter.handleImportGA()
                              }
                              emptyListScreenView.help = { [weak self] in self?.presenter.handleShowHelp() }
                          }
                          
                          func setupNotificationsListeners() {
                              let center = NotificationCenter.default
                              center.addObserver(
                                  self, selector: #selector(notificationServicesWereUpdated), name: .servicesWereUpdated, object: nil
                              )
                              center.addObserver(
                                  self, selector: #selector(notificationSectionsWereUpdated), name: .sectionsWereUpdated, object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeActive),
                                  name: UIApplication.didBecomeActiveNotification,
                                  object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeInactive),
                                  name: UIApplication.willResignActiveNotification,
                                  object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeInactive),
                                  name: UIApplication.didEnterBackgroundNotification,
                                  object: nil
                              )
                          }
                      }
                      import UIKit
                      import Common
                      
                      final class TokensViewController: UIViewController {
                          var presenter: TokensPresenter!
                          var addButton: UIBarButtonItem? {
                              navigationItem.rightBarButtonItem
                          }
                          private(set) var gridView: GridView!
                          private(set) var gridLayout: UICollectionViewFlowLayout!
                          private(set) var dataSource: UICollectionViewDiffableDataSource<GridSection, GridCell>!
                          
                          let headerHeight: CGFloat = 50
                          let emptySearchScreenView = GridViewEmptySearchScreen()
                          let emptyListScreenView = GridViewEmptyListScreen()
                          
                          private var configuredWidth: CGFloat = 0
                          var searchBarAdded = false
                          
                          let searchController = CommonSearchController()
                          
                          override func loadView() {
                              gridLayout = UICollectionViewFlowLayout()
                              gridView = GridView(frame: .zero, collectionViewLayout: gridLayout)
                              self.view = gridView
                              gridView.configure()
                          }
                          
                          override func viewDidLoad() {
                              super.viewDidLoad()
                              
                              setupView()
                              setupEmptyScreensLayout()
                              setupEmptyScreensEvents()
                              setupDelegates()
                              setupDataSource()
                              setupDragAndDrop()
                              setupNotificationsListeners()
                          }
                          
                          // MARK: - App events
                          
                          override func viewWillLayoutSubviews() {
                              super.viewWillLayoutSubviews()
                              configureLayout()
                          }
                          
                          override func viewWillAppear(_ animated: Bool) {
                              super.viewWillAppear(animated)
                              presenter.viewWillAppear()
                              startSafeAreaKeyboardAdjustment()
                          }
                          
                          override func viewWillDisappear(_ animated: Bool) {
                              super.viewWillDisappear(animated)
                              stopSafeAreaKeyboardAdjustment()
                          }
                          
                          deinit {
                              NotificationCenter.default.removeObserver(self)
                          }
                      }
                      
                      private extension TokensViewController {
                          func setupView() {
                              extendedLayoutIncludesOpaqueBars = true
                              view.backgroundColor = Theme.Colors.Fill.background
                              title = T.Commons.tokens
                              accessibilityTraits = .header
                          }
                          
                          func setupDelegates() {
                              searchController.searchBarDelegate = self
                              gridView.delegate = self
                          }
                          
                          func setupDataSource() {
                              dataSource = UICollectionViewDiffableDataSource(
                                  collectionView: gridView,
                                  cellProvider: { collectionView, indexPath, item in
                                      if item.cellType == .serviceTOTP {
                                          if collectionView.isEditing {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewEditItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewEditItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  additionalInfo: item.additionalInfo,
                                                  serviceTypeName: item.serviceTypeName,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  canBeDragged: item.canBeDragged
                                              )
                                              return cell
                                          } else {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  secret: item.secret,
                                                  serviceTypeName: item.serviceTypeName,
                                                  additionalInfo: item.additionalInfo,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  useNextToken: item.useNextToken
                                              )
                                              return cell
                                          }
                                      } else if item.cellType == .serviceHOTP {
                                          if collectionView.isEditing {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewEditItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewEditItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  additionalInfo: item.additionalInfo,
                                                  serviceTypeName: item.serviceTypeName,
                                                  iconType: item.iconType,
                                                  category: item.category,
                                                  canBeDragged: item.canBeDragged
                                              )
                                              return cell
                                          } else {
                                              let cell = collectionView.dequeueReusableCell(
                                                  withReuseIdentifier: GridViewCounterItemCell.reuseIdentifier,
                                                  for: indexPath
                                              ) as? GridViewCounterItemCell
                                              cell?.update(
                                                  name: item.name,
                                                  secret: item.secret,
                                                  serviceTypeName: item.serviceTypeName,
                                                  additionalInfo: item.additionalInfo,
                                                  iconType: item.iconType,
                                                  category: item.category
                                              )
                                              return cell
                                          }
                                      }
                                      let cell = collectionView.dequeueReusableCell(
                                          withReuseIdentifier: GridEmptyCollectionViewCell.reuseIdentifier,
                                          for: indexPath
                                      ) as? GridEmptyCollectionViewCell
                                      return cell
                                  })
                              dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath
                                  -> UICollectionReusableView? in
                                  let header = collectionView.dequeueReusableSupplementaryView(
                                      ofKind: kind,
                                      withReuseIdentifier: GridSectionHeader.reuseIdentifier,
                                      for: indexPath
                                  ) as? GridSectionHeader
                                  header?.setIsEditing(collectionView.isEditing)
                                  header?.dataSource = self
                                  if let data = self?.dataSource.snapshot().sectionIdentifiers[indexPath.section] {
                                      header?.setConfiguration(data)
                                  }
                                  return header
                              }
                          }
                          
                          func setupDragAndDrop() {
                              gridView.dragDelegate = self
                              gridView.dropDelegate = self
                              gridView.dragInteractionEnabled = presenter.enableDragAndDropOnStart
                          }
                          
                          func setupEmptyScreensLayout() {
                              view.addSubview(emptySearchScreenView, with: [
                                  emptySearchScreenView.leadingAnchor.constraint(equalTo: gridView.frameLayoutGuide.leadingAnchor),
                                  emptySearchScreenView.trailingAnchor.constraint(equalTo: gridView.frameLayoutGuide.trailingAnchor),
                                  emptySearchScreenView.topAnchor.constraint(equalTo: gridView.frameLayoutGuide.topAnchor),
                                  emptySearchScreenView.bottomAnchor.constraint(equalTo: gridView.frameLayoutGuide.bottomAnchor)
                              ])
                              emptySearchScreenView.isHidden = true
                              emptySearchScreenView.alpha = 0
                              
                              view.addSubview(emptyListScreenView, with: [
                                  emptyListScreenView.leadingAnchor.constraint(equalTo: gridView.frameLayoutGuide.leadingAnchor),
                                  emptyListScreenView.trailingAnchor.constraint(equalTo: gridView.frameLayoutGuide.trailingAnchor),
                                  emptyListScreenView.topAnchor.constraint(equalTo: gridView.safeTopAnchor),
                                  emptyListScreenView.bottomAnchor.constraint(equalTo: gridView.safeBottomAnchor)
                              ])
                              emptyListScreenView.isHidden = true
                              emptyListScreenView.alpha = 0
                          }
                          
                          func configureLayout() {
                              guard let screenWidth = UIApplication.keyWindow?.bounds.size.width,
                                    configuredWidth != screenWidth else { return }
                              
                              configuredWidth = screenWidth
                              
                              let cellHeight = Theme.Metrics.servicesCellHeight
                              
                              let minimumCellWidth: CGFloat = Theme.Metrics.pageWidth
                              let itemsInRow = Int(screenWidth / minimumCellWidth)
                              let margin: CGFloat = 0
                              
                              let marginsWidth = margin * CGFloat(itemsInRow - 1)
                              let screenWidthWithoutMargins = screenWidth - marginsWidth
                              let elementWidth = floor(screenWidthWithoutMargins / CGFloat(itemsInRow))
                              
                              gridLayout.itemSize = CGSize(width: elementWidth, height: cellHeight)
                              gridLayout.minimumInteritemSpacing = margin
                              
                              gridLayout.headerReferenceSize = CGSize(width: 100, height: headerHeight)
                              
                              gridLayout.minimumLineSpacing = 0
                          }
                          
                          func setupEmptyScreensEvents() {
                              emptyListScreenView.pairNewService = { [weak self] in self?.presenter.handleShowCamera() }
                              emptyListScreenView.import2FAS = { [weak self] in
                                  AnalyticsLog(.onboardingBackupFile)
                                  self?.presenter.handleImport2FAS()
                              }
                              emptyListScreenView.importGA = { [weak self] in
                                  AnalyticsLog(.onboardingGA)
                                  self?.presenter.handleImportGA()
                              }
                              emptyListScreenView.help = { [weak self] in self?.presenter.handleShowHelp() }
                          }
                          
                          func setupNotificationsListeners() {
                              let center = NotificationCenter.default
                              center.addObserver(
                                  self, selector: #selector(notificationServicesWereUpdated), name: .servicesWereUpdated, object: nil
                              )
                              center.addObserver(
                                  self, selector: #selector(notificationSectionsWereUpdated), name: .sectionsWereUpdated, object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeActive),
                                  name: UIApplication.didBecomeActiveNotification,
                                  object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeInactive),
                                  name: UIApplication.willResignActiveNotification,
                                  object: nil
                              )
                              center.addObserver(
                                  self,
                                  selector: #selector(notificationAppDidBecomeInactive),
                                  name: UIApplication.didEnterBackgroundNotification,
                                  object: nil
                              )
                          }
                      }
                    

Mission-driven

Online security is critical to everyone's privacy, online and offline. Account hijacking leads to breaches of personal data, leaks of valuable and sensitive information, social media impersonation, and results in billions of dollars in damage each year.

How do you know which security solution is best for you? Should you evaluate tools based on trust or brand reputation alone — or perhaps on a reliable source of information, including source code?

That is why we created the 2FAS project — an initiative that adheres to the values of transparency, privacy and security. The 2FAS apps are designed to meet everyone's needs while remaining free, accessible and easy to use.
11

years of careful development and continuous improvements

4.7

average rating score in Google Play and AppStore

6+

million downloads worldwide

How we started and where we are today

2015
Mark

Mark founded 2FAS.

2016

We are doing R&D projects related to the internet security and 2FA.

2017

2FAS Auth is launched on AppStore and GooglePlay.

2018

2FAS Auth reaches first 100k downloads.

2019

2FAS Auth redesigned according to new UI guidelines.

2020

2FAS Auth reaches 1 million downloads.

2021

Backup added to 2FAS Auth, and it reached 2.5 million downloads.

2022

We launched a Discord server and a custom Browser Extension. 2FAS Auth reached 5 million downloads and turned into an Open-source project.

2023

We've added several new languages to 2FAS Auth, and it reached 6 million downloads.

2024

We started working on a new project - 2FAS Pass, a local-first password manager. 2FAS Auth reaches 8 million downloads

2025

2FAS Pass is launched on AppStore and Google Play.

Next

Meet the TEAM

We're security, design and Open-source enthusiasts, forever curious and ready to transform the way online security is done.

Core squad

Mark
Founder, CEO
Mark
Greg
CTO
Greg
Andrew
CMO
Andrew
Paul
CDO, UX
Paul
Raphael
Development
Raphael
Zibi
Development
Zibi
Matt
Development
Matt
Tobias
Development
Tobias
Chris
Development
Chris
Matt
Design
Matt
Dominic
Design
Dominic
Irena
Brand Relations Manager
Irena
Rafael
Lead translator, QA
Rafael
Leo
Community Lead
Leo
Matt
Security Officer
Matt
Contributors

The project is developed with the support of an awesome group of contributors that regularly improve the 2FAS app codebase, content of our application and build the 2FAS community.

Dhavan Bhayani@‌Dhavan Bhayani

Yurashi

AndJustice4All

Leonardo@Spluffity

Vijay Pondini@vijaypondini

Chris@Bravo_six

Justin Reitmeier

Fluffy

Jan Tennert

Noah@noah

Pedro Monteiro

SrHallowen_

SadBeats

Syun

Emp

NΞОИ

ThePokyx

Artem@Globart

Samuel Rollón del Río

Rosanna @roclahy

pmtz

Skyglitch

Davide Fiorini@fiorins

ΛMNESIΛ

Bruce

Kyriakos Parmakelis@Talos

Alexander K

polygon0323/ぽりごん

ROCKTAKEY

Mikuqwq

Xiaohuli_zi

Yoru.kot

Ceviz

Arsquid

Nifty

xfoxx

gabrielebonini99

Do you want to contribute to the 2FAS project?

We are giving the world the 2FAS apps completely free. If you believe in keeping the Internet safe, open and secure for everyone, we would greatly value your contribution!

Do you want to contribute to the 2FAS project?

There are several ways for you to contribute to the 2FAS project:

  • Check the 2FAS source code.
  • Commit code changes.
  • Increase security by finding and solving vulnerabilities.
  • Translate the 2FAS app to new languages.
  • Popularize the 2FAS app (Social Media / other channels).
  • Help other users with 2FA and the 2FAS apps-related problems on our Discord server.
  • Support other users by creating documentation and helping to overcome difficulties.
  • Update and expand the service’s icons database.
  • Donate to the 2FAS project.
Check our GitHubJoin our Discord

2FAS has been featured in

Want to meet?
Let's connect online
or offline!

We are working 100% remotely, but if you're interested in cooperation, let's have an online call or meet for coffee in Las Vegas!

Find us in sunny Nevada

Two Factor Authentication Service, Inc.

1887 Whitney Mesa Dr #2130

Henderson, Nevada 89014

Want to meet? Let's connect online or offline!Want to meet? Let's connect online or offline!
  • About us
  • Press kit
  • Terms of Service
  • Privacy Policy

Site theme

Authenticator

Products

  • 2FAS Auth Mobile App
  • 2FAS Auth Browser Extension

Resources

  • Donations
  • How to enable 2FA
  • Quick Browser Extension Check
  • Check generated token
  • Your branding
  • Your 2FA guide
  • Open-source Licenses

Comparisons

  • Google Authenticator vs. 2FAS Auth
  • Authy vs. 2FAS Auth
  • Microsoft Authenticator vs. 2FAS Auth
  • Duo vs. 2FAS Auth

Policies

  • 2FAS Auth Privacy Policy
  • 2FAS Auth EULA

Password manager

Products

  • 2FAS Pass Mobile App
  • 2FAS Pass Browser Extension

Resources

  • 2FAS Pass Pricing
  • 2FAS Pass Recovery
  • Open-source Licenses

Policies

  • 2FAS Pass Privacy Policy
  • 2FAS Pass EULA

Support

  • Help Center
  • Support

Connect

© 2026 Two Factor Authentication Service, Inc. All rights reserved.