An open API service indexing awesome lists of open source software.

https://github.com/cloudmosa/authenticator

Transfer MFA secrets to Cloud Phone devices
https://github.com/cloudmosa/authenticator

authenticator javascript mfa mfa-authenticator

Last synced: 22 days ago
JSON representation

Transfer MFA secrets to Cloud Phone devices

Awesome Lists containing this project

README

          

# MFA Sync Service

Secure, ephemeral MFA secret key sharing service for Cloud Phone devices, with or without a camera.

![Authenticator Design](./mfa-sync.png)

## Availability & Use

1. Sign up for the [Developer Program](https://www.cloudphone.tech/developer-program)
2. Enable [Developer Mode](https://developer.cloudfone.com/docs/guides/developer-tools/#developer-mode) on your Cloud Phone device
3. Add this widget with the URL: [https://mfa.cloudphone.tech/sync.html](https://mfa.cloudphone.tech/sync.html) and [icon](./public/favicon-512x512.png)
4. Visit [https://mfa.cloudphone.tech/](https://mfa.cloudphone.tech/) on your desktop or mobile (Android or iOS) and scan or enter an MFA secret
5. Open MFA Sync on Cloud Phone and enter the PIN

## Key Uri Format

This app processes data in the Key URI format.

```text
otpauth://totp/Zoho:email@zoho.com?secret=JBSWY3DPEHPK3PXP&period=30&digits=6&algorithm=SHA1&issuer=Zoho
```

See [Key Uri Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format).

## Architecture

```text
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Phone │ │ │ │ Feature │
│ (Admin) │────────>│ VPS Server │<────────│ Phone │
│ Scan QR Code│ │ + Redis │ │ Enter PIN │
└─────────────┘ └──────────────┘ └─────────────┘
│ │ │
│ │ │
└─── Generate PIN ───────┤ │
│ │
└──── Retrieve Secret ────┘
```

## Features

- ✅ **Ephemeral Storage**: Secrets auto-delete after retrieval or expiration
- ✅ **Encrypted at Rest**: AES-256-GCM encryption in Redis
- ✅ **Rate Limited**: Protection against brute force attacks
- ✅ **T9-Friendly**: Simple numeric PIN entry for feature phones
- ✅ **QR Scanner**: Built-in camera scanning for admin interface
- ✅ **TOTP Generator**: Full authenticator app functionality in browser
- ✅ **Zero Dependencies**: Client-side uses only Web Crypto API

## Quick Start

### Local Development

```bash
# Install dependencies
npm install

# Start Redis
docker run -d -p 6379:6379 redis:7-alpine

# Start server
npm start

# Access at http://localhost:3000
```

### Docker Deployment

```bash
# Build and run with Docker Compose
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down
```

## VPS Deployment

### Prerequisites

1. VPS with Docker installed
2. Domain name (optional, for HTTPS)
3. GitHub repository secrets configured

### GitHub Secrets Setup

Add these secrets to your GitHub repository:

```env
VPS_HOST=your.server.ip
VPS_USER=your-ssh-user
VPS_SSH_KEY=
ALLOWED_ORIGINS=https://mfa.cloudphone.tech
```

### Server Setup

```bash
# SSH into your VPS
ssh user@your-server

# Install Docker (if not installed)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# Create deployment directory
sudo mkdir -p /opt/mfa-sync
sudo chown $USER:$USER /opt/mfa-sync
cd /opt/mfa-sync

# Clone repository
git clone https://github.com/yourusername/mfa-sync.git .

# Create docker-compose.yml
cp docker-compose.yml /opt/mfa-sync/

# Start services
docker-compose up -d
```

### SSL Certificate (Let's Encrypt)

```bash
# Install certbot
sudo apt-get update
sudo apt-get install certbot

# Generate certificate
sudo certbot certonly --standalone -d mfa.cloudphone.tech

# Copy certificates to nginx directory
sudo mkdir -p /opt/mfa-sync/ssl
sudo cp /etc/letsencrypt/live/mfa.cloudphone.tech/fullchain.pem /opt/mfa-sync/ssl/cert.pem
sudo cp /etc/letsencrypt/live/mfa.cloudphone.tech/privkey.pem /opt/mfa-sync/ssl/key.pem
sudo chown -R $USER:$USER /opt/mfa-sync/ssl

# Restart nginx
docker-compose restart nginx
```

## Usage

### 1. Admin Interface

Access from your smartphone with a camera:

```text
https://mfa.cloudphone.tech.com/
```

1. Click "📷 Scan QR Code"
2. Point camera at MFA QR code
3. Secret auto-fills, or paste manually
4. Click "Generate PIN"
5. Display shows 6-digit PIN

### 2. Feature Phone Interface (sync.html)

Access from your feature phone browser:

```text
https://mfa.cloudphone.tech/sync.html
```

1. Enter the 6-digit PIN from admin interface
2. Click "Retrieve Secret" (or press Enter)
3. Account added with live TOTP codes
4. Codes refresh every 30 seconds

## API Reference

### POST /api/store

Store an MFA secret and generate PIN.

**Request:**

```json
{
"secret": "JBSWY3DPEHPK3PXP",
"label": "GitHub",
"issuer": "GitHub",
"ttl": 300
}
```

**Response:**

```json
{
"pin": "123456",
"expiresIn": 300,
"expiresAt": "2025-10-22T10:15:00.000Z"
}
```

### POST /api/retrieve

Retrieve MFA secret with PIN (one-time use).

**Request:**

```json
{
"pin": "123456"
}
```

**Response:**

```json
{
"secret": "JBSWY3DPEHPK3PXP",
"label": "GitHub",
"issuer": "GitHub",
"type": "totp",
"algorithm": "SHA1",
"digits": 6,
"period": 30
}
```

### GET `/api/health`

Health check endpoint.

**Response:**

```json
{
"status": "healthy",
"redis": "connected"
}
```

## Security Considerations

### What This Service Does

✅ Provides secure, temporary exchange of MFA secrets
✅ Encrypts secrets at rest with AES-256-GCM
✅ Automatically deletes secrets after retrieval
✅ Rate limits to prevent brute force attacks
✅ Uses in-memory storage (Redis) with TTL
✅ One-time PIN retrieval only

### What You Should Do

⚠️ **Use HTTPS only** - Never deploy without SSL/TLS
⚠️ **Restrict ALLOWED_ORIGINS** - Limit to your domain
⚠️ **Use strong firewall rules** - Limit Redis access
⚠️ **Monitor logs** - Watch for suspicious activity
⚠️ **Keep secrets short-lived** - Use 5-10 minute TTLs
⚠️ **Use on trusted networks** - Avoid public WiFi for admin interface

### Threat Model

- ✅ Protects against: Interception, storage leaks, unauthorized access
- ⚠️ Limited protection: Network-level attacks require HTTPS
- ❌ Does not protect: Compromised admin device, malicious VPS

## Environment Variables

```bash
PORT=3000 # Server port
REDIS_URL=redis://localhost:6379 # Redis connection string
ALLOWED_ORIGINS=* # CORS origins (comma-separated)
NODE_ENV=production # Environment
PIN_TTL=120 # Pin Time to Live (TTL) in seconds
```

## Troubleshooting

### Redis Connection Failed

```bash
# Check Redis is running
docker ps | grep redis

# View Redis logs
docker-compose logs redis

# Test Redis connection
docker exec -it mfa-sync-redis-1 redis-cli ping
```

### PIN Not Found

- Check TTL hasn't expired
- Verify PIN is exactly 6-8 digits
- Ensure no spaces in PIN entry
- Check if already retrieved (`/api/check/:pin`)

### Camera Not Working

- Ensure HTTPS is enabled (required for camera API)
- Check browser permissions
- Try different browser (Chrome/Safari recommended)

## License

[Apache 2.0](./LICENSE)

## Contributing

Issues and pull requests welcome!