Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetUsernameFromContext ¶
GetUsernameFromContext extracts the username from the user object in context. It attempts to extract from Gin context's "user" key set by RequireAuth middleware. Returns empty string if user cannot be determined.
Types ¶
type AccessToken ¶
type AccessToken struct {
ID string `gorm:"primaryKey"`
Token string `gorm:"uniqueIndex;not null"`
TokenType string `gorm:"not null;default:'Bearer'"`
TokenCategory string `gorm:"not null;default:'access';index"` // 'access' or 'refresh'
Status string `gorm:"not null;default:'active';index"` // 'active', 'disabled', 'revoked'
UserID string `gorm:"not null;index"`
ClientID string `gorm:"not null;index"`
Scopes string `gorm:"not null"` // space-separated scopes
ExpiresAt time.Time
CreatedAt time.Time
LastUsedAt *time.Time `gorm:"index"` // Last time token was used (for refresh tokens)
ParentTokenID string `gorm:"index"` // Links access tokens to their refresh token
AuthorizationID *uint `gorm:"index"` // FK → UserAuthorization.ID (nil for device_code grants)
}
func (*AccessToken) IsAccessToken ¶ added in v0.11.0
func (t *AccessToken) IsAccessToken() bool
IsAccessToken returns true if token category is 'access'
func (*AccessToken) IsActive ¶
func (t *AccessToken) IsActive() bool
IsActive returns true if token status is 'active'
func (*AccessToken) IsDisabled ¶
func (t *AccessToken) IsDisabled() bool
IsDisabled returns true if token status is 'disabled'
func (*AccessToken) IsExpired ¶
func (t *AccessToken) IsExpired() bool
func (*AccessToken) IsRefreshToken ¶ added in v0.11.0
func (t *AccessToken) IsRefreshToken() bool
IsRefreshToken returns true if token category is 'refresh'
func (*AccessToken) IsRevoked ¶
func (t *AccessToken) IsRevoked() bool
IsRevoked returns true if token status is 'revoked'
type AuditDetails ¶
AuditDetails stores additional event-specific information as JSON
func (*AuditDetails) Scan ¶
func (a *AuditDetails) Scan(value any) error
Scan implements the sql.Scanner interface for database retrieval
type AuditLog ¶
type AuditLog struct {
ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
// Event information
EventType EventType `gorm:"type:varchar(50);index;not null" json:"event_type"`
EventTime time.Time `gorm:"index;not null" json:"event_time"`
Severity EventSeverity `gorm:"type:varchar(20);not null" json:"severity"`
// Actor information
ActorUserID string `gorm:"type:varchar(36);index" json:"actor_user_id"`
ActorUsername string `gorm:"type:varchar(100)" json:"actor_username"`
ActorIP string `gorm:"type:varchar(45);index" json:"actor_ip"` // Support IPv6
// Resource information
ResourceType ResourceType `gorm:"type:varchar(50);index" json:"resource_type"`
ResourceID string `gorm:"type:varchar(36);index" json:"resource_id"`
ResourceName string `gorm:"type:varchar(255)" json:"resource_name"`
// Operation details
Action string `gorm:"type:varchar(255);not null" json:"action"`
Details AuditDetails `gorm:"type:json" json:"details"`
Success bool `gorm:"index;not null" json:"success"`
ErrorMessage string `gorm:"type:text" json:"error_message,omitempty"`
// Request metadata
UserAgent string `gorm:"type:varchar(500)" json:"user_agent,omitempty"`
RequestPath string `gorm:"type:varchar(500)" json:"request_path,omitempty"`
RequestMethod string `gorm:"type:varchar(10)" json:"request_method,omitempty"`
// Timestamps (no UpdatedAt - immutable logs)
CreatedAt time.Time `gorm:"index;not null" json:"created_at"`
}
AuditLog represents an audit log entry
type AuthorizationCode ¶
type AuthorizationCode struct {
ID uint `gorm:"primaryKey;autoIncrement"`
UUID string `gorm:"uniqueIndex;size:36;not null"` // Public UUID for API/UI identification
// Code storage: SHA256 hash for security, prefix for quick lookup
CodeHash string `gorm:"uniqueIndex;not null"` // SHA256(plainCode)
CodePrefix string `gorm:"index;not null;size:8"` // First 8 chars for quick lookup
// Relations (int PK for fast JOIN, string ClientID for OAuth protocol)
ApplicationID int64 `gorm:"not null;index"` // FK → OAuthApplication.ID
ClientID string `gorm:"not null;index"` // Denormalized ClientID UUID (OAuth protocol use)
UserID string `gorm:"not null;index"` // FK → User.ID
RedirectURI string `gorm:"not null"`
Scopes string `gorm:"not null"`
// PKCE (RFC 7636)
CodeChallenge string `gorm:"default:''"` // code_challenge (empty = PKCE not used)
CodeChallengeMethod string `gorm:"default:'S256'"` // "S256" or "plain"
// OIDC (OpenID Connect Core 1.0 §3.1.2.1)
Nonce string `gorm:"default:''"` // nonce from authorization request (empty if not provided)
ExpiresAt time.Time
UsedAt *time.Time // Set immediately upon exchange; prevents replay attacks
CreatedAt time.Time
}
AuthorizationCode stores OAuth 2.0 authorization codes (RFC 6749). Codes are short-lived (default 10 minutes) and single-use.
func (*AuthorizationCode) IsExpired ¶
func (a *AuthorizationCode) IsExpired() bool
func (*AuthorizationCode) IsUsed ¶
func (a *AuthorizationCode) IsUsed() bool
func (AuthorizationCode) TableName ¶
func (AuthorizationCode) TableName() string
type DeviceCode ¶
type DeviceCode struct {
ID int64 `gorm:"primaryKey;autoIncrement"`
DeviceCode string `gorm:"-"` // Not stored in DB, only for in-memory use
DeviceCodeHash string `gorm:"uniqueIndex;not null"` // PBKDF2 hash of device code
DeviceCodeSalt string `gorm:"not null"` // Random salt for hashing
DeviceCodeID string `gorm:"index;not null"` // Last 8 chars for quick lookup
UserCode string `gorm:"uniqueIndex;not null"`
ClientID string `gorm:"not null;index"`
Scopes string `gorm:"not null"` // space-separated scopes
ExpiresAt time.Time
Interval int // polling interval in seconds
UserID string // filled after authorization
Authorized bool `gorm:"default:false"`
AuthorizedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
func (*DeviceCode) IsExpired ¶
func (d *DeviceCode) IsExpired() bool
type EventSeverity ¶
type EventSeverity string
EventSeverity represents the severity level of an audit event
const ( SeverityInfo EventSeverity = "INFO" SeverityWarning EventSeverity = "WARNING" SeverityError EventSeverity = "ERROR" SeverityCritical EventSeverity = "CRITICAL" )
type EventType ¶
type EventType string
EventType represents the type of audit event
const ( // Authentication events EventAuthenticationSuccess EventType = "AUTHENTICATION_SUCCESS" EventAuthenticationFailure EventType = "AUTHENTICATION_FAILURE" EventLogout EventType = "LOGOUT" EventOAuthAuthentication EventType = "OAUTH_AUTHENTICATION" // Device authorization events EventDeviceCodeGenerated EventType = "DEVICE_CODE_GENERATED" EventDeviceCodeAuthorized EventType = "DEVICE_CODE_AUTHORIZED" // Token events EventAccessTokenIssued EventType = "ACCESS_TOKEN_ISSUED" EventRefreshTokenIssued EventType = "REFRESH_TOKEN_ISSUED" EventIDTokenIssued EventType = "ID_TOKEN_ISSUED" EventTokenRefreshed EventType = "TOKEN_REFRESHED" EventTokenRevoked EventType = "TOKEN_REVOKED" EventTokenDisabled EventType = "TOKEN_DISABLED" EventTokenEnabled EventType = "TOKEN_ENABLED" // Admin operations EventClientCreated EventType = "CLIENT_CREATED" EventClientUpdated EventType = "CLIENT_UPDATED" EventClientDeleted EventType = "CLIENT_DELETED" EventClientSecretRegenerated EventType = "CLIENT_SECRET_REGENERATED" // Security events EventRateLimitExceeded EventType = "RATE_LIMIT_EXCEEDED" EventSuspiciousActivity EventType = "SUSPICIOUS_ACTIVITY" // Authorization Code Flow events (RFC 6749) EventAuthorizationCodeGenerated EventType = "AUTHORIZATION_CODE_GENERATED" EventAuthorizationCodeExchanged EventType = "AUTHORIZATION_CODE_EXCHANGED" EventAuthorizationCodeDenied EventType = "AUTHORIZATION_CODE_DENIED" EventUserAuthorizationGranted EventType = "USER_AUTHORIZATION_GRANTED" EventUserAuthorizationRevoked EventType = "USER_AUTHORIZATION_REVOKED" EventClientTokensRevokedAll EventType = "CLIENT_TOKENS_REVOKED_ALL" //nolint:gosec // G101: false positive, this is a const string describing an event type, not a credential // Client Credentials Flow events (RFC 6749 §4.4) EventClientCredentialsTokenIssued EventType = "CLIENT_CREDENTIALS_TOKEN_ISSUED" //nolint:gosec // G101: false positive // Audit events EventTypeAuditLogView EventType = "AUDIT_LOG_VIEWED" EventTypeAuditLogExported EventType = "AUDIT_LOG_EXPORTED" )
type OAuthApplication ¶
type OAuthApplication struct {
ID int64 `gorm:"primaryKey;autoIncrement"`
ClientID string `gorm:"uniqueIndex;not null"`
ClientSecret string `gorm:"not null"` // bcrypt hashed secret
ClientName string `gorm:"not null"`
Description string `gorm:"type:text"`
UserID string `gorm:"not null"`
Scopes string `gorm:"not null"`
GrantTypes string `gorm:"not null;default:'device_code'"`
RedirectURIs StringArray `gorm:"type:json"`
ClientType string `gorm:"not null;default:'public'"` // "confidential" or "public"
EnableDeviceFlow bool `gorm:"not null;default:true"`
EnableAuthCodeFlow bool `gorm:"not null;default:false"`
EnableClientCredentialsFlow bool `gorm:"not null;default:false"` // Client Credentials Grant (RFC 6749 §4.4); confidential clients only
IsActive bool `gorm:"not null;default:true"`
CreatedBy string
CreatedAt time.Time
UpdatedAt time.Time
}
func (*OAuthApplication) GenerateClientSecret ¶
func (app *OAuthApplication) GenerateClientSecret(ctx context.Context) (string, error)
GenerateClientSecret will generate the client secret and returns the plaintext and saves the hash at the database
func (OAuthApplication) TableName ¶
func (OAuthApplication) TableName() string
TableName overrides the table name used by OAuthApplication to `oauth_applications`
func (*OAuthApplication) ValidateClientSecret ¶
func (app *OAuthApplication) ValidateClientSecret(secret []byte) bool
ValidateClientSecret validates the given secret by the hash saved in database
type OAuthConnection ¶
type OAuthConnection struct {
ID string `gorm:"primaryKey"`
UserID string `gorm:"not null;uniqueIndex:idx_oauth_user_provider,priority:1"`
Provider string `gorm:"not null;uniqueIndex:idx_oauth_provider_user,priority:1;uniqueIndex:idx_oauth_user_provider,priority:2"` // "github", "gitea", "gitlab"
ProviderUserID string `gorm:"not null;uniqueIndex:idx_oauth_provider_user,priority:2"` // Provider's user ID
// OAuth metadata (snapshot for audit/reference)
ProviderUsername string // Provider's username
ProviderEmail string // Provider's email (snapshot)
AvatarURL string // User avatar URL from provider
// Token storage (should be encrypted in production)
AccessToken string `gorm:"type:text"` // OAuth access token
RefreshToken string `gorm:"type:text"` // OAuth refresh token
TokenExpiry time.Time // Token expiration time
// Activity tracking
LastUsedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
OAuthConnection represents an OAuth provider connection for a user
func (OAuthConnection) TableName ¶
func (OAuthConnection) TableName() string
TableName overrides the table name used by OAuthConnection to `oauth_connections`
type ResourceType ¶
type ResourceType string
ResourceType represents the type of resource being operated on
const ( ResourceUser ResourceType = "USER" ResourceClient ResourceType = "CLIENT" ResourceToken ResourceType = "TOKEN" ResourceDeviceCode ResourceType = "DEVICE_CODE" ResourceOAuthConfig ResourceType = "OAUTH_CONFIG" ResourceAuthorization ResourceType = "AUTHORIZATION" )
type StringArray ¶
type StringArray []string
StringArray is a custom type for []string that can be stored as JSON in database
func (StringArray) Join ¶
func (s StringArray) Join(sep string) string
Join returns a string with elements joined by the specified separator
func (*StringArray) Scan ¶
func (s *StringArray) Scan(value any) error
Scan implements sql.Scanner interface
type User ¶
type User struct {
ID string `gorm:"primaryKey"`
Username string `gorm:"uniqueIndex;not null"`
Email string `gorm:"uniqueIndex;not null"` // Email is unique and required
PasswordHash string // OAuth-only users have empty password
Role string `gorm:"not null;default:'user'"` // "admin" or "user"
FullName string // User full name
AvatarURL string // User avatar URL (from OAuth or manual)
// External authentication support
ExternalID string `gorm:"index"` // External user ID (e.g., from HTTP API)
AuthSource string `gorm:"default:'local'"` // "local" or "http_api"
CreatedAt time.Time
UpdatedAt time.Time
}
func (*User) IsExternal ¶
IsExternal returns true if user authenticates via external provider
type UserAuthorization ¶
type UserAuthorization struct {
ID uint `gorm:"primaryKey;autoIncrement"`
UUID string `gorm:"uniqueIndex;size:36;not null"` // Public UUID for API/UI identification
// Relations (composite unique index ensures one grant per user+app)
UserID string `gorm:"not null;uniqueIndex:idx_user_app"` // FK → User.ID
ApplicationID int64 `gorm:"not null;uniqueIndex:idx_user_app"` // FK → OAuthApplication.ID
ClientID string `gorm:"not null;index"` // Denormalized ClientID UUID (for UI display and API responses)
Scopes string `gorm:"not null"`
GrantedAt time.Time
RevokedAt *time.Time
IsActive bool `gorm:"not null;default:true"`
CreatedAt time.Time
UpdatedAt time.Time
}
UserAuthorization records a user's consent grant to an OAuth application. There is at most one active record per (UserID, ApplicationID) pair.
func (UserAuthorization) TableName ¶
func (UserAuthorization) TableName() string