Host Swagger UI Behind Company Auth (Without Cloudflare Access)
Internal API documentation shouldn't be public. Your API endpoints, authentication flows, request/response schemas, and error codes are internal information — useful to your engineers, valuable to anyone trying to revers
The problem
Internal API documentation shouldn't be public. Your API endpoints, authentication flows, request/response schemas, and error codes are internal information — useful to your engineers, valuable to anyone trying to reverse-engineer your product.
The standard approaches to protecting it are expensive or complex:
- Nginx behind VPN: Requires every API consumer to be on the VPN. Mobile developers, remote contractors, and teams on different network segments all hit friction.
- Cloudflare Pages + Access: ~$700/month for 100 users. 2–4 hours of setup. Per-seat pricing punishes broad access.
- Azure Static Web Apps: Free tier is Microsoft-only. Standard tier requires Azure expertise.
- Self-hosted Swagger UI behind HTTP basic auth: A shared password. Not identity-aware. Anyone with the password can share it.
Display: generate a static Swagger UI bundle → publish it → company-gated URL.
Generate a static Swagger UI file
From an OpenAPI spec file:
npm install swagger-ui-dist
node -e "
const fs = require('fs');
const path = require('path');
const swaggerUiDist = require('swagger-ui-dist');
const spec = JSON.parse(fs.readFileSync('./openapi.json', 'utf8'));
const html = \`<!DOCTYPE html>
<html>
<head>
<title>API Documentation</title>
<link rel='stylesheet' type='text/css' href='https://unpkg.com/swagger-ui-dist/swagger-ui.css'>
</head>
<body>
<div id='swagger-ui'></div>
<script src='https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js'></script>
<script>
SwaggerUIBundle({
spec: \${JSON.stringify(spec)},
dom_id: '#swagger-ui',
presets: [SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset],
layout: 'StandaloneLayout'
})
</script>
</body>
</html>\`;
fs.writeFileSync('./api-docs.html', html);
" Or use Redoc (simpler for read-only documentation):
npx @redocly/cli build-docs openapi.json -o api-docs.htmlPublish with Display
dsp publish ./api-docs.html --name "internal-api-docs"Share the URL in your onboarding docs, Notion, or Slack. Engineers authenticate with their company email and see the full interactive API reference — try-it-out, request/response schemas, authentication flows.
Auto-update when the spec changes
name: Publish API Docs
on:
push:
branches: [main]
paths: ['openapi.json', 'openapi.yaml']
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate Swagger UI
run: npx @redocly/cli build-docs openapi.json -o api-docs.html
- name: Publish docs
run: |
npm install -g @display-dev/cli
dsp publish ./api-docs.html --name "internal-api-docs"
env:
DISPLAYDEV_API_KEY: ${{ secrets.DISPLAYDEV_API_KEY }}Every time openapi.json changes on main, the published API docs update automatically. The URL stays the same.
Comparison
| Nginx + VPN | Cloudflare Pages + Access | Display | |
|---|---|---|---|
| Monthly cost | $50+ VPS + maintenance | ~$700 (100 users) | $49 |
| Setup time | Hours | 2–4 hours | 15 min |
| Requires VPN client | ✅ | ❌ | ❌ |
| Company identity auth | ✅ (via LDAP/VPN) | ✅ | ✅ |
| Google + Microsoft SSO | ✅ (with config) | ✅ | ✅ |
| Maintenance | High | Medium | None |
FAQ
Can I password-protect Swagger UI instead?
Swagger UI doesn't have built-in auth. You can add HTTP basic auth at the server level (Nginx, Apache), but that's a shared password — not identity-aware. Anyone who has the password can share it, and there's no per-user audit trail.
Does this work with OpenAPI 3.1?
Yes. Both Swagger UI and Redoc support OpenAPI 3.1. Generate the HTML bundle from your spec file and publish it — Display serves whatever HTML you provide.
Can I restrict API docs to specific teams within the company?
Not yet at the subdomain level — the current access model is domain-based (all @yourcompany.com emails get access). For team-level restrictions, you can create separate artifacts per team and share only the relevant URL with each audience.
Free tier. No credit card. One-time password auth for viewers on free, Google + Microsoft SSO on Teams ($49/month flat).