0x2fa is a two-factor authentication (2FA) system built on Oasis Protocol. It provides a secure, decentralized and user-friendly way to implement 2FA for any application.
The project is organized as follows:
contracts/
: Contains the Solidity smart contractsscripts/
: Deployment and utility scriptstest/
: Test files for the smart contractslib/
: External libraries and dependencies
The main contract Authenticator.sol
implements the 2FA functionality. It allows users to:
- Add new authenticator entries
- Remove existing entries
- Generate time-based codes
- Export authenticator entries
The OTPSHA1.sol
library provides the HOTP and TOTP implementations using SHA1 for generating one-time passwords.
-
Clone the repository:
git clone https://github.com/0x2fa-org/0x2fa.git cd 0x2fa
-
Install dependencies:
pnpm i
-
Compile the contracts:
hh compile
-
Run tests:
forge test
To deploy the Authenticator contract:
hh deploy --network <network-name>
Replace <network-name>
with the desired network (e.g., localhost
, sapphire
, sapphire-testnet
, sapphire-localhost
).
To interact with the deployed contract, you can use Viem in your frontend or backend application. Here are examples of how to use different functions of the Authenticator contract:
import { createPublicClient, http, createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { authenticatorABI } from './authenticatorABI'
const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
const contractAddress = '0x...'
async function addAuthenticator(auth: SignIn, secret: string, label: string, issuer: string, timestep: number) {
const { request } = await publicClient.simulateContract({
address: contractAddress,
abi: authenticatorABI,
functionName: 'add',
args: [auth, secret, label, issuer, timestep],
})
const hash = await walletClient.writeContract(request)
return hash
}
async function removeAuthenticator(auth: SignIn, id: number) {
const { request } = await publicClient.simulateContract({
address: contractAddress,
abi: authenticatorABI,
functionName: 'remove',
args: [auth, id],
})
const hash = await walletClient.writeContract(request)
return hash
}
async function generateCode(auth: SignIn, clientTimestamp: number) {
const code = await publicClient.readContract({
address: contractAddress,
abi: authenticatorABI,
functionName: 'generate',
args: [auth, clientTimestamp],
})
return code
}
async function exportAuthenticators(auth: SignIn) {
const entries = await publicClient.readContract({
address: contractAddress,
abi: authenticatorABI,
functionName: 'export',
args: [auth],
})
return entries
}
- Ensure that the secret keys for TOTP are securely stored and transmitted.
- Implement auth validation for all user functions to prevent unauthorized access.
- Relying on the block timestamp for TOTP generation is not secure.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License.