Modern Python library for HTTP security headers with safe defaults, configurable presets, and first-class ASGI/WSGI middleware (FastAPI, Django, Flask, Shiny, and more).
See the codeDefine HTTP security headers once. Apply them consistently across Python web apps.
secure provides a small, dependency-free API for configuring modern security headers across common Python web frameworks through ASGI middleware, WSGI middleware, or framework response hooks.
Use it when you want to avoid copy-pasted header strings spread across handlers, hooks, and middleware.
Quick links: Quick start · Headers · Middleware
secureSetting headers manually is fine for one endpoint. It gets harder to review when values are copied across routes, response hooks, reverse-proxy settings, and different framework integrations.
secure helps you:
Secure policy object instead of scattered header stringsThe defaults are a reasonable starting point, not a substitute for application-specific review. Content Security Policy in particular should be adjusted for the scripts, styles, assets, and third-party services your app actually uses.
uv add secure
# or
pip install secure
Use middleware when you can attach secure once and cover the whole application.
from fastapi import FastAPI
from secure import Secure
from secure.middleware import SecureASGIMiddleware
app = FastAPI()
secure_headers = Secure.with_default_headers()
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
Use the same policy object in framework hooks, middleware callbacks, or handlers that expose a response object with headers support.
from secure import Secure
secure_headers = Secure.with_default_headers()
secure_headers.set_headers(response)
# or
await secure_headers.set_headers_async(response)
Secure.with_default_headers() maps to Preset.BALANCED, a practical default designed to be customized.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
Content-Security-Policy: default-src 'self'; base-uri 'self'; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src 'self'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; upgrade-insecure-requests
Strict-Transport-Security: max-age=31536000; includeSubDomains
Permissions-Policy: geolocation=(), microphone=(), camera=()
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
This preset reflects modern browser guidance from MDN and OWASP. It reduces cross-origin risk, prevents MIME sniffing, and provides a conservative Content Security Policy you can extend.
The default CSP avoids unsafe script execution by default, but CSP is context-sensitive. Interactive apps, dashboards, CDNs, analytics, embedded content, or other third-party integrations may require additional configuration.
from secure import Preset, Secure
Secure.from_preset(Preset.BALANCED)
Secure.from_preset(Preset.BASIC)
Secure.from_preset(Preset.STRICT)
Start with BALANCED, review the generated headers, and move stricter only when needed.
secure provides both ASGI and WSGI middleware.
multi_okfrom secure import Secure
from secure.middleware import SecureASGIMiddleware
secure_headers = Secure.with_default_headers()
app = SecureASGIMiddleware(app, secure=secure_headers)
from secure import Secure
from secure.middleware import SecureWSGIMiddleware
secure_headers = Secure.with_default_headers()
app = SecureWSGIMiddleware(app, secure=secure_headers)
from secure import Secure
class SecureHeadersMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.secure = Secure.with_default_headers()
def __call__(self, request):
response = self.get_response(request)
self.secure.set_headers(response)
return response
These examples show common integration paths. See the full framework integration guide for additional frameworks and notes about first-class middleware versus minimal fallback examples.
from secure.middleware import SecureASGIMiddleware
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
@app.after_request
def add_security_headers(response):
secure_headers.set_headers(response)
return response
from shiny import App
from secure.middleware import SecureASGIMiddleware
app = SecureASGIMiddleware(App(), secure=secure_headers)
Interactive apps often need CSP configuration for their script, style, and asset loading patterns.
from secure.headers import ContentSecurityPolicy
csp = (
ContentSecurityPolicy()
.default_src("'self'")
.script_src("'self'", "cdn.example.com")
)
from secure.headers import PermissionsPolicy
permissions = (
PermissionsPolicy()
.geolocation("'self'")
.camera("'none'")
)
Use the optional pipeline when you need stricter control:
secure_headers = (
Secure.with_default_headers()
.allowlist_headers(...)
.deduplicate_headers(...)
.validate_and_normalize_headers(...)
)
This makes header allowlists, deduplication, normalization, and validation explicit instead of leaving those choices spread across application code.
Read the full documentation.
MIT License
Issues and pull requests are welcome.
Built using guidance from MDN and OWASP secure headers recommendations.
Overall
Maintained
Code review
PyPI
Latest release
Releases this year
3,543 followers · starred Oct 2025
4,002 followers · starred Dec 2018
122 followers · starred May 2026
2,324 followers · starred Dec 2018
Modern Python library for HTTP security headers with safe defaults, configurable presets, and first-class ASGI/WSGI middleware (FastAPI, Django, Flask, Shiny, and more).
See the codeDefine HTTP security headers once. Apply them consistently across Python web apps.
secure provides a small, dependency-free API for configuring modern security headers across common Python web frameworks through ASGI middleware, WSGI middleware, or framework response hooks.
Use it when you want to avoid copy-pasted header strings spread across handlers, hooks, and middleware.
Quick links: Quick start · Headers · Middleware
secureSetting headers manually is fine for one endpoint. It gets harder to review when values are copied across routes, response hooks, reverse-proxy settings, and different framework integrations.
secure helps you:
Secure policy object instead of scattered header stringsThe defaults are a reasonable starting point, not a substitute for application-specific review. Content Security Policy in particular should be adjusted for the scripts, styles, assets, and third-party services your app actually uses.
uv add secure
# or
pip install secure
Use middleware when you can attach secure once and cover the whole application.
from fastapi import FastAPI
from secure import Secure
from secure.middleware import SecureASGIMiddleware
app = FastAPI()
secure_headers = Secure.with_default_headers()
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
Use the same policy object in framework hooks, middleware callbacks, or handlers that expose a response object with headers support.
from secure import Secure
secure_headers = Secure.with_default_headers()
secure_headers.set_headers(response)
# or
await secure_headers.set_headers_async(response)
Secure.with_default_headers() maps to Preset.BALANCED, a practical default designed to be customized.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
Content-Security-Policy: default-src 'self'; base-uri 'self'; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src 'self'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; upgrade-insecure-requests
Strict-Transport-Security: max-age=31536000; includeSubDomains
Permissions-Policy: geolocation=(), microphone=(), camera=()
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
This preset reflects modern browser guidance from MDN and OWASP. It reduces cross-origin risk, prevents MIME sniffing, and provides a conservative Content Security Policy you can extend.
The default CSP avoids unsafe script execution by default, but CSP is context-sensitive. Interactive apps, dashboards, CDNs, analytics, embedded content, or other third-party integrations may require additional configuration.
from secure import Preset, Secure
Secure.from_preset(Preset.BALANCED)
Secure.from_preset(Preset.BASIC)
Secure.from_preset(Preset.STRICT)
Start with BALANCED, review the generated headers, and move stricter only when needed.
secure provides both ASGI and WSGI middleware.
multi_okfrom secure import Secure
from secure.middleware import SecureASGIMiddleware
secure_headers = Secure.with_default_headers()
app = SecureASGIMiddleware(app, secure=secure_headers)
from secure import Secure
from secure.middleware import SecureWSGIMiddleware
secure_headers = Secure.with_default_headers()
app = SecureWSGIMiddleware(app, secure=secure_headers)
from secure import Secure
class SecureHeadersMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.secure = Secure.with_default_headers()
def __call__(self, request):
response = self.get_response(request)
self.secure.set_headers(response)
return response
These examples show common integration paths. See the full framework integration guide for additional frameworks and notes about first-class middleware versus minimal fallback examples.
from secure.middleware import SecureASGIMiddleware
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
@app.after_request
def add_security_headers(response):
secure_headers.set_headers(response)
return response
from shiny import App
from secure.middleware import SecureASGIMiddleware
app = SecureASGIMiddleware(App(), secure=secure_headers)
Interactive apps often need CSP configuration for their script, style, and asset loading patterns.
from secure.headers import ContentSecurityPolicy
csp = (
ContentSecurityPolicy()
.default_src("'self'")
.script_src("'self'", "cdn.example.com")
)
from secure.headers import PermissionsPolicy
permissions = (
PermissionsPolicy()
.geolocation("'self'")
.camera("'none'")
)
Use the optional pipeline when you need stricter control:
secure_headers = (
Secure.with_default_headers()
.allowlist_headers(...)
.deduplicate_headers(...)
.validate_and_normalize_headers(...)
)
This makes header allowlists, deduplication, normalization, and validation explicit instead of leaving those choices spread across application code.
Read the full documentation.
MIT License
Issues and pull requests are welcome.
Built using guidance from MDN and OWASP secure headers recommendations.
Overall
Maintained
Code review
PyPI
Latest release
Releases this year
3,543 followers · starred Oct 2025
4,002 followers · starred Dec 2018
122 followers · starred May 2026
2,324 followers · starred Dec 2018