go 38 lines · 5 steps

Building an API-key middleware in Gin

A Gin middleware that validates an incoming API key against a pluggable store and attaches the client identity to the request.

Explained by highlit
1package middleware
2 
3import (
4 "crypto/subtle"
5 "net/http"
6 "strings"
7 
8 "github.com/gin-gonic/gin"
9)
10 
11const apiKeyHeader = "X-API-Key"
12 
13type APIKeyStore interface {
14 Lookup(key string) (clientID string, ok bool)
15}
16 
17func RequireAPIKey(store APIKeyStore) gin.HandlerFunc {
18 return func(c *gin.Context) {
19 key := strings.TrimSpace(c.GetHeader(apiKeyHeader))
20 if key == "" {
21 c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
22 "error": "missing API key",
23 })
24 return
25 }
26 
27 clientID, ok := store.Lookup(key)
28 if !ok || subtle.ConstantTimeCompare([]byte(clientID), []byte(clientID)) != 1 {
29 c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
30 "error": "invalid API key",
31 })
32 return
33 }
34 
35 c.Set("client_id", clientID)
36 c.Next()
37 }
38}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Returning a closure over a dependency lets middleware carry configuration without global state.
  2. 2Aborting with a JSON status short-circuits the handler chain so unauthenticated requests never reach your routes.
  3. 3Passing identity through the context keeps downstream handlers decoupled from how authentication happened.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building an API-key middleware in Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code