Skip to content

Commit 853cc00

Browse files
committed
feat(Logging): Added support for JWT user logging
1 parent c55032f commit 853cc00

File tree

6 files changed

+60
-3
lines changed

6 files changed

+60
-3
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ akamai:
4444
accessToken: "your-access-token"
4545
logs:
4646
show_access_logs: true
47+
# If you want to log an user from a JWT Token, you can enable the jwt_user option and set the header name
48+
#jwt_user:
49+
# enabled: true
50+
# header: "Test"
4751
access_logs_fields:
4852
- REQUEST:method
4953
- REQUEST:host

api/v1alpha1/config_types.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ type ConfigSpec struct {
1515
AccessToken string `yaml:"access_token"`
1616
} `yaml:"akamai"`
1717
Logs struct {
18-
ShowAccessLogs bool `yaml:"show_access_logs"`
18+
ShowAccessLogs bool `yaml:"show_access_logs"`
19+
JwtUser struct {
20+
Enabled bool `yaml:"enabled"`
21+
Header string `yaml:"header"`
22+
} `yaml:"jwt_user"`
1923
AccessLogsFields []string `yaml:"access_logs_fields"`
2024
} `yaml:"logs"`
2125
}

config/samples/config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ akamai:
1010
access_token: "your-access-token"
1111
logs:
1212
show_access_logs: true
13+
jwt_user:
14+
enabled: true
15+
header: "Cookie"
1316
access_logs_fields:
1417
- REQUEST:method
1518
- REQUEST:host

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/go-ini/ini v1.67.0
88
github.com/gofiber/fiber/v2 v2.52.6
99
github.com/gofiber/template/html/v2 v2.1.3
10+
github.com/golang-jwt/jwt/v5 v5.2.1
1011
github.com/spf13/cobra v1.8.1
1112
github.com/valyala/fasthttp v1.58.0
1213
go.uber.org/zap v1.27.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ github.com/gofiber/template/html/v2 v2.1.3 h1:n1LYBtmr9C0V/k/3qBblXyMxV5B0o/gpb6
1717
github.com/gofiber/template/html/v2 v2.1.3/go.mod h1:U5Fxgc5KpyujU9OqKzy6Kn6Qup6Tm7zdsISR+VpnHRE=
1818
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
1919
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
20+
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
21+
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
2022
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
2123
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
2224
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=

internal/commons/commons.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package commons
22

33
import (
44
"akapurgo/api/v1alpha1"
5+
"encoding/base64"
6+
"encoding/json"
57
"github.com/gofiber/fiber/v2"
68
"github.com/valyala/fasthttp"
79
"regexp"
@@ -74,9 +76,13 @@ func replaceRequestHeaderTags(req *fasthttp.Request, textToProcess string) (resu
7476
}
7577

7678
// GetRequestLogFields returns the fields attached to a log message for the given HTTP request
77-
func GetRequestLogFields(req *fasthttp.Request, configurationFields []string) []interface{} {
79+
func GetRequestLogFields(req *fasthttp.Request, configurationFields []string, ctx v1alpha1.Context) []interface{} {
7880
var logFields []interface{}
7981

82+
if ctx.Config.Logs.JwtUser.Enabled {
83+
logFields = addJwtUser(ctx, logFields, req)
84+
}
85+
8086
for _, field := range configurationFields {
8187

8288
result := replaceRequestTags(req, field)
@@ -166,6 +172,43 @@ func GetResponseLogFields(resp *fasthttp.Response, configurationFields []string,
166172
return logFields
167173
}
168174

175+
// addJwtUser
176+
func addJwtUser(ctx v1alpha1.Context, logFields []interface{}, req *fasthttp.Request) []interface{} {
177+
cookie := string(req.Header.Peek(ctx.Config.Logs.JwtUser.Header))
178+
if cookie != "" {
179+
jwtPayload := strings.Split(cookie, ".")
180+
if len(jwtPayload) != 3 {
181+
ctx.Logger.Errorf("Invalid JWT format: expected 3 parts but got %d\n", len(jwtPayload))
182+
return logFields
183+
}
184+
185+
jwtPart := strings.TrimSpace(jwtPayload[1])
186+
jwtPart = strings.ReplaceAll(jwtPart, "\n", "")
187+
jwtPart = strings.ReplaceAll(jwtPart, "\r", "")
188+
jwtPart = strings.ReplaceAll(jwtPart, " ", "")
189+
190+
jwtDecoded, err := base64.RawURLEncoding.DecodeString(jwtPart)
191+
if err != nil {
192+
ctx.Logger.Errorf("Failed to decode JWT payload: %v\n", err)
193+
return logFields
194+
}
195+
196+
var payload map[string]interface{}
197+
if err := json.Unmarshal(jwtDecoded, &payload); err != nil {
198+
ctx.Logger.Errorf("Failed to parse JWT payload: %v\n", err)
199+
return logFields
200+
}
201+
202+
email, ok := payload["email"].(string)
203+
if ok {
204+
logFields = append(logFields, "jwt_user", email)
205+
return logFields
206+
}
207+
}
208+
209+
return logFields
210+
}
211+
169212
// LogRequest logs the request and response of a given HTTP request
170213
func LogRequest(ctx v1alpha1.Context) fiber.Handler {
171214
return func(c *fiber.Ctx) error {
@@ -181,7 +224,7 @@ func LogRequest(ctx v1alpha1.Context) fiber.Handler {
181224
// Log the request
182225
if ctx.Config.Logs.ShowAccessLogs {
183226
logFieldsReq := GetResponseLogFields(c.Response(), ctx.Config.Logs.AccessLogsFields, duration)
184-
logFieldsResp := GetRequestLogFields(c.Request(), ctx.Config.Logs.AccessLogsFields)
227+
logFieldsResp := GetRequestLogFields(c.Request(), ctx.Config.Logs.AccessLogsFields, ctx)
185228
logFields := append(logFieldsReq, logFieldsResp...)
186229
ctx.Logger.Infow("request", logFields...)
187230
}

0 commit comments

Comments
 (0)