Added readme file.
This commit is contained in:
324
README.md
Normal file
324
README.md
Normal file
@@ -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.
|
||||||
Reference in New Issue
Block a user