Files
forward_auth_server/README.md
2025-11-04 21:22:10 +02:00

324 lines
7.4 KiB
Markdown

# Forward Auth TOTP
A lightweight forward authentication service for Caddy (or any reverse proxy) that uses TOTP (Time-based One-Time Password) tokens for user authentication.
## Features
- 🔐 TOTP-based authentication (compatible with Google Authenticator, Authy, 1Password, etc.)
- 🎫 JWT session management with configurable duration
- 👥 Support for multiple users (1-20+ TOTP seeds)
- 🪶 Lightweight SQLite database
- 🚀 Single binary deployment
- 🔄 Works with Caddy's `forward_auth` directive
- 📱 Mobile-friendly login page
## Prerequisites
- Go 1.21 or higher
- SQLite3
- Caddy v2 (or any reverse proxy that supports forward authentication)
## Installation
### Clone the repository
```bash
git clone https://github.com/yourusername/forward-auth-totp.git
cd forward-auth-totp
```
### Install dependencies
```bash
go mod download
```
### Build the application
```bash
go build -o forward-auth main.go
```
## Configuration
### Environment Variables
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `JWT_SECRET` | Secret key for signing JWT tokens | (insecure default) | **Recommended** |
**Important:** Always set a secure `JWT_SECRET` in production:
```bash
export JWT_SECRET="your-very-secure-random-secret-here-min-32-chars"
```
Generate a secure secret:
```bash
openssl rand -base64 32
```
### Application Constants
You can modify these constants in `main.go`:
- `sessionDuration`: JWT session duration (default: 24 hours)
- `dbFile`: SQLite database file path (default: `auth.db`)
- `jwtCookie`: Cookie name for JWT token (default: `auth_token`)
## Usage
### First Run
On first run, the application will automatically generate a TOTP seed:
```bash
./forward-auth
```
Output:
```
No seeds found, generating one...
New TOTP seed generated:
Secret: JBSWY3DPEHPK3PXP
OTPAuth URL: otpauth://totp/ForwardAuthApp:user?secret=JBSWY3DPEHPK3PXP&issuer=ForwardAuthApp
Use this to set up your authenticator app.
Starting auth server on :3000
```
Scan the QR code (use the OTPAuth URL with a QR generator) or manually enter the secret into your authenticator app.
### Generate Additional TOTP Seeds
For multiple users, generate additional seeds:
```bash
./forward-auth -generate
```
Each seed can be used by a different user with their own authenticator app.
### Running as a Service
#### systemd (Linux)
Create `/etc/systemd/system/forward-auth.service`:
```ini
[Unit]
Description=Forward Auth TOTP Service
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/forward-auth
Environment="JWT_SECRET=your-secure-secret-here"
ExecStart=/opt/forward-auth/forward-auth
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
```
Enable and start:
```bash
sudo systemctl enable forward-auth
sudo systemctl start forward-auth
```
## Caddy Configuration
### Basic Configuration
```caddyfile
# Your protected application
app.example.com {
forward_auth localhost:3000 {
uri /verify
copy_headers X-Original-URI
}
reverse_proxy localhost:8080
}
# Auth service (optional, if you want it accessible externally)
auth.example.com {
reverse_proxy localhost:3000
}
```
### Advanced Configuration with Error Handling
```caddyfile
app.example.com {
# Allow access to login page without auth
@login {
path /login*
}
handle @login {
reverse_proxy localhost:3000
}
# Protect everything else
forward_auth localhost:3000 {
uri /verify
copy_headers X-Original-URI
}
reverse_proxy localhost:8080
}
```
### Multiple Protected Services
```caddyfile
# Auth service
auth.example.com {
reverse_proxy localhost:3000
}
# Protected app 1
app1.example.com {
forward_auth auth.example.com {
uri /verify
copy_headers X-Original-URI
}
reverse_proxy localhost:8080
}
# Protected app 2
app2.example.com {
forward_auth auth.example.com {
uri /verify
copy_headers X-Original-URI
}
reverse_proxy localhost:8081
}
```
## API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/verify` | GET | Verify JWT token (for forward auth) |
| `/login` | GET | Display login form |
| `/login` | POST | Process OTP submission |
| `/health` | GET | Health check endpoint |
## Security Considerations
### Production Checklist
- [ ] Set a strong `JWT_SECRET` environment variable
- [ ] Enable HTTPS and uncomment `Secure: true` in cookie settings
- [ ] Restrict database file permissions: `chmod 600 auth.db`
- [ ] Run the service as a non-root user
- [ ] Keep the TOTP secrets secure and backed up
- [ ] Consider rate limiting on the `/login` endpoint
- [ ] Monitor failed authentication attempts
### HTTPS Configuration
For production, uncomment the `Secure` flag in `main.go`:
```go
http.SetCookie(w, &http.Cookie{
Name: jwtCookie,
Value: tokenStr,
Expires: time.Now().Add(sessionDuration),
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
Secure: true, // Uncomment this line
Path: "/",
})
```
## Database Management
### Backup
```bash
cp auth.db auth.db.backup
```
### View All Seeds
```bash
sqlite3 auth.db "SELECT * FROM seeds;"
```
### Remove a Seed
```bash
sqlite3 auth.db "DELETE FROM seeds WHERE id = 1;"
```
### Reset Database
```bash
rm auth.db
./forward-auth # Will generate a new seed automatically
```
## Troubleshooting
### "Invalid OTP" Error
- Ensure your device time is synchronized (TOTP is time-based)
- Check that you're using the correct seed in your authenticator app
- Verify the OTP code hasn't expired (codes are valid for 30 seconds)
### Authentication Not Working
- Check Caddy logs: `journalctl -u caddy -f`
- Check forward-auth logs: `journalctl -u forward-auth -f`
- Verify the forward auth service is running: `curl http://localhost:3000/health`
- Ensure `X-Original-URI` header is being passed correctly
### Cookie Not Persisting
- Verify you're using HTTPS in production with `Secure: true`
- Check that the cookie path matches your application structure
- Ensure `SameSite` attribute is compatible with your setup
## Performance
This application is designed for light usage (1-20 users, <100 requests/day):
- **Memory footprint:** ~10-15 MB
- **CPU usage:** Minimal (<1% on modern systems)
- **Database size:** <1 KB for up to 20 seeds
- **Startup time:** <100ms
## Development
### Run in Development Mode
```bash
go run main.go
```
### Run Tests
```bash
go test -v ./...
```
### Build for Different Platforms
```bash
# Linux
GOOS=linux GOARCH=amd64 go build -o forward-auth-linux main.go
# macOS
GOOS=darwin GOARCH=amd64 go build -o forward-auth-macos main.go
# Windows
GOOS=windows GOARCH=amd64 go build -o forward-auth.exe main.go
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
MIT License - see LICENSE file for details
## Acknowledgments
- [golang-jwt/jwt](https://github.com/golang-jwt/jwt) - JWT implementation
- [pquerna/otp](https://github.com/pquerna/otp) - TOTP implementation
- [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - SQLite driver
## Support
For issues and questions, please open an issue on GitHub.
---
**Note:** This is a simple authentication service suitable for personal or small team use. For larger deployments, consider more robust authentication solutions with features like account lockout, audit logging, and multi-factor authentication options.