Learning Fiber - CSRF, CORS, and Security
Series/Learn Fiber/Episode 18
Episode 18 of 23

Learning Fiber - CSRF, CORS, and Security

This episode covers web security in Fiber v3: the csrf middleware with KeyLookup and cookie configuration, the cors middleware with AllowOrigins and credentials, and combined practices for protecting APIs from cross-site attacks.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

The web has threats inherent to how it works: other sites can exploit a user's browser to send unwanted requests. Episode 18 covers two middleware that protect against these threats — CSRF and CORS — and how to combine them.

CSRF prevents malicious sites from forcing the browser to send harmful requests to your application; CORS controls which sites are allowed to read responses. Both are essential to understand when building APIs consumed by browsers.

The CSRF Middleware

Basic Setup

csrf.New() protects state mutations (POST, PUT, DELETE) with a per-session token:

CSRF dasar
app.Use(csrf.New())

Without configuration, the middleware creates a CSRF token, stores it in a cookie, and validates subsequent requests. If the request carries a matching token, it passes; if not, an error is returned. Tokens are generated randomly per visitor and must be sent again on every mutation.

KeyLookup and Tokens

By default the token is read from the X-CSRF-Token header. Change the token source with KeyLookup:

Mengatur sumber token
app.Use(csrf.New(csrf.Config{
    KeyLookup: "header:X-CSRF-Token",
    ErrorHandler: func(c fiber.Ctx, err error) error {
        return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
            "error": "token CSRF tidak valid",
        })
    },
}))

KeyLookup: "header:X-CSRF-Token" means the token is expected in that header. The source:key format also supports cookie:csrf or form:csrf. ErrorHandler changes the default response to JSON — important for consistency with your API.

The cookie that stores the token also needs secure settings:

Cookie CSRF yang aman
app.Use(csrf.New(csrf.Config{
    CookieName: "csrf_token",
    CookieHTTPOnly: true,
    CookieSameSite: "Lax",
}))

CookieHTTPOnly: true prevents JavaScript from reading the token via document.cookie — reducing theft risk. CookieSameSite: "Lax" blocks cookie delivery on cross-site requests, closing the main CSRF vector. Enable CookieSecure in production so the cookie is only sent over HTTPS.

The CORS Middleware

Basic Setup

CORS controls which sites may read responses:

CORS dasar
app.Use(cors.New())

By default, all origins are allowed (AllowOrigins: "*"). This isn't safe for APIs holding sensitive data — every site could read the responses. For public APIs without cookie authentication, this default is sometimes acceptable; for other APIs, restrict origins explicitly.

AllowOrigins and Credentials

For production, register the allowed origins explicitly:

Batasi origin
app.Use(cors.New(cors.Config{
    AllowOrigins: "https://gofiber.io, https://gofiber.net",
    AllowHeaders: "Origin, Content-Type, Accept, Authorization",
    AllowMethods: "GET, POST, PUT, DELETE, OPTIONS",
}))

AllowOrigins accepts a comma-separated list of origins; anything else is answered without CORS headers. AllowHeaders and AllowMethods announce what may be sent. If clients use cookies with CORS, add AllowCredentials: true — and remember, AllowCredentials must not be used with a wildcard origin *.

AllowOriginsFunc

For a dynamic origin list — for example from a database — use AllowOriginsFunc:

Origin dinamis
app.Use(cors.New(cors.Config{
    AllowOriginsFunc: func(origin string) bool {
        return strings.HasSuffix(origin, ".myapp.example.com")
    },
}))

AllowOriginsFunc returns true for every matching origin. This example allows all subdomains of .myapp.example.com without registering them one by one — useful when tenants create new subdomains dynamically.

Combining Security Practices

Middleware Order

The installation order of middleware determines behavior. A recommended convention:

Stack keamanan
app.Use(recover.New())
app.Use(cors.New(cors.Config{AllowOrigins: "https://app.example.com"}))
app.Use(csrf.New())
 
api := app.Group("/api", jwtware.New(jwtware.Config{
    SigningKey: jwtware.SigningKey{Key: []byte(secret)},
}))

recover goes outermost so a panic doesn't kill the server; cors sets headers for all responses; csrf protects mutations; and JWT guards the /api area. CSRF is usually unnecessary for purely token-based APIs — choose by need: cookie-based sessions use CSRF, token-based use JWT.

Testing

Tes header keamanan
curl -i http://localhost:3000/
curl -i -H "Origin: https://evil.example.com" http://localhost:3000/api/data

The first request shows the CSRF header in the response. The second request from a foreign origin doesn't receive the Access-Control-Allow-Origin header — the browser will block reading the response. Try with a registered origin and compare the results.

Closing

Key takeaways:

  • csrf.New() protects mutations with a per-session token; by default the token is in the X-CSRF-Token header.
  • KeyLookup sets the token source: header:, cookie:, or form:.
  • Secure CSRF cookies: CookieHTTPOnly, CookieSameSite, and CookieSecure.
  • cors.New() allows all origins by default — restrict with AllowOrigins for production.
  • AllowCredentials: true must not be combined with a wildcard origin.
  • AllowOriginsFunc suits dynamic origin lists.
  • Combine the stack: recover → cors → csrf → (jwt per group).

In the next episode, episode 19, we discuss sessions and authentication — the session middleware with Redis/Memcache/MySQL storage, storing session data, and a complete authentication flow.