Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .github/workflows/go-combined-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ jobs:
uses: reviewdog/action-golangci-lint@v2
with:
github_token: ${{ steps.app-token.outputs.token }}
go_version: '1.23'
go_version: '1.26'
tool_name: golint
level: error
fail_level: any
reporter: github-pr-review
filter_mode: diff_context
golangci_lint_version: v2.4.0
golangci_lint_version: latest
Comment thread
coderabbitai[bot] marked this conversation as resolved.
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ steps.app-token.outputs.token }}
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
Expand All @@ -70,10 +70,11 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version: '1.23'
go-version: '1.26'
cache: false

- name: Gosec Scanner
uses: securego/gosec@master
with:
args: ./...
- name: Install Gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest

- name: Run Gosec
run: gosec ./...
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## [2.8.0-beta.4](https://github.com/LerianStudio/lib-auth/compare/v2.8.0-beta.3...v2.8.0-beta.4) (2026-05-18)


### Bug Fixes

* **security:** redact clientSecret from tracing span payload ([fb15a94](https://github.com/LerianStudio/lib-auth/commit/fb15a9486a5d937ff45a7f9a2c7cc18fd6018569))

## [2.8.0-beta.3](https://github.com/LerianStudio/lib-auth/compare/v2.8.0-beta.2...v2.8.0-beta.3) (2026-05-18)

## [2.8.0-beta.2](https://github.com/LerianStudio/lib-auth/compare/v2.8.0-beta.1...v2.8.0-beta.2) (2026-05-18)

## [2.8.0-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.7.0...v2.8.0-beta.1) (2026-05-18)

Comment thread
qnen marked this conversation as resolved.
## [2.7.0](https://github.com/LerianStudio/lib-auth/compare/v2.6.0...v2.7.0) (2026-04-27)


Expand Down
68 changes: 38 additions & 30 deletions auth/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import (
"strings"
"time"

"github.com/LerianStudio/lib-commons/v5/commons/log"
"github.com/LerianStudio/lib-commons/v5/commons/opentelemetry"
"github.com/LerianStudio/lib-commons/v5/commons/zap"
observability "github.com/LerianStudio/lib-observability"
"github.com/LerianStudio/lib-observability/log"
"github.com/LerianStudio/lib-observability/tracing"
"github.com/LerianStudio/lib-observability/zap"
"go.opentelemetry.io/otel/attribute"

"github.com/LerianStudio/lib-commons/v5/commons"
Expand Down Expand Up @@ -214,9 +215,9 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient
// If the user is authorized, the request is passed to the next handler; otherwise, a 403 Forbidden status is returned.
func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler {
return func(c *fiber.Ctx) error {
ctx := opentelemetry.ExtractHTTPContext(c.UserContext(), c)
ctx := tracing.ExtractHTTPContext(c.UserContext(), c)

_, tracer, reqID, _ := commons.NewTrackingFromContext(ctx)
_, tracer, reqID, _ := observability.NewTrackingFromContext(ctx)

if !auth.Enabled || auth.Address == "" {
return c.Next()
Expand Down Expand Up @@ -261,7 +262,7 @@ func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler {

// checkAuthorization sends an authorization request to the external service and returns whether the action is authorized.
func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, action, accessToken string) (bool, int, error) {
_, tracer, reqID, _ := commons.NewTrackingFromContext(ctx)
_, tracer, reqID, _ := observability.NewTrackingFromContext(ctx)

ctx, span := tracer.Start(ctx, "lib_auth.check_authorization")
defer span.End()
Expand All @@ -276,7 +277,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to parse token: %v", err)

opentelemetry.HandleSpanError(span, "Failed to parse token", err)
tracing.HandleSpanError(span, "Failed to parse token", err)

return false, http.StatusUnauthorized, err
}
Expand All @@ -287,7 +288,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a

err := errors.New("token claims are not in the expected format")

opentelemetry.HandleSpanError(span, "Failed to parse claims", err)
tracing.HandleSpanError(span, "Failed to parse claims", err)

return false, http.StatusUnauthorized, err
}
Expand All @@ -303,7 +304,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a

err := errors.New("missing owner claim in token")

opentelemetry.HandleSpanError(span, "Missing owner claim in token", err)
tracing.HandleSpanError(span, "Missing owner claim in token", err)

return false, http.StatusUnauthorized, err
}
Expand All @@ -318,9 +319,9 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
"action": action,
}

err = opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", requestBody, nil)
err = tracing.SetSpanAttributesFromValue(span, "app.request.payload", requestBody, nil)
if err != nil {
opentelemetry.HandleSpanError(span, "Failed to convert request body to JSON string", err)
tracing.HandleSpanError(span, "Failed to convert request body to JSON string", err)

return false, http.StatusInternalServerError, err
}
Expand All @@ -329,7 +330,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to marshal request body: %v", err)

opentelemetry.HandleSpanError(span, "Failed to marshal request body", err)
tracing.HandleSpanError(span, "Failed to marshal request body", err)

return false, http.StatusInternalServerError, err
}
Expand All @@ -338,12 +339,12 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to create request: %v", err)

opentelemetry.HandleSpanError(span, "Failed to create request", err)
tracing.HandleSpanError(span, "Failed to create request", err)

return false, http.StatusInternalServerError, fmt.Errorf("failed to create request: %w", err)
}

opentelemetry.InjectHTTPContext(ctx, req.Header)
tracing.InjectHTTPContext(ctx, req.Header)

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", accessToken)
Expand All @@ -352,7 +353,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to make request: %v", err)

opentelemetry.HandleSpanError(span, "Failed to make request", err)
tracing.HandleSpanError(span, "Failed to make request", err)

return false, http.StatusInternalServerError, fmt.Errorf("failed to make request: %w", err)
}
Expand All @@ -362,7 +363,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to read response body: %v", err)

opentelemetry.HandleSpanError(span, "Failed to read response body", err)
tracing.HandleSpanError(span, "Failed to read response body", err)

return false, http.StatusInternalServerError, fmt.Errorf("failed to read response body: %w", err)
}
Expand All @@ -371,15 +372,15 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err)

opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err)
tracing.HandleSpanError(span, "Failed to unmarshal auth error response", err)

return false, http.StatusInternalServerError, fmt.Errorf("failed to unmarshal auth error response: %w", err)
}

if respError.Code != "" && resp.StatusCode != http.StatusInternalServerError {
logErrorf(ctx, auth.Logger, "Authorization request failed: %s", respError.Message)

opentelemetry.HandleSpanError(span, "Authorization request failed", respError)
tracing.HandleSpanError(span, "Authorization request failed", respError)

return false, resp.StatusCode, respError
}
Expand All @@ -388,7 +389,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
if err := json.Unmarshal(body, &response); err != nil {
logErrorf(ctx, auth.Logger, "Failed to unmarshal response: %v", err)

opentelemetry.HandleSpanError(span, "Failed to unmarshal response", err)
tracing.HandleSpanError(span, "Failed to unmarshal response", err)

return false, http.StatusInternalServerError, fmt.Errorf("failed to unmarshal response: %w", err)
}
Expand All @@ -400,7 +401,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a
// It takes the client ID and client secret as parameters and returns the access token if the request is successful.
// If the request fails at any step, an error is returned with a descriptive message.
func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clientSecret string) (string, error) {
_, tracer, reqID, _ := commons.NewTrackingFromContext(ctx)
_, tracer, reqID, _ := observability.NewTrackingFromContext(ctx)

ctx, span := tracer.Start(ctx, "lib_auth.get_application_token")
defer span.End()
Expand All @@ -421,9 +422,16 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
"clientSecret": clientSecret,
}

err := opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", requestBody, nil)
// tracePayload mirrors requestBody but omits clientSecret so the OAuth secret
// never flows into telemetry. Do not collapse these two maps.
tracePayload := map[string]string{
"grantType": "client_credentials",
"clientId": clientID,
}

err := tracing.SetSpanAttributesFromValue(span, "app.request.payload", tracePayload, nil)
if err != nil {
opentelemetry.HandleSpanError(span, "Failed to convert request body to JSON string", err)
tracing.HandleSpanError(span, "Failed to convert request body to JSON string", err)

return "", fmt.Errorf("failed to convert request body to JSON string: %w", err)
}
Expand All @@ -432,7 +440,7 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to marshal request body: %v", err)

opentelemetry.HandleSpanError(span, "Failed to marshal request body", err)
tracing.HandleSpanError(span, "Failed to marshal request body", err)

return "", fmt.Errorf("failed to marshal request body: %w", err)
}
Expand All @@ -441,20 +449,20 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to create request: %v", err)

opentelemetry.HandleSpanError(span, "Failed to create request", err)
tracing.HandleSpanError(span, "Failed to create request", err)

return "", fmt.Errorf("failed to create request: %w", err)
}

opentelemetry.InjectHTTPContext(ctx, req.Header)
tracing.InjectHTTPContext(ctx, req.Header)

req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req)
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to make request: %v", err)

opentelemetry.HandleSpanError(span, "Failed to make request", err)
tracing.HandleSpanError(span, "Failed to make request", err)

return "", fmt.Errorf("failed to make request: %w", err)
}
Expand All @@ -464,7 +472,7 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to read response body: %v", err)

opentelemetry.HandleSpanError(span, "Failed to read response body", err)
tracing.HandleSpanError(span, "Failed to read response body", err)

return "", fmt.Errorf("failed to read response body: %w", err)
}
Expand All @@ -473,15 +481,15 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
if err != nil {
logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err)

opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err)
tracing.HandleSpanError(span, "Failed to unmarshal auth error response", err)

return "", fmt.Errorf("failed to unmarshal auth error response: %w", err)
}

if respError.Code != "" && resp.StatusCode != http.StatusInternalServerError {
logErrorf(ctx, auth.Logger, "Failed to get application token: %s", respError.Message)

opentelemetry.HandleSpanError(span, "Failed to get application token", respError)
tracing.HandleSpanError(span, "Failed to get application token", respError)

return "", respError
}
Expand All @@ -490,7 +498,7 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien
if err := json.Unmarshal(body, &response); err != nil {
logErrorf(ctx, auth.Logger, "Failed to unmarshal response: %v", err)

opentelemetry.HandleSpanError(span, "Failed to unmarshal response", err)
tracing.HandleSpanError(span, "Failed to unmarshal response", err)

return "", fmt.Errorf("failed to unmarshal response: %w", err)
}
Expand Down
13 changes: 7 additions & 6 deletions auth/middleware/middlewareGRPC.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (
"strings"

"github.com/LerianStudio/lib-commons/v5/commons"
"github.com/LerianStudio/lib-commons/v5/commons/opentelemetry"
observability "github.com/LerianStudio/lib-observability"
"github.com/LerianStudio/lib-observability/tracing"
jwt "github.com/golang-jwt/jwt/v5"
"go.opentelemetry.io/otel/attribute"
"google.golang.org/grpc"
Expand Down Expand Up @@ -50,7 +51,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer
}

token, ok := extractTokenFromMD(ctx)
_, tracer, reqID, _ := commons.NewTrackingFromContext(ctx)
_, tracer, reqID, _ := observability.NewTrackingFromContext(ctx)

ctx, span := tracer.Start(ctx, "lib_auth.authorize_grpc_unary_policy")
defer span.End()
Expand All @@ -63,7 +64,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer

pol, found := policyForMethod(cfg, info.FullMethod)
if !found {
opentelemetry.HandleSpanError(span, "no policy configured for method", fmt.Errorf("%s", info.FullMethod))
tracing.HandleSpanError(span, "no policy configured for method", fmt.Errorf("%s", info.FullMethod))

return nil, status.Error(codes.Internal, "internal configuration error")
}
Expand All @@ -75,7 +76,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer

sub, err = cfg.SubResolver(ctx, info.FullMethod, req)
if err != nil {
opentelemetry.HandleSpanError(span, "failed to resolve subject", err)
tracing.HandleSpanError(span, "failed to resolve subject", err)

return nil, status.Error(codes.Internal, "internal configuration error")
}
Expand All @@ -86,8 +87,8 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer
"resource": pol.Resource,
"action": pol.Action,
}
if err := opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", payload, nil); err != nil {
opentelemetry.HandleSpanError(span, "failed to set span payload", err)
if err := tracing.SetSpanAttributesFromValue(span, "app.request.payload", payload, nil); err != nil {
tracing.HandleSpanError(span, "failed to set span payload", err)
}

authorized, httpStatus, err := auth.checkAuthorization(ctx, sub, pol.Resource, pol.Action, token)
Expand Down
2 changes: 1 addition & 1 deletion auth/middleware/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"

"github.com/LerianStudio/lib-commons/v5/commons/log"
"github.com/LerianStudio/lib-observability/log"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down
Loading
Loading