User Identification
ByteHide Logger provides user identification features to track which user performed actions. This is essential for auditing, debugging, and understanding user behavior in production systems.
AuthUser Struct
The AuthUser struct contains user authentication information:
Go
type AuthUser struct {
ID string // Unique identifier
Email string // User's email address
Token string // Authentication token
}type AuthUser struct {
ID string // Unique identifier
Email string // User's email address
Token string // Authentication token
}Setting Authenticated Users
Basic User Identification
Set the authenticated user when they log in or their context becomes available:
Go
import "github.com/bytehide/bytehide-logs-go"
user := &logs.AuthUser{
ID: "user_12345",
Email: "john.doe@example.com",
Token: "eyJhbGc...", // JWT or session token
}
logs.SetUser(user)
logs.Info("User logged in successfully")import "github.com/bytehide/bytehide-logs-go"
user := &logs.AuthUser{
ID: "user_12345",
Email: "john.doe@example.com",
Token: "eyJhbGc...", // JWT or session token
}
logs.SetUser(user)
logs.Info("User logged in successfully")User Identification in HTTP Middleware
Extract user info from authentication context and set globally:
Go
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Extract user from JWT or session
user, err := extractUser(r)
if err != nil {
logs.Warn("Failed to extract user information")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Set user in logger
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
Token: user.SessionToken,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User authenticated")
next.ServeHTTP(w, r)
})
}
func extractUser(r *http.Request) (*User, error) {
// Extract from Authorization header, session cookie, etc.
token := r.Header.Get("Authorization")
if token == "" {
return nil, fmt.Errorf("no authorization token")
}
user, err := parseToken(token)
if err != nil {
return nil, fmt.Errorf("invalid token: %w", err)
}
return user, nil
}func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Extract user from JWT or session
user, err := extractUser(r)
if err != nil {
logs.Warn("Failed to extract user information")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Set user in logger
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
Token: user.SessionToken,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User authenticated")
next.ServeHTTP(w, r)
})
}
func extractUser(r *http.Request) (*User, error) {
// Extract from Authorization header, session cookie, etc.
token := r.Header.Get("Authorization")
if token == "" {
return nil, fmt.Errorf("no authorization token")
}
user, err := parseToken(token)
if err != nil {
return nil, fmt.Errorf("invalid token: %w", err)
}
return user, nil
}User Identification in Service Layer
Set user context when processing user-specific operations:
Go
type OrderService struct {
repo OrderRepository
}
func (s *OrderService) CreateOrder(user *AuthUser, request *CreateOrderRequest) (*Order, error) {
// Set user in logger
logs.SetUser(user)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User creating order")
order := &Order{
ID: generateID(),
UserID: user.ID,
CustomerID: request.CustomerID,
CreatedAt: time.Now(),
}
err := s.repo.Save(order)
if err != nil {
logs.WithContext("userId", user.ID).
Error("Failed to create order", err)
return nil, err
}
logs.WithContext("userId", user.ID).
WithContext("orderId", order.ID).
Info("Order created successfully")
return order, nil
}type OrderService struct {
repo OrderRepository
}
func (s *OrderService) CreateOrder(user *AuthUser, request *CreateOrderRequest) (*Order, error) {
// Set user in logger
logs.SetUser(user)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User creating order")
order := &Order{
ID: generateID(),
UserID: user.ID,
CustomerID: request.CustomerID,
CreatedAt: time.Now(),
}
err := s.repo.Save(order)
if err != nil {
logs.WithContext("userId", user.ID).
Error("Failed to create order", err)
return nil, err
}
logs.WithContext("userId", user.ID).
WithContext("orderId", order.ID).
Info("Order created successfully")
return order, nil
}Anonymous Users
Use SetAnonymousID() for unauthenticated users or bots:
Go
import "github.com/bytehide/bytehide-logs-go"
// Set anonymous user ID (e.g., from session, device, or request)
anonId := generateSessionID()
logs.SetAnonymousID(anonId)
logs.WithContext("anonId", anonId).
Info("Anonymous user visited")import "github.com/bytehide/bytehide-logs-go"
// Set anonymous user ID (e.g., from session, device, or request)
anonId := generateSessionID()
logs.SetAnonymousID(anonId)
logs.WithContext("anonId", anonId).
Info("Anonymous user visited")Anonymous User in Public APIs
Go
func handlePublicAPIRequest(w http.ResponseWriter, r *http.Request) {
// Generate or extract anonymous ID
anonID := extractOrGenerateAnonID(r)
logs.SetAnonymousID(anonID)
logs.WithContext("anonId", anonID).
WithContext("path", r.URL.Path).
WithContext("method", r.Method).
Debug("Processing public API request")
// Process request
result, err := processRequest(r)
if err != nil {
logs.Error("Public API request failed", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
func extractOrGenerateAnonID(r *http.Request) string {
// Try to get from cookie
cookie, err := r.Cookie("session_id")
if err == nil {
return cookie.Value
}
// Generate new ID
return generateSessionID()
}func handlePublicAPIRequest(w http.ResponseWriter, r *http.Request) {
// Generate or extract anonymous ID
anonID := extractOrGenerateAnonID(r)
logs.SetAnonymousID(anonID)
logs.WithContext("anonId", anonID).
WithContext("path", r.URL.Path).
WithContext("method", r.Method).
Debug("Processing public API request")
// Process request
result, err := processRequest(r)
if err != nil {
logs.Error("Public API request failed", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
func extractOrGenerateAnonID(r *http.Request) string {
// Try to get from cookie
cookie, err := r.Cookie("session_id")
if err == nil {
return cookie.Value
}
// Generate new ID
return generateSessionID()
}User Lifecycle
Login Flow
Go
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
var loginReq struct {
Email string `json:"email"`
Password string `json:"password"`
}
err := json.NewDecoder(r.Body).Decode(&loginReq)
if err != nil {
logs.WithContext("email", loginReq.Email).
Error("Failed to decode login request", err)
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// Authenticate user
user, err := h.service.AuthenticateUser(loginReq.Email, loginReq.Password)
if err != nil {
logs.WithContext("email", loginReq.Email).
Warn("User authentication failed")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Set user in logger
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
Token: user.Token,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User logged in successfully")
// Return token
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"token": user.Token,
})
}func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
var loginReq struct {
Email string `json:"email"`
Password string `json:"password"`
}
err := json.NewDecoder(r.Body).Decode(&loginReq)
if err != nil {
logs.WithContext("email", loginReq.Email).
Error("Failed to decode login request", err)
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// Authenticate user
user, err := h.service.AuthenticateUser(loginReq.Email, loginReq.Password)
if err != nil {
logs.WithContext("email", loginReq.Email).
Warn("User authentication failed")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Set user in logger
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
Token: user.Token,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User logged in successfully")
// Return token
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"token": user.Token,
})
}Logout Flow
Go
func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
user, err := extractUserFromRequest(r)
if err != nil {
logs.Warn("Failed to extract user for logout")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Log logout with current user context
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User logged out")
// Clear user from logger
logs.SetUser(nil)
// Return success
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "logged_out",
})
}func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
user, err := extractUserFromRequest(r)
if err != nil {
logs.Warn("Failed to extract user for logout")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Log logout with current user context
authUser := &logs.AuthUser{
ID: user.ID,
Email: user.Email,
}
logs.SetUser(authUser)
logs.WithContext("userId", user.ID).
WithContext("email", user.Email).
Info("User logged out")
// Clear user from logger
logs.SetUser(nil)
// Return success
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "logged_out",
})
}User Session Management
Go
func (s *SessionService) CreateSession(user *AuthUser) (string, error) {
logs.SetUser(user)
logs.WithContext("userId", user.ID).
Trace("Creating new session")
session := &Session{
ID: generateSessionID(),
UserID: user.ID,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
}
err := s.repo.Save(session)
if err != nil {
logs.WithContext("userId", user.ID).
Error("Failed to create session", err)
return "", err
}
logs.WithContext("userId", user.ID).
WithContext("sessionId", session.ID).
Debug("Session created successfully")
return session.ID, nil
}
func (s *SessionService) ValidateSession(sessionID string) (*AuthUser, error) {
session, err := s.repo.Get(sessionID)
if err != nil {
logs.WithContext("sessionId", sessionID).
Debug("Session not found")
return nil, err
}
if time.Now().After(session.ExpiresAt) {
logs.WithContext("sessionId", sessionID).
Warn("Session expired")
return nil, fmt.Errorf("session expired")
}
user := &logs.AuthUser{
ID: session.UserID,
}
logs.SetUser(user)
logs.WithContext("userId", session.UserID).
Trace("Session validated successfully")
return user, nil
}func (s *SessionService) CreateSession(user *AuthUser) (string, error) {
logs.SetUser(user)
logs.WithContext("userId", user.ID).
Trace("Creating new session")
session := &Session{
ID: generateSessionID(),
UserID: user.ID,
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(24 * time.Hour),
}
err := s.repo.Save(session)
if err != nil {
logs.WithContext("userId", user.ID).
Error("Failed to create session", err)
return "", err
}
logs.WithContext("userId", user.ID).
WithContext("sessionId", session.ID).
Debug("Session created successfully")
return session.ID, nil
}
func (s *SessionService) ValidateSession(sessionID string) (*AuthUser, error) {
session, err := s.repo.Get(sessionID)
if err != nil {
logs.WithContext("sessionId", sessionID).
Debug("Session not found")
return nil, err
}
if time.Now().After(session.ExpiresAt) {
logs.WithContext("sessionId", sessionID).
Warn("Session expired")
return nil, fmt.Errorf("session expired")
}
user := &logs.AuthUser{
ID: session.UserID,
}
logs.SetUser(user)
logs.WithContext("userId", session.UserID).
Trace("Session validated successfully")
return user, nil
}Best Practices
User Identification Best Practices
- Set user early in request processing pipeline (typically in middleware)
- Use AuthUser for authenticated requests with ID, Email, and Token
- Use SetAnonymousID() for unauthenticated requests to distinguish them
- Clear user context on logout with
logs.SetUser(nil) - Include user ID in log context for additional clarity
- Protect sensitive data - don't log full tokens or passwords (use data masking)
- Maintain user consistency throughout request lifecycle
Token Security
While the AuthUser struct includes a Token field for tracking authentication state, never log or expose full token values. Use data masking to protect sensitive tokens.