Documentation
¶
Index ¶
- func GetUserIDFromContext(ctx context.Context) string
- func GetUsernameFromContext(ctx context.Context) string
- func SetUserContext(ctx context.Context, user *User) context.Context
- type AccessToken
- type AuditDetails
- type AuditLog
- type AuthorizationCode
- type DeviceCode
- type EventSeverity
- type EventType
- type OAuthApplication
- type OAuthConnection
- type ResourceType
- type StringArray
- type User
- type UserAuthorization
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetUserIDFromContext ¶ added in v0.14.0
GetUserIDFromContext extracts user ID from context
func GetUsernameFromContext ¶
GetUsernameFromContext extracts the username from the user object in context. 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 GetUserFromContext ¶ added in v0.14.0
GetUserFromContext extracts full user object from context
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