package middleware import ( "fmt" "log" "net/http" "os" "strings" "time" "github.com/MicahParks/keyfunc" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" ) func AuthKeycloak() (gin.HandlerFunc, error) { baseURL := os.Getenv("KEYCLOAK_BASE_URL") realm := os.Getenv("KEYCLOAK_REALM") audience := os.Getenv("KEYCLOAK_AUDIENCE") issuer := os.Getenv("KEYCLOAK_ISSUER") jwksURL := fmt.Sprintf( "%s/realms/%s/protocol/openid-connect/certs", baseURL, realm, ) jwks, err := keyfunc.Get(jwksURL, keyfunc.Options{ RefreshInterval: time.Hour, RefreshErrorHandler: func(err error) { fmt.Println("JWKS refresh error:", err) }, }) if err != nil { return nil, err } return func(c *gin.Context) { auth := c.GetHeader("Authorization") if auth == "" { c.AbortWithStatusJSON(401, gin.H{"message": "missing token"}) return } tokenStr := strings.TrimPrefix(auth, "Bearer ") token, err := jwt.Parse(tokenStr, jwks.Keyfunc) if err != nil || !token.Valid { c.AbortWithStatusJSON(401, gin.H{"message": err.Error()}) return } claims := token.Claims.(jwt.MapClaims) log.Println(claims) // validate issuer if claims["iss"] != issuer { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid issuer"}) return } // validate audience if !claims.VerifyAudience(audience, true) { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid audience"}) return } c.Set("claims", claims) c.Next() }, nil }