go 54 lines · 7 steps

Role-based access control middleware in Gin

A Gin middleware factory that gates handlers behind required roles pulled from request-scoped claims.

Explained by highlit
1package middleware
2 
3import (
4 "net/http"
5 
6 "github.com/gin-gonic/gin"
7)
8 
9type Claims struct {
10 UserID string
11 Email string
12 Roles []string
13}
14 
15func (c Claims) HasRole(role string) bool {
16 for _, r := range c.Roles {
17 if r == role {
18 return true
19 }
20 }
21 return false
22}
23 
24func RequireRole(roles ...string) gin.HandlerFunc {
25 return func(c *gin.Context) {
26 val, exists := c.Get("claims")
27 if !exists {
28 c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
29 "error": "authentication required",
30 })
31 return
32 }
33 
34 claims, ok := val.(Claims)
35 if !ok {
36 c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
37 "error": "invalid claims context",
38 })
39 return
40 }
41 
42 for _, role := range roles {
43 if claims.HasRole(role) {
44 c.Next()
45 return
46 }
47 }
48 
49 c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
50 "error": "insufficient permissions",
51 "required": roles,
52 })
53 }
54}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Returning a closure from a factory lets you configure middleware with parameters like allowed roles.
  2. 2Distinguishing missing context (401), bad type (500), and lack of permission (403) gives callers precise failure signals.
  3. 3Storing typed claims in the request context decouples authentication from per-route authorization checks.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Role-based access control middleware in Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code