From ee9b5859521b47d1023efea72d6d5192c90d8a38 Mon Sep 17 00:00:00 2001 From: Kalzu Rekku Date: Tue, 4 Nov 2025 21:22:10 +0200 Subject: [PATCH] Added readme file. --- README.md | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..70857fc --- /dev/null +++ b/README.md @@ -0,0 +1,324 @@ +# 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. \ No newline at end of file