Documentation
¶
Index ¶
- Variables
- func AuditLoginFailed(c *gin.Context, username, reason string)
- func AuditLoginSuccess(c *gin.Context, userID uint, rememberMe bool)
- func AuditLogout(c *gin.Context, userID uint)
- func AuditLogoutAll(c *gin.Context, userID uint, revokedSessions int64)
- func AuditRateLimitExceeded(c *gin.Context, endpoint string)
- func AuditRefreshFailed(c *gin.Context, reason string)
- func AuditRefreshReuseDetected(c *gin.Context, userID uint)
- func AuditRefreshSuccess(c *gin.Context, userID uint)
- func CleanupExpiredTokens(ctx context.Context) (int64, error)
- func ExtractToken(c *gin.Context) string
- func ExtractTokenID(c *gin.Context) (uint, error)
- func GenerateToken(userID uint) (string, error)
- func HasLiveRefreshToken(ctx context.Context, accountID uint) (bool, error)
- func HashPassword(password string) (string, error)
- func Headers() gin.HandlerFunc
- func JwtAuthAdminProcessor() gin.HandlerFunc
- func JwtAuthProcessor() gin.HandlerFunc
- func LogoutAllHandler(c *gin.Context)
- func LogoutHandler(c *gin.Context)
- func MaxBodyBytes(limit int64) gin.HandlerFunc
- func NewEndpointRateLimiter(endpoint string, requestsPerWindow, burstSize, windowMinutes int) gin.HandlerFunc
- func RefreshTokenHandler(c *gin.Context)
- func RevokeAllUserTokens(ctx context.Context, accountID uint) (int64, error)
- func RevokeRefreshToken(ctx context.Context, tokenString string) (uint, bool, error)
- func TokenValid(c *gin.Context) error
- func VerifyPassword(password, hashedPassword string) error
- type AuditEvent
- type AuditEventType
- type IPRateLimiter
- type LogoutAllResponse
- type RefreshResponse
- type RefreshToken
- type RefreshTokenInput
- type TokenPairResponse
Constants ¶
This section is empty.
Variables ¶
var ErrTokenAlreadyRotated = errors.New("refresh token already rotated")
ErrTokenAlreadyRotated is returned when a rotation loses the race against a concurrent rotation of the same token
Functions ¶
func AuditLoginFailed ¶ added in v0.16.0
AuditLoginFailed logs a failed login attempt
func AuditLoginSuccess ¶ added in v0.16.0
AuditLoginSuccess logs a successful login attempt
func AuditLogout ¶ added in v0.16.0
AuditLogout logs a logout event
func AuditLogoutAll ¶ added in v1.11.0
AuditLogoutAll logs a logout-from-all-devices event
func AuditRateLimitExceeded ¶ added in v0.16.0
AuditRateLimitExceeded logs a rate limit exceeded event
func AuditRefreshFailed ¶ added in v0.16.0
AuditRefreshFailed logs a failed token refresh attempt
func AuditRefreshReuseDetected ¶ added in v1.11.1
AuditRefreshReuseDetected logs the replay of a superseded refresh token beyond the rotation grace window — a possible token-theft signal surfaced for out-of-band alerting (no automatic revocation is performed)
func AuditRefreshSuccess ¶ added in v0.16.0
AuditRefreshSuccess logs a successful token refresh
func CleanupExpiredTokens ¶ added in v0.16.0
CleanupExpiredTokens deletes refresh tokens that can never be valid again: expired ones and revoked ones (logout, logout-all, password change)
func ExtractToken ¶
ExtractToken extracts the JWT from the Authorization header. Tokens are deliberately not accepted via query string: URLs leak into access logs, proxies, browser history and Referer headers.
func ExtractTokenID ¶
ExtractTokenID extracts user ID from token (existing function, moved here)
func GenerateToken ¶
GenerateToken generates a JWT access token (existing function, moved here)
func HasLiveRefreshToken ¶ added in v1.11.1
HasLiveRefreshToken reports whether the account still has at least one non-revoked, unexpired refresh token — used to deny the rotation grace once a logout/password-change/admin action has cleared the sessions.
func HashPassword ¶
HashPassword hashes a password using bcrypt
func Headers ¶ added in v1.11.0
func Headers() gin.HandlerFunc
Headers sets defense-in-depth response headers on every response. HSTS is intentionally left to the reverse proxy / load balancer.
func JwtAuthAdminProcessor ¶
func JwtAuthAdminProcessor() gin.HandlerFunc
JwtAuthAdminProcessor validates JWT and checks admin role (existing function, moved here). Alg-confusion and key-source attacks are handled by TokenValid (via jwtKeyFunc + WithValidMethods).
func JwtAuthProcessor ¶
func JwtAuthProcessor() gin.HandlerFunc
JwtAuthProcessor validates JWT tokens (existing function, moved here)
func LogoutAllHandler ¶ added in v1.11.0
LogoutAllHandler handles POST /v1/auth/logout-all @Summary Logout from all devices @Description Revoke all refresh tokens of the authenticated user @Security Bearer @Tags Authentication @Produce json @Success 200 {object} LogoutAllResponse @Failure 401 {object} apitypes.ErrorResponse "Unauthorized" @Failure 500 {object} apitypes.ErrorResponse "Internal server error" @Router /v1/auth/logout-all [post]
func LogoutHandler ¶ added in v1.11.0
LogoutHandler handles POST /auth/logout @Summary Logout (revoke a refresh token) @Description Revoke the presented refresh token, ending that session. Always 200: token existence cannot be probed. @Tags Authentication @Accept json @Produce json @Param refresh_token body RefreshTokenInput true "Refresh Token" @Success 200 {object} apitypes.OkResponse @Failure 400 {object} apitypes.ErrorResponse "Invalid input" @Failure 500 {object} apitypes.ErrorResponse "Internal server error" @Router /auth/logout [post]
func MaxBodyBytes ¶ added in v1.11.0
func MaxBodyBytes(limit int64) gin.HandlerFunc
MaxBodyBytes limits the size of the request body. Requests declaring a larger Content-Length are rejected with 413; bodies without a declared length are capped while reading via http.MaxBytesReader (the read error surfaces in the handler, typically as a 400 on binding).
func NewEndpointRateLimiter ¶ added in v1.6.1
func NewEndpointRateLimiter(endpoint string, requestsPerWindow, burstSize, windowMinutes int) gin.HandlerFunc
NewEndpointRateLimiter creates a rate limiting middleware for any endpoint
func RefreshTokenHandler ¶ added in v0.16.0
RefreshTokenHandler handles POST /auth/refresh @Summary Refresh access token @Description Exchange a valid refresh token for a new access token @Tags Authentication @Accept json @Produce json @Param refresh_token body RefreshTokenInput true "Refresh Token" @Success 200 {object} RefreshResponse @Failure 400 {object} apitypes.ErrorResponse "Invalid input" @Failure 401 {object} apitypes.ErrorResponse "Invalid or expired refresh token" @Failure 500 {object} apitypes.ErrorResponse "Internal server error" @Router /auth/refresh [post]
func RevokeAllUserTokens ¶ added in v1.11.0
RevokeAllUserTokens revokes every live refresh token of an account and returns how many sessions were revoked
func RevokeRefreshToken ¶ added in v1.11.0
RevokeRefreshToken marks a refresh token as revoked. It returns the owning account ID and whether a live token matched, so callers can audit the event yet respond generically either way (no token enumeration).
func TokenValid ¶
TokenValid validates a JWT token (existing function, moved here)
func VerifyPassword ¶
VerifyPassword verifies a password against a bcrypt hash
Types ¶
type AuditEvent ¶ added in v0.16.0
type AuditEvent struct {
Timestamp time.Time `json:"timestamp"`
EventType AuditEventType `json:"event_type"`
UserID *uint `json:"user_id,omitempty"`
Username string `json:"username,omitempty"`
IP string `json:"ip"`
UserAgent string `json:"user_agent,omitempty"`
Message string `json:"message"`
RememberMe bool `json:"remember_me,omitempty"`
}
AuditEvent represents a security audit event
type AuditEventType ¶ added in v0.16.0
type AuditEventType string
AuditEventType represents the type of audit event
const ( // Authentication events EventLoginSuccess AuditEventType = "login_success" EventLoginFailed AuditEventType = "login_failed" EventRefreshSuccess AuditEventType = "refresh_success" EventRefreshFailed AuditEventType = "refresh_failed" EventLogout AuditEventType = "logout_success" EventLogoutAll AuditEventType = "logout_all_success" EventRefreshReuse AuditEventType = "refresh_token_reuse_detected" EventRateLimitExceeded AuditEventType = "rate_limit_exceeded" )
type IPRateLimiter ¶ added in v0.16.0
type IPRateLimiter struct {
// contains filtered or unexported fields
}
IPRateLimiter manages rate limiters per IP address
func NewIPRateLimiter ¶ added in v0.16.0
func NewIPRateLimiter(requestsPerWindow, burstSize, windowMinutes int) *IPRateLimiter
NewIPRateLimiter creates a new IP-based rate limiter
func (*IPRateLimiter) GetLimiter ¶ added in v0.16.0
func (rl *IPRateLimiter) GetLimiter(ip string) *rate.Limiter
GetLimiter returns the rate limiter for an IP, creating if needed
func (*IPRateLimiter) RetryAfterSeconds ¶ added in v1.6.1
func (rl *IPRateLimiter) RetryAfterSeconds() int
RetryAfterSeconds returns the retry_after value in seconds based on the configured window
type LogoutAllResponse ¶ added in v1.11.0
type LogoutAllResponse struct {
Message string `json:"message"`
RevokedSessions int64 `json:"revoked_sessions"`
}
LogoutAllResponse is the response of POST /v1/auth/logout-all
type RefreshResponse ¶ added in v0.16.0
type RefreshResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token,omitempty"`
RefreshExpiresIn int64 `json:"refresh_expires_in,omitempty"`
}
RefreshResponse represents the response from refresh endpoint. RefreshToken carries the rotated successor the client must store — the presented token is revoked. The fields are absent only on the short reuse-grace path (benign multi-tab race), where no rotation happens.
type RefreshToken ¶ added in v0.16.0
type RefreshToken struct {
ID uint
Token string
AccountID uint
ExpiresAt time.Time
CreatedAt time.Time
LastUsedAt *time.Time
Revoked bool
// RotatedAt is set when the token was revoked because a successor was
// issued (rotation), nil when revoked by logout/password/admin action
RotatedAt *time.Time
}
RefreshToken represents a refresh token row in the database. It is a storage model, never serialized to clients — no json tags on purpose: Token holds the plaintext right after creation but the SHA-256 hash when read back from the database.
func CreateRefreshToken ¶ added in v0.16.0
func CreateRefreshToken(ctx context.Context, accountID uint, rememberMe bool) (*RefreshToken, error)
CreateRefreshToken creates a new refresh token for a user
func GetRefreshToken ¶ added in v0.16.0
func GetRefreshToken(ctx context.Context, tokenString string) (*RefreshToken, error)
GetRefreshToken retrieves a refresh token by token string
func RotateRefreshToken ¶ added in v1.11.1
func RotateRefreshToken(ctx context.Context, old *RefreshToken) (*RefreshToken, error)
RotateRefreshToken atomically revokes the presented token and issues its successor, preserving the session horizon. Returns ErrTokenAlreadyRotated when a concurrent rotation of the same token won the race.
type RefreshTokenInput ¶ added in v0.16.0
type RefreshTokenInput struct {
Token string `json:"refresh_token" binding:"required"`
}
RefreshTokenInput represents the input for refresh token endpoint
type TokenPairResponse ¶ added in v0.16.0
type TokenPairResponse struct {
Token string `json:"token"` // Backward compatibility - same as AccessToken
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
AccessExpiresIn int64 `json:"access_expires_in"`
RefreshExpiresIn int64 `json:"refresh_expires_in"`
}
TokenPairResponse represents access + refresh token pair
func GenerateTokenPair ¶ added in v0.16.0
func GenerateTokenPair(ctx context.Context, accountID uint, rememberMe bool) (*TokenPairResponse, error)
GenerateTokenPair generates both access and refresh tokens (NEW)