Self-hosted testing platform for Duo authentication flows
Test, demonstrate, and validate Duo authentication policies across WebSDK v4, Device Management Portal, SAML 2.0, and OIDC.
Key capabilities: Multi-tenant management · Web-based configuration · Auto-provisioning via Admin API · Policy testing · Theme-aware UI
Step 1: Run the Toolkit
docker run -d \
--name duo-uet \
-p 8080:8080 \
-v duo-uet-data:/app/config \
ghcr.io/1broseidon/duo_uet:latestStep 2: Create Admin API Credentials in Duo
- Log into the Duo Admin Panel
- Go to Applications → Protect an Application
- Search for "Admin API" and click Protect
- Grant these permissions:
- ✅ Grant read information (validates credentials)
- ✅ Grant applications (auto-creates test apps)
Step 3: Configure the Toolkit
- Open
http://localhost:8080/configure - Click Add Tenant and paste your Admin API credentials:
- Integration key
- Secret key
- API hostname
- Start creating test applications!
Configuration persists automatically in the Docker volume.
Alternative: Docker Compose
For persistent test environments, use the included docker-compose.yml:
docker compose up -dIncludes named volumes and health checks.
Alternative: Local Directory
To access the config file directly on your host:
mkdir -p duo-config
docker run -d \
--name duo-uet \
-p 8080:8080 \
-v $(pwd)/duo-config:/app/config \
ghcr.io/1broseidon/duo_uet:latestConfig appears at ./duo-config/config.yaml
- Multi-tenant support — Test multiple Duo environments simultaneously
- Auto-provisioning — Creates applications in Duo Admin Panel via API
- Full auth coverage — WebSDK v4, DMP, SAML 2.0, OIDC in one interface
- Zero config required — Web UI handles all configuration
- Persistent storage — Configuration survives container restarts
For Customer Success Engineers:
- Demonstrate different Duo authentication experiences to prospects
- Validate policy configurations before customer deployment
- Troubleshoot authentication flows with isolated test environments
- Compare behavior across WebSDK versions and SSO protocols
For Technical Teams:
- Test authentication integration before customer deployments
- Training environment for new team members
- Policy impact analysis and validation
- Troubleshoot authentication issues in isolation
For Security Teams:
- Audit authentication behavior across different configurations
- Test MFA policy enforcement in controlled environments
- Validate SSO metadata and claim mappings
- Security assessment of authentication flows
Download the latest release from GitHub Releases:
# Linux/macOS example
wget https://github.com/1broseidon/duo_uet/releases/download/v1.0.0/user_experience_toolkit_1.0.0_linux_amd64.tar.gz
tar -xzf user_experience_toolkit_1.0.0_linux_amd64.tar.gz
./uetPlatforms: Linux, macOS, Windows (amd64, arm64)
Requires Go 1.25+:
git clone https://github.com/1broseidon/duo_uet.git
cd duo_uet
go mod download
go build -o uet ./cmd/uet
./uetAccess at http://localhost:8080
┌─────────────────┐
│ 1. Start App │ Docker or binary starts with empty config
└────────┬────────┘
│
▼
┌─────────────────┐
│ 2. Web UI Setup │ Navigate to /configure
└────────┬────────┘ Add Admin API credentials
│
▼
┌─────────────────┐
│ 3. Auto-Create │ Provision apps via Duo Admin API
└────────┬────────┘ Generate client IDs/secrets automatically
│
▼
┌─────────────────┐
│ 4. Test Flows │ Applications appear on dashboard
└─────────────────┘ Test authentication immediately
Configuration is stored in config.yaml and persists in your Docker volume or local directory. The file is automatically created on first run and managed through the web UI.
Priority order for config file resolution:
UET_CONFIG_PATHenvironment variable/app/config/config.yaml(Docker default)./config.yaml(local development)
Edit config.yaml directly:
encryption_enabled: false # Optional: Enable AES-256-GCM encryption
tenants:
- id: "tenant-1"
name: "Production"
api_hostname: "api-xxxxxxxx.duosecurity.com"
admin_api_key: "DIXXXXXXXXXXXXXXXXXX"
admin_api_secret: "your-secret-key"
applications:
- id: "app-1"
name: "WebSDK v4 Demo"
type: "websdk"
tenant_id: "tenant-1"
enabled: true
client_id: "DIXXXXXXXXXXXXXXXXXX"
client_secret: "your-client-secret"Full schema: config.yaml.example
For sensitive test environments, enable AES-256-GCM encryption:
# Enable encryption in config.yaml
encryption_enabled: true
# Provide master key via environment
export UET_MASTER_KEY="your-secure-password"
# Or use auto-generated key file (creates .uet_key with chmod 600)
./uetNote: This toolkit is designed for testing and demonstration. For production Duo deployments, use Duo's production-grade integrations directly.
Test and demonstrate all major Duo authentication flows:
| Type | Description | Testing Focus |
|---|---|---|
| WebSDK v4 | Universal Prompt | Policy behavior, MFA methods, device trust |
| DMP | Device Management Portal | Device health checks, trusted endpoints |
| SAML 2.0 | Duo SSO SAML | Metadata validation, attribute mapping, SSO flows |
| OIDC | Duo SSO OpenID Connect | Token validation, claim inspection, scope testing |
Note: All authentication flows use Duo's latest Universal SDK (WebSDK v4). DMP is simply a specialized configuration for device trust policies.
Each flow provides:
- Complete authentication simulation
- Token/claim inspection for validation
- Technical details for troubleshooting
- Side-by-side policy comparison
┌─────────────────────────────────────────────────────────────┐
│ Frontend │
│ Bulma CSS + Design System + Theme Switcher (Light/Dark) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Go Fiber v3 API │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Home │ │ Config │ │ Auth │ │ Admin │ │
│ │ Handler │ │ Handler │ │ Flows │ │ API │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Config Management │
│ YAML Storage + Optional AES-256-GCM Encryption │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Duo Integration │
│ Universal SDK + Admin API + SAML + OIDC Libraries │
└─────────────────────────────────────────────────────────────┘
Tech Stack:
- Backend: Go 1.25, Fiber v3
- Frontend: Vanilla JS, Bulma CSS, HTML
- Storage: YAML with optional encryption
- Auth: Duo Universal SDK (WebSDK v4), SAML 2.0, OIDC
- Container: Docker, Alpine Linux, multi-arch
Development: See CONTRIBUTING.md for development setup, testing, and code quality guidelines.
docker build -t duo-uet:local .
# Run with auto-generated config
docker run -d \
-p 8080:8080 \
-v duo-uet-local:/app/config \
duo-uet:localAutomated builds on version tags (v*.*.*):
ghcr.io/1broseidon/duo_uet:latest- Latest releaseghcr.io/1broseidon/duo_uet:v1.0.0- Specific versionghcr.io/1broseidon/duo_uet:v1.0,v1- Major/minor aliases
Multi-arch support: linux/amd64, linux/arm64
UET_CONFIG_PATH— Override config file location (default:/app/config/config.yamlin Docker,./config.yamllocally)UET_MASTER_KEY— Master encryption key for encrypted configs (optional)TZ— Timezone for logs and timestamps (default:UTC)
.
├── cmd/
│ ├── uet/ # Main application entry point
│ │ ├── main.go # Application entrypoint with embedded assets
│ │ ├── static/ # CSS, JS, images (embedded in binary)
│ │ └── templates/ # HTML templates (embedded in binary)
│ └── encrypt-config/ # Config encryption utility
├── internal/
│ ├── config/ # YAML config + encryption
│ ├── crypto/ # AES-256-GCM encryption
│ ├── handlers/ # HTTP handlers (home, config, auth flows)
│ ├── duoadmin/ # Duo Admin API client
│ └── saml/ # SAML request/response handling
├── .github/workflows/ # CI/CD pipelines
├── .goreleaser.yml # Multi-platform build automation
├── Dockerfile # Local development builds
├── Dockerfile.goreleaser # CI/CD optimized builds
├── CONTRIBUTING.md # Development guidelines
└── config.yaml.example # Configuration template
- Contributing — Development workflow and standards
- Config Examples — Full configuration schema
This toolkit is designed for testing and demonstration purposes in non-production environments.
Security features for test environments:
- Config Encryption: Optional AES-256-GCM for secrets at rest
- Non-root Container: Runs as UID 1000 in Docker
- Secret Management: Supports environment variables
- Volume Isolation: Docker volumes keep credentials separate from host
Important: Use dedicated test credentials and non-production Duo environments. For production Duo deployments, implement Duo's SDKs and integrations directly in your applications.
Reporting vulnerabilities: Open a GitHub issue.
# Verify port isn't in use
lsof -i :8080
# Check Docker logs
docker compose logs -f
# Test health check
docker exec duo-uet wget -O- http://127.0.0.1:8080/# Remove volume and start over
docker compose down -v
docker compose up -d
# Or with docker run
docker volume rm duo-uet-data
docker volume create duo-uet-dataSee CHANGELOG.md for detailed version history and GitHub Releases for release notes.
Contributions are welcome! Whether it's bug reports, feature requests, or code contributions, we'd love your help.
- 🐛 Report bugs — Open an issue
- 💡 Suggest features — Start a discussion
- 📝 Improve docs — Help make documentation clearer
- 🔧 Submit PRs — Fix bugs or add features
See CONTRIBUTING.md for development setup and guidelines.
This project is licensed under the MIT License — see the LICENSE file for details.
Third-party dependencies are subject to their own licenses — see THIRD_PARTY_NOTICES.md for details.
Built for Customer Success Engineers and technical teams

