Skip to content
Kona

CORS and security headers

Two complementary middleware classes in org.konaframework:kona-auth harden HTTP responses:

  • CORS (CorsMiddleware) — tell browsers which other origins may call your API with cookies or custom headers.
  • Security headers (SecurityHeadersMiddleware) — attach headers that reduce clickjacking, MIME sniffing, and related risks.

Neither replaces authentication, CSRF, or rate limiting; they constrain how browsers treat responses.

import org.konaframework.http.HttpKernel
import org.konaframework.security.CorsConfig
import org.konaframework.security.CorsMiddleware
val cors = CorsMiddleware(
CorsConfig(
allowedOrigins = listOf("https://app.example.com"),
allowedMethods = listOf("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"),
allowedHeaders = listOf("Content-Type", "Authorization", "X-Requested-With"),
allowCredentials = true,
maxAgeSeconds = 600,
),
)
app.resolve(HttpKernel::class.java).pushMiddleware(cors)

Defaults (no-arg CorsConfig()): origins *, common methods, headers *, credentials off, max-age 600 seconds.

  1. Preflight — OPTIONS with Origin + Access-Control-Request-Method short-circuits with 204 and CORS headers (handler not run).
  2. Other requests — the pipeline runs; CORS headers are applied to the response.
Config field Effect
allowedOrigins Exact origin match, or * (with credentials, * echoes the request origin)
allowedMethods Access-Control-Allow-Methods
allowedHeaders Fixed list, or * (reflect request headers / sensible default)
exposedHeaders Access-Control-Expose-Headers when non-empty
allowCredentials Sets Access-Control-Allow-Credentials: true
maxAgeSeconds Access-Control-Max-Age

When the allowed origin is not *, responses also get Vary: Origin (merged with any existing Vary).

import org.konaframework.security.SecurityHeadersConfig
import org.konaframework.security.SecurityHeadersMiddleware
val headers = SecurityHeadersMiddleware(
SecurityHeadersConfig(
xContentTypeOptions = "nosniff",
xFrameOptions = "SAMEORIGIN",
referrerPolicy = "no-referrer-when-downgrade",
xXssProtection = "0",
// permissionsPolicy = "geolocation=()",
// strictTransportSecurity = "max-age=31536000; includeSubDomains",
// contentSecurityPolicy = "default-src 'self'",
// custom = mapOf("X-App" to "kona"),
),
)
app.resolve(HttpKernel::class.java).pushMiddleware(headers)

Any config field set to null skips that header. Defaults enable X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and X-XSS-Protection as shown above. Enable HSTS only behind HTTPS.

Push outer concerns first (they wrap later middleware):

  1. CorsMiddleware — handle preflight early
  2. SecurityHeadersMiddleware — tag every response
  3. StartSession / CSRF / auth / throttle — application logic

Order among CORS and security headers is flexible; keep session and CSRF inside the cookie/session path as documented on those pages.