AnnouncementsIntroducing Arkoren

    Menu

    Grant explicit cross-origin browser response access and handle preflights without confusing CORS with request authorization.

    What's on this page
    1. Allow a known front end's origin, methods, and headers without treating CORS as authorization.
    2. Answer preflights before authentication and control their advertised cache lifetime.
    3. Enable cookie credentials and readable response metadata deliberately.
    4. Distinguish public defaults, explicit empty lists, and malformed origin failures.
    On this page

    A portal at https://portal.example.com cannot normally read responses from https://api.example.com. Cross-Origin Resource Sharing (CORS) lets the API grant that browser access with response headers. An origin consists of a scheme, host, and optional port; changing any of them changes the origin.

    CORS is a browser response-access policy, not authentication or a write barrier. Disallowed origins can still reach your handlers without CORS permission headers. Keep authentication, resource authorization, and CSRF protection where cookies authorize actions.

    Allow a Front End

    For a portal that reads account details and sends JSON changes with a bearer token, allow its exact origin, methods, and request headers. Import net/http and arkoren.dev/core/http/middleware/cors. On a fresh API router routes, register this before authentication, body checks, and routes:

    routes.Use(cors.Middleware(func(policy *cors.Builder) {
    	policy.AllowedOrigins("https://portal.example.com")
    	policy.AllowedMethods(http.MethodGet, http.MethodPatch)
    	policy.AllowedHeaders("Content-Type", "Authorization")
    }))

    Requests with that Origin receive permission headers. Authorization must be listed when browser code supplies a bearer token; listing it does not validate the token. The policy applies to every route on this router, including unmatched requests, so the portal can read eligible error responses too. Choose narrower group scope if only part of the API shares the policy.

    Use bare ASCII origins, without a trailing slash. Construction panics for missing schemes or hostnames, userinfo, paths (including /), query or fragment delimiters (including empty ? or #), wildcard host patterns, and invalid or empty ports. Decimal ports must be in 0–65535; international hostnames need ASCII punycode. Only the complete * wildcard is supported.

    Configured origins are lowercased, not fully canonicalized. For example, https://portal.example.com:443 does not match a browser’s https://portal.example.com. Configure the spelling the browser sends in Origin; this validation is not a general URL sanitizer.

    Handle Preflights

    Before a cross-origin JSON PATCH, the browser asks whether the API permits the method and headers. This preflight is an OPTIONS request with Origin and Access-Control-Request-Method:

    OPTIONS /account/preferences HTTP/1.1
    Host: api.example.com
    Origin: https://portal.example.com
    Access-Control-Request-Method: PATCH
    Access-Control-Request-Headers: authorization, content-type

    For an allowed origin, the middleware answers 204 No Content without calling the next layer. It advertises your configured method and header lists; the browser checks those lists before sending the actual request. A 204 alone does not mean the requested method or headers were approved.

    Requests without Origin, requests from disallowed origins, and ordinary OPTIONS requests without Access-Control-Request-Method continue to the next layer. Allowed non-preflight requests also continue. CORS does not reject an ordinary request because its method is absent from AllowedMethods.

    Preflights arrive without credentials, so CORS must precede authentication. Otherwise an authentication failure can stop the browser before it sends its authenticated request. See policy ordering. Non-browser clients do not enforce these permission headers.

    Preflight answers default to Access-Control-Max-Age: 300, allowing five minutes of caching, subject to browser limits. To disable this advertised cache lifetime, add policy.MaxAge(0) to the construction callback. Positive durations are rounded down to whole seconds: 1500*time.Millisecond sends 1. Nonpositive durations and positive durations below one second omit the header; import time when using duration expressions.

    Send Credentials

    If the portal uses session cookies instead of bearer tokens, explicitly allow credentials for that trusted origin. Replace the previous registration with this cookie-backed variant:

    routes.Use(cors.Middleware(func(policy *cors.Builder) {
    	policy.AllowedOrigins("https://portal.example.com")
    	policy.AllowedMethods(http.MethodGet, http.MethodPatch)
    	policy.AllowedHeaders("Content-Type")
    	policy.AllowCredentials(true)
    }))

    Credentials are off by default. Combining AllowCredentials(true) with any * origin entry panics at construction. Never replace a trusted origin list with arbitrary reflection of the request’s origin.

    Browser code must also opt in to credentials, for example with fetch(url, { credentials: "include" }). Cookie SameSite, Secure, and browser privacy rules still apply; CORS does not override them. Configure session cookies appropriately and retain CSRF protection, with a trusted origin for intentional cross-origin writes. Trusting an origin for response access neither authenticates its visitors nor authorizes their account changes.

    Expose Metadata

    If the portal displays an API request ID for support, allow script access to that response header. This separate construction example assumes your server already sets X-Request-ID:

    routes.Use(cors.Middleware(func(policy *cors.Builder) {
    	policy.AllowedOrigins("https://portal.example.com")
    	policy.ExposedHeaders("X-Request-ID")
    }))

    ExposedHeaders names response headers beyond the browser’s basic readable set; it does not create their values. Include the method, request-header, and credential settings from your chosen policy when combining these examples. With an explicit origin list, responses vary on Origin, including requests without that header. Recognized allowed preflights also vary on requested method and headers, so shared caches can distinguish permission answers.

    Refine Defaults

    Use cors.Middleware() without configuration only when you intend public cross-origin response access without credentials. It allows *, advertises GET, POST, and HEAD, and allows request headers Accept and Content-Type. No extra response headers are exposed by default.

    List setters replace earlier lists. After all callbacks run, omitted or nil origin, method, and request-header lists receive defaults; nonnil empty lists remain empty. To grant no origins explicitly:

    routes.Use(cors.Middleware(func(policy *cors.Builder) {
    	policy.AllowedOrigins([]string{}...)
    }))

    That omits origin permission but still passes requests onward. In contrast, policy.AllowedOrigins() supplies nil and restores the wildcard default. The same distinction applies to AllowedMethods and AllowedHeaders: explicit empty lists omit their preflight headers. Configuration lists are copied during construction, and validation uses the final settings after all callbacks.

    For every setting, see the cors API reference.

    Open a bulk documentation archive?

    This file contains every guide in its scope, not API declarations. Loading it all into an agent can exhaust its context window and increase processing time and cost. For coding tasks, start with the index and read only the relevant pages.

    Use the full archive for offline indexing, bulk processing, or deliberate large-context use.

    Browse the index instead
    Open archive