Hi there! I'm Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.
Securing your API is non-negotiable. Whether you're building public or internal services, unprotected endpoints can expose your system to data theft, misuse, or even total compromise.
This guide outlines essential API security principles, with practical Go code snippets using the Echo web framework where applicable.
1. Use Proper HTTP Methods
Only allow HTTP methods appropriate for each endpoint. Respond with 405 Method Not Allowed
for disallowed methods.
e := echo.New()
// Proper usage
e.GET("/users/:id", getUser)
e.POST("/users", createUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
// Middleware to handle unsupported methods
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
allowedMethods := map[string][]string{
"/users": {"POST"},
"/users/:id": {"GET", "PUT", "DELETE"},
}
route := c.Path()
method := c.Request().Method
for path, methods := range allowedMethods {
if echo.NewRouter().Find(method, path, c) != nil {
return next(c)
}
if path == route {
return echo.NewHTTPError(http.StatusMethodNotAllowed, "Method Not Allowed")
}
}
return next(c)
}
})
2. Content-Type Validation
Validate the Content-Type
header. Expect application/json
for JSON APIs.
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if c.Request().Method == http.MethodPost || c.Request().Method == http.MethodPut {
if c.Request().Header.Get(echo.HeaderContentType) != echo.MIMEApplicationJSON {
return echo.NewHTTPError(http.StatusUnsupportedMediaType, "Only application/json allowed")
}
}
return next(c)
}
})
3. Validate User Input
Use input validation to prevent injection attacks and ensure data integrity.
type CreateUserInput struct {
Name string `json:"name" validate:"required,min=3"`
Email string `json:"email" validate:"required,email"`
}
func createUser(c echo.Context) error {
var input CreateUserInput
if err := c.Bind(&input); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid request")
}
if err := c.Validate(&input); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// Proceed safely
return c.JSON(http.StatusOK, map[string]string{"status": "user created"})
}
To enable validation:
import "github.com/go-playground/validator/v10"
type CustomValidator struct {
validator *validator.Validate
}
func (cv *CustomValidator) Validate(i interface{}) error {
return cv.validator.Struct(i)
}
e.Validator = &CustomValidator{validator: validator.New()}
4. Use Authorization Header for Tokens
Tokens should be sent in the standard Authorization: Bearer <token>
header—not in query parameters.
func tokenAuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
auth := c.Request().Header.Get("Authorization")
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing or invalid Authorization header")
}
token := strings.TrimPrefix(auth, "Bearer ")
if !validateToken(token) {
return echo.NewHTTPError(http.StatusUnauthorized, "Invalid token")
}
return next(c)
}
}
Avoid this:
GET /api/data?token=abc123 ❌
5. Avoid Client-Side Encryption
Don’t rely on client-side encryption for sensitive data. Encrypt on the server side using robust libraries.
// Example: AES encryption
func encryptAES(plaintext, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
plaintextBytes := []byte(plaintext)
ciphertext := make([]byte, aes.BlockSize+len(plaintextBytes))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintextBytes)
return base64.URLEncoding.EncodeToString(ciphertext), nil
}
Keep keys and secrets on the server, never in the client-side code.
6. Use an API Gateway
Use tools like Kong, Traefik, or AWS API Gateway for enhanced security features:
- JWT validation
- IP whitelisting
- Rate limiting
- Request logging
- TLS termination
Example: Kong Rate Limiting (declarative config)
services:
- name: my-api
url: http://myapi:8000
routes:
- name: my-api-route
paths:
- /v1/
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
Final Tips
- Always use HTTPS (TLS) to encrypt data in transit.
- Enable logging and alerting for abnormal traffic.
- Keep dependencies updated to patch known vulnerabilities.
- Run security headers like
X-Content-Type-Options: nosniff
.
TL;DR Checklist
Security Feature | Status |
---|---|
Proper HTTP methods | ✅ |
Content-Type validation | ✅ |
Input validation | ✅ |
Token via Authorization
|
✅ |
No client-side encryption | ✅ |
API gateway used | ✅ |
API security is not a luxury — it’s a baseline. Build secure by default, and save yourself from firefighting later.
LiveAPI helps you get all your backend APIs documented in a few minutes.
With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.
If you're tired of updating Swagger manually or syncing Postman collections, give it a shot.
Top comments (0)