Protect Your Documentation
Never expose internal API documentation publicly in production. Use DocsAuth to require authentication before serving the Scalar UI and the OpenAPI spec.
docs := openswag.New(openswag.Config{
Info: openswag.Info{
Title: "Internal API",
Version: "1.0.0",
},
DocsAuth: &openswag.DocsAuth{
Enabled: true,
Username: os.Getenv("DOCS_USER"),
Password: os.Getenv("DOCS_PASS"),
},
})If the environment variables are missing in some environment, Enabled: true with no credentials makes every docs request fail with HTTP 500 DocsAuth enabled but no credentials configured (v1.3.0+), so the mistake is visible instead of looking like a wrong password.
Use Environment Variables for Credentials
Never hardcode usernames, passwords, or API keys in your source code. Always read them from environment variables or a secrets manager.
// Good
auth := &openswag.DocsAuth{
Enabled: true,
Username: os.Getenv("DOCS_USER"),
Password: os.Getenv("DOCS_PASS"),
}
// Bad — never do this
auth := &openswag.DocsAuth{
Enabled: true,
Username: "admin",
Password: "secret123",
}Credential Persistence
Tokens and keys entered in the docs UI's auth playground are handled client-side by Scalar; open-swag-go never receives or stores them, and it has no setting that controls how Scalar keeps them. AuthConfig.PersistCredentials exists but currently has no effect: it is not passed to Scalar.
For docs reachable by untrusted users, assume credentials typed into the page may stay in that browser. Prefer short-lived tokens for testing, and protect the docs themselves with DocsAuth when they should not be public.
CORS Configuration
There are two separate CORS concerns, and open-swag-go only controls the first one.
The spec endpoint. SpecHandler (and Mount) send Access-Control-Allow-Origin: * on openapi.json by default. In v1.3.0+, restrict it with UIConfig.SpecCORSOrigin: an explicit origin is sent as-is, and "-" omits the header entirely (enough when the docs UI and the spec are served from the same origin).
docs := openswag.New(openswag.Config{
Info: openswag.Info{
Title: "My API",
Version: "1.0.0",
},
UI: openswag.UIConfig{
SpecCORSOrigin: "https://app.example.com", // "" = "*", "-" = no header
},
})Your API. The try-it console is part of the Scalar UI and calls your API directly from the browser. If the API and the docs are on different origins, configure CORS on the API server; open-swag-go has no CORS proxy setting.
import "github.com/rs/cors"
c := cors.New(cors.Options{
AllowedOrigins: []string{"https://docs.example.com"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowedHeaders: []string{"Authorization", "Content-Type"},
})
handler := c.Handler(router)CORS Checklist
- Set specific allowed origins instead of
* - Restrict allowed methods to what your API actually uses
- Set
Access-Control-Max-Ageto reduce preflight requests - Never expose sensitive headers in
Access-Control-Expose-Headers
API Key Protection
For machine-to-machine access to your docs, use API key authentication. The key is passed as the ?key= query parameter, so it can end up in access logs and browser history:
docs := openswag.New(openswag.Config{
Info: openswag.Info{
Title: "Partner API",
Version: "1.0.0",
},
DocsAuth: &openswag.DocsAuth{
Enabled: true,
APIKey: os.Getenv("DOCS_API_KEY"), // access with /docs/?key=...
},
})Summary
| Practice | Recommendation |
|---|---|
| Docs authentication | Always enable in production |
| Credentials | Use environment variables |
| Credential persistence | Disable for public environments |
| CORS | Use specific origins, not wildcards |
| API keys | Rotate regularly, store in secrets manager |