initiate keycloak token checking

This commit is contained in:
renaldybrada
2026-02-13 15:43:05 +07:00
parent 4bc1ba94e5
commit b5b4763b45
5 changed files with 92 additions and 2 deletions
+7 -1
View File
@@ -29,4 +29,10 @@ DB_ANTRIAN_PASSWORD=stim*RS54
DB_ANTRIAN_HOST=10.10.123.165
DB_ANTRIAN_DATABASE=satu_db
DB_ANTRIAN_PORT=5000
DB_ANTRIAN_SSLMODE=disable
DB_ANTRIAN_SSLMODE=disable
#KEYCLOAK CREDENTIAL
KEYCLOAK_BASE_URL=https://keycloak.example.com
KEYCLOAK_REALM=myrealm
KEYCLOAK_AUDIENCE=my-client-id
KEYCLOAK_ISSUER=https://keycloak.example.com/realms/myrealm
+2
View File
@@ -5,6 +5,7 @@ go 1.25.3
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/MicahParks/keyfunc v1.9.0 // indirect
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
@@ -21,6 +22,7 @@ require (
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
+4
View File
@@ -3,6 +3,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
@@ -45,6 +47,8 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+72
View File
@@ -0,0 +1,72 @@
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
}
+7 -1
View File
@@ -12,6 +12,7 @@ import (
"antrian-operasi/internal/domain/reference/spesialis"
"antrian-operasi/internal/domain/reference/tindakan"
"antrian-operasi/internal/middleware"
"log"
"net/http"
"github.com/gin-gonic/gin"
@@ -34,7 +35,12 @@ func RegisterRoutes(cfg *config.Config, dbService database.Service) *gin.Engine
// init middleware
router.Use(middleware.SecureCORSConfig(cfg.Security))
api := router.Group("/api")
authKeycloak, err := middleware.AuthKeycloak()
if err != nil {
log.Fatalf("Unable to initiate keycloak auth")
}
api := router.Group("/api", authKeycloak)
antrian := api.Group("/antrian-operasi")
{