x-sensitive-data¶
Automatically mask sensitive data in structured logs.
Overview¶
The x-sensitive-data extension allows you to mark fields as containing sensitive information that should be automatically masked when logging. This is useful for preventing accidental exposure of sensitive data like passwords, API keys, credit card numbers, etc. in logs.
The extension generates two methods:
Masked()- Returns a copy of the struct with sensitive fields maskedLogValue()- Implements Go'sslog.LogValuerinterface (callsMasked()internally)
This means:
- JSON serialization stays raw -
json.Marshal(user)returns the actual values (needed for API calls) - Masked JSON -
json.Marshal(user.Masked())returns masked values - Structured logging is masked -
slog.Info("user", "user", user)automatically masks sensitive fields
Masking Strategies¶
The extension supports several masking strategies:
full: Replace the entire value with a fixed-length mask ("********") to hide both content and lengthregex: Mask only parts of the value matching a regex pattern (keeps context visible)hash: Replace the value with a SHA256 hash (one-way, useful for verification)partial: Mask the middle part while keeping prefix/suffix visible (e.g., show last 4 digits of credit card)
Example¶
openapi: 3.0.0
info:
title: Sensitive Data Example
version: 1.0.0
paths:
/users:
get:
operationId: getUsers
responses:
'200':
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
required:
- id
- username
properties:
id:
type: integer
format: int64
username:
type: string
email:
type: string
x-sensitive-data:
mask: full
ssn:
type: string
x-sensitive-data:
mask: regex
pattern: '\d{3}-\d{2}-\d{4}'
creditCard:
type: string
x-sensitive-data:
mask: partial
keepSuffix: 4
apiKey:
type: string
x-sensitive-data:
mask: hash
algorithm: sha256
Generated Code¶
This generates a struct with Masked() and LogValue() methods:
type User struct {
ID int64 `json:"id" validate:"required"`
Username string `json:"username" validate:"required"`
Email *string `json:"email,omitempty" sensitive:""`
Ssn *string `json:"ssn,omitempty" sensitive:""`
CreditCard *string `json:"creditCard,omitempty" sensitive:""`
APIKey *string `json:"apiKey,omitempty" sensitive:""`
}
func (u User) Validate() error {
return runtime.ConvertValidatorError(typesValidator.Struct(u))
}
// Masked returns a copy of the struct with sensitive fields masked.
func (u User) Masked() User {
masked := u
if masked.Email != nil {
v := runtime.MaskSensitiveString(*masked.Email, runtime.SensitiveDataConfig{
Type: runtime.MaskTypeFull,
Pattern: "",
Algorithm: "",
KeepPrefix: 0,
KeepSuffix: 0,
})
masked.Email = &v
}
if masked.Ssn != nil {
v := runtime.MaskSensitiveString(*masked.Ssn, runtime.SensitiveDataConfig{
Type: runtime.MaskTypeRegex,
Pattern: "\\d{3}-\\d{2}-\\d{4}",
Algorithm: "",
KeepPrefix: 0,
KeepSuffix: 0,
})
masked.Ssn = &v
}
if masked.CreditCard != nil {
v := runtime.MaskSensitiveString(*masked.CreditCard, runtime.SensitiveDataConfig{
Type: runtime.MaskTypePartial,
Pattern: "",
Algorithm: "",
KeepPrefix: 0,
KeepSuffix: 4,
})
masked.CreditCard = &v
}
if masked.APIKey != nil {
v := runtime.MaskSensitiveString(*masked.APIKey, runtime.SensitiveDataConfig{
Type: runtime.MaskTypeHash,
Pattern: "",
Algorithm: "sha256",
KeepPrefix: 0,
KeepSuffix: 0,
})
masked.APIKey = &v
}
return masked
}
// LogValue implements slog.LogValuer interface for structured logging.
func (u User) LogValue() slog.Value {
type plain User
return slog.AnyValue(plain(u.Masked()))
}
Behavior¶
When logging with slog:
user := User{
ID: 1,
Username: "johndoe",
Email: Ptr("user@example.com"),
Ssn: Ptr("123-45-6789"),
CreditCard: Ptr("1234-5678-9012-3456"),
APIKey: Ptr("my-secret-key"),
}
// Masked in logs
slog.Info("user created", "user", user)
// Output: user={id=1 username=johndoe email=******** ssn=***-**-**** creditCard=********3456 apiKey=325ededd...}
// Raw in JSON (for API calls)
json.Marshal(user)
// Output: {"id":1,"username":"johndoe","email":"user@example.com","ssn":"123-45-6789",...}
Masked JSON Output¶
If you need masked JSON (e.g., for API responses that should hide sensitive data), use the Masked() method:
// Get masked JSON
maskedJSON, _ := json.Marshal(user.Masked())
// Output: {"id":1,"username":"johndoe","email":"********","ssn":"***-**-****",...}
Partial Masking Options¶
keepPrefix: Number of characters to keep at the startkeepSuffix: Number of characters to keep at the end
Full Example¶
You can see this in more detail in the example code.
Related Extensions¶
x-oapi-codegen-extra-tags- Generate arbitrary struct tagsx-go-json-ignore- Ignore fields when (un)marshaling JSON