Authentication and Authorization
The authentication context package provides a simple and powerful structure for managing authenticated user information throughout the application. Using Go's native context mechanism, it allows storing and retrieving user details securely, making it ideal for multi-tenant applications.
Main Components
1. AuthenticationContext
The core structure that holds authentication data:
type AuthenticationContext struct {
TenantID string `json:"tenantId"`
UserID string `json:"userId"`
}
2. IAuthenticationContext Interface
Defines the contract for standardized access to information:
type IAuthenticationContext interface {
GetUserID() string
GetTenantID() string
}
3. User Structure
Represents the complete user profile in the system:
type User struct {
ID string
Email string
Phone string
Name string
TenantID string
Profile string
Profiles []string
PhotoURL string
}
Core Features
1. Context Creation
authContext := security.NewAuthenticationContext("tenant123", "user456")
2. Storing in Go Context
Add authentication information to the request context:
ctx = authContext.SetInContext(context.Background())
3. Data Retrieval
Retrieve information from anywhere that has access to the context:
authContext := security.GetAuthenticationContext(ctx)
if authContext != nil {
tenantID := authContext.GetTenantID()
userID := authContext.GetUserID()
}
4. Validation
Check if the context has valid data:
if authContext.Valid() {
// Proceed with the operation
}
Usage Examples
1. Multi-tenant Data Access
Ensure data isolation using the TenantID retrieved from the context.
func (r *Repository) FetchData(ctx context.Context) (*Data, error) {
authContext := security.GetAuthenticationContext(ctx)
if authContext == nil {
return nil, errors.New("unauthenticated user")
}
// Mandatory filter by TenantID for security
return r.db.Query(
"SELECT * FROM table WHERE tenant_id = ? AND user_id = ?",
authContext.GetTenantID(),
authContext.GetUserID(),
)
}
2. Layer Propagation
The context must be passed forward to keep the authentication chain intact.
func (s *Service) Process(ctx context.Context, data *Data) error {
// The context already carries the security information.
// Just pass it to the persistence layer.
return s.repository.Save(ctx, data)
}
Best Practices
- Propagation: Always pass
context.Contextas the first argument of your functions to not lose the authentication trace. - Rigid Validation: Always check if
authContext != niland useValid()before performing critical operations. - Data Security: The authentication context should be created only after successful credential validation (such as a JWT token).
- Isolation: In multi-tenant systems, never perform database queries without including the
TenantIDin theWHEREclause.