auth

package
v0.0.0-...-dba3917 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 16, 2026 License: Apache-2.0 Imports: 42 Imported by: 0

README

Authentication and Authorization System for TMI

This package implements a secure, reliable, and robust authentication and authorization system for the TMI service, designed to work with the tmi-ux Angular web application.

Features

  • Multiple OAuth 2.0 Providers: Support for Google, GitHub, and Microsoft authentication
  • JWT-based Authentication: Secure JWT tokens for API authentication
  • Refresh Token Mechanism: Automatic token refresh without requiring re-authentication
  • Account Linking: Link multiple OAuth providers to a single user account
  • Role-based Authorization: Support for owner, writer, and reader roles
  • Redis Caching: High-performance caching of authorization data
  • Database Migrations: Automatic database schema management

Architecture

The authentication system uses a hybrid database approach:

  1. PostgreSQL as the primary persistent store for:

    • User accounts and profiles
    • OAuth provider configurations
    • Authorization data (roles, permissions)
    • Account linking information
  2. Redis for:

    • Authorization cache
    • Token management
    • Rate limiting
    • Session data

Setup

Prerequisites
  • PostgreSQL 12+
  • Redis 6+
  • Go 1.24+
Configuration
  1. Copy the .env.example file to .env:
cp .env.example .env
  1. Edit the .env file with your configuration values:
# PostgreSQL Configuration
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=your_postgres_user
POSTGRES_PASSWORD=your_postgres_password
POSTGRES_DB=tmi
POSTGRES_SSLMODE=disable

# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DB=0

# JWT Configuration
JWT_SECRET=your_jwt_secret_key
JWT_EXPIRATION_SECONDS=3600
JWT_SIGNING_METHOD=HS256

# OAuth Configuration
OAUTH_CALLBACK_URL=http://localhost:8080/oauth2/callback

# OAuth Provider Configuration
...
  1. Set up OAuth providers:

Integration

To integrate the authentication system into your application:

package main

import (
	"github.com/ericfitz/tmi/auth"
	"github.com/gin-gonic/gin"
)

func main() {
	// Load unified configuration
	config, err := config.Load()
	if err != nil {
		panic(err)
	}

	// Create a new Gin router
	router := gin.Default()

	// Initialize the authentication system with unified config
	// NOTE: Use InitAuthWithConfig, NOT the deprecated InitAuth function
	authHandlers, err := auth.InitAuthWithConfig(router, config)
	if err != nil {
		panic(err)
	}

	// Add your routes
	// ...

	// Start the server
	router.Run(":8080")
}

API Endpoints

OAuth Flow
  • GET /oauth2/providers - List available OAuth providers
  • GET /oauth2/authorize?idp={provider} - Redirect to OAuth provider for authentication
  • GET /oauth2/callback - Handle OAuth callback and issue JWT tokens
Token Management
  • POST /oauth2/token?idp={provider} - Exchange authorization code for JWT tokens
  • POST /oauth2/refresh - Refresh an expired JWT token
  • POST /oauth2/logout - Revoke a refresh token
User Information
  • GET /oauth2/me - Get current user information (requires authentication)

Authorization

To protect your API endpoints, use the authentication middleware:

// Create a new router group with authentication
protected := router.Group("/api")
protected.Use(authMiddleware.AuthRequired())

// Add routes that require authentication
protected.GET("/resource", getResource)

// Add routes that require specific roles
protected.POST("/resource", authMiddleware.RequireWriter(), createResource)
protected.PUT("/resource/:id", authMiddleware.RequireWriter(), updateResource)
protected.DELETE("/resource/:id", authMiddleware.RequireOwner(), deleteResource)

Database Migrations

The authentication system automatically runs database migrations on startup. The migration files are located in the migrations directory.

Cache Rebuilding

The authentication system includes a background job that periodically rebuilds the Redis cache from PostgreSQL to handle any potential inconsistencies.

Security Considerations

  • JWT tokens are short-lived (1 hour by default)
  • Refresh tokens are stored in Redis with automatic expiration
  • CSRF protection is implemented using state parameters
  • All sensitive data is stored securely
  • OAuth provider credentials are stored in environment variables

Documentation

Index

Constants

View Source
const (
	// MinVerifierLength is the minimum length for a code verifier (43 characters)
	MinVerifierLength = 43
	// MaxVerifierLength is the maximum length for a code verifier (128 characters)
	MaxVerifierLength = 128
	// VerifierByteLength is the number of random bytes to generate (32 bytes = 43 base64url chars)
	VerifierByteLength = 32
)

PKCE constants per RFC 7636

View Source
const (
	// UserCacheTTL defines how long user data is cached
	UserCacheTTL = 15 * time.Minute
)
View Source
const (

	// UserContextKey is the key for the user in the Gin context
	UserContextKey contextKey = "user"
)

Variables

View Source
var DefaultClaimMappings = map[string]string{
	"subject_claim":        "sub",
	"email_claim":          "email",
	"name_claim":           "name",
	"given_name_claim":     "given_name",
	"family_name_claim":    "family_name",
	"picture_claim":        "picture",
	"email_verified_claim": "email_verified",
	"groups_claim":         "groups",
}

DefaultClaimMappings provides standard claim names for common OAuth providers

View Source
var TestUsers = struct {
	Admin    User
	Regular  User
	External User
}{
	Admin: User{
		InternalUUID:   "admin-internal-uuid",
		Provider:       "tmi",
		ProviderUserID: "[email protected]",
		Email:          "[email protected]",
		Name:           "Admin User",
		EmailVerified:  true,
		Groups:         []string{"admins"},
		IsAdmin:        true,
		CreatedAt:      time.Now(),
		ModifiedAt:     time.Now(),
	},
	Regular: User{
		InternalUUID:   "regular-internal-uuid",
		Provider:       "tmi",
		ProviderUserID: "[email protected]",
		Email:          "[email protected]",
		Name:           "Regular User",
		EmailVerified:  true,
		Groups:         []string{},
		IsAdmin:        false,
		CreatedAt:      time.Now(),
		ModifiedAt:     time.Now(),
	},
	External: User{
		InternalUUID:   "external-internal-uuid",
		Provider:       "google",
		ProviderUserID: "[email protected]",
		Email:          "[email protected]",
		Name:           "External User",
		EmailVerified:  true,
		Groups:         []string{},
		IsAdmin:        false,
		CreatedAt:      time.Now(),
		ModifiedAt:     time.Now(),
	},
}

TestUsers provides standard test user identities for auth testing

Functions

func ComputeS256Challenge

func ComputeS256Challenge(codeVerifier string) string

ComputeS256Challenge computes the S256 code challenge from a code verifier Returns base64url(SHA256(codeVerifier))

func ExpectUserCreate

func ExpectUserCreate(mock sqlmock.Sqlmock)

ExpectUserCreate sets up mock expectation for user creation

func ExpectUserDelete

func ExpectUserDelete(mock sqlmock.Sqlmock, userID string)

ExpectUserDelete sets up mock expectation for user deletion

func ExpectUserQuery

func ExpectUserQuery(mock sqlmock.Sqlmock, email string, user *User)

ExpectUserQuery sets up mock expectation for a user query by email

func ExpectUserUpdate

func ExpectUserUpdate(mock sqlmock.Sqlmock)

ExpectUserUpdate sets up mock expectation for user update

func GenerateCodeVerifier

func GenerateCodeVerifier() (string, error)

GenerateCodeVerifier generates a cryptographically secure random code verifier Returns a 43-character base64url-encoded string (32 random bytes)

func GetDatabaseManager

func GetDatabaseManager() *db.Manager

GetDatabaseManager returns the global database manager

func InitAuth

func InitAuth(router *gin.Engine) error

InitAuth initializes the authentication system

func IntegrationExample

func IntegrationExample()

IntegrationExample shows how to integrate the authentication system with the main application

func MockEmptyUserRows

func MockEmptyUserRows(mock sqlmock.Sqlmock) *sqlmock.Rows

MockEmptyUserRows returns empty rows for user queries

func MockUserRow

func MockUserRow(mock sqlmock.Sqlmock, user User) *sqlmock.Rows

MockUserRow returns mock SQL rows for a user query

func SetupMockDB

func SetupMockDB(t *testing.T) (*sql.DB, sqlmock.Sqlmock)

SetupMockDB creates a mock SQL database for testing

func SetupMockRedis

func SetupMockRedis(t *testing.T) (*redis.Client, *miniredis.Miniredis)

SetupMockRedis creates a mock Redis client using miniredis

func Shutdown

func Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the authentication system

func ValidateCodeChallenge

func ValidateCodeChallenge(codeVerifier, codeChallenge, method string) error

ValidateCodeChallenge validates that a code verifier matches the code challenge Uses constant-time comparison to prevent timing attacks

func ValidateCodeChallengeFormat

func ValidateCodeChallengeFormat(challenge string) error

ValidateCodeChallengeFormat validates the format of a code challenge

func ValidateCodeVerifierFormat

func ValidateCodeVerifierFormat(verifier string) error

ValidateCodeVerifierFormat validates the format of a code verifier

func ValidateTokenClaims

func ValidateTokenClaims(t *testing.T, claims *Claims, user User)

ValidateTokenClaims is a helper to validate common JWT claims

Types

type AdminChecker

type AdminChecker interface {
	IsAdmin(ctx context.Context, userInternalUUID *string, provider string, groupUUIDs []string) (bool, error)
	GetGroupUUIDsByNames(ctx context.Context, provider string, groupNames []string) ([]string, error)
}

AdminChecker is an interface for checking if a user is an administrator

type AuthScenario

type AuthScenario struct {
	Name           string
	User           User
	RequiredRole   string
	ExpectedAccess bool
	SetupContext   func(context.Context) context.Context
}

AuthScenario represents an authorization test scenario

type BaseProvider

type BaseProvider struct {
	// contains filtered or unexported fields
}

BaseProvider provides common functionality for all providers

func NewBaseProvider

func NewBaseProvider(config OAuthProviderConfig, callbackURL string) (*BaseProvider, error)

NewBaseProvider creates a new base OAuth provider

func (*BaseProvider) ExchangeCode

func (p *BaseProvider) ExchangeCode(ctx context.Context, code string) (*TokenResponse, error)

ExchangeCode exchanges an authorization code for tokens

func (*BaseProvider) GetAuthorizationURL

func (p *BaseProvider) GetAuthorizationURL(state string) string

GetAuthorizationURL returns the authorization URL with the given state

func (*BaseProvider) GetOAuth2Config

func (p *BaseProvider) GetOAuth2Config() *oauth2.Config

GetOAuth2Config returns the OAuth2 configuration

func (*BaseProvider) GetUserInfo

func (p *BaseProvider) GetUserInfo(ctx context.Context, accessToken string) (*UserInfo, error)

GetUserInfo gets user information from the provider

func (*BaseProvider) ValidateIDToken

func (p *BaseProvider) ValidateIDToken(ctx context.Context, idToken string) (*IDTokenClaims, error)

ValidateIDToken validates an ID token

type Claims

type Claims struct {
	Email            string   `json:"email"`
	EmailVerified    bool     `json:"email_verified,omitempty"`
	Name             string   `json:"name"`
	IdentityProvider string   `json:"idp,omitempty"`    // Identity provider
	Groups           []string `json:"groups,omitempty"` // User's groups from IdP
	jwt.RegisteredClaims
}

Claims represents the JWT claims

type ClientCredential

type ClientCredential struct {
	ID               uuid.UUID
	OwnerUUID        uuid.UUID
	ClientID         string
	ClientSecretHash string
	Name             string
	Description      string
	IsActive         bool
	LastUsedAt       *time.Time
	CreatedAt        time.Time
	ModifiedAt       time.Time
	ExpiresAt        *time.Time
}

ClientCredential represents an OAuth 2.0 client credential for machine-to-machine authentication

func CreateTestClientCredential

func CreateTestClientCredential(ownerUUID uuid.UUID, name string) *ClientCredential

CreateTestClientCredential creates a test client credential

type ClientCredentialCreateParams

type ClientCredentialCreateParams struct {
	OwnerUUID        uuid.UUID
	ClientID         string
	ClientSecretHash string
	Name             string
	Description      string
	ExpiresAt        *time.Time
}

ClientCredentialCreateParams contains parameters for creating a new client credential

type ClientCredentialTestCase

type ClientCredentialTestCase struct {
	Name          string
	ClientID      string
	ClientSecret  string
	ExpectSuccess bool
	ExpectedError string
	SetupMock     func(sqlmock.Sqlmock)
	VerifyResult  func(*testing.T, *TokenPair)
}

ClientCredentialTestCase represents a test case for client credential operations

type Config

type Config struct {
	Database  DatabaseConfig // New unified database config
	Postgres  PostgresConfig // Legacy - kept for backward compatibility
	Redis     RedisConfig
	JWT       JWTConfig
	OAuth     OAuthConfig
	SAML      SAMLConfig
	BuildMode string // dev, test, or production
}

Config holds all authentication configuration

func ConfigFromUnified

func ConfigFromUnified(unified *config.Config) Config

ConfigFromUnified converts unified config to auth-specific config

func LoadConfig

func LoadConfig() (Config, error)

LoadConfig loads configuration from environment variables

func (*Config) GetEnabledProviders

func (c *Config) GetEnabledProviders() []OAuthProviderConfig

GetEnabledProviders returns a slice of enabled OAuth providers

func (*Config) GetJWTDuration

func (c *Config) GetJWTDuration() time.Duration

GetJWTDuration returns the JWT expiration duration

func (*Config) GetProvider

func (c *Config) GetProvider(providerID string) (OAuthProviderConfig, bool)

GetProvider returns a specific OAuth provider configuration

func (*Config) ToDBConfig

func (c *Config) ToDBConfig() (db.PostgresConfig, db.RedisConfig)

ToDBConfig converts Config to db.PostgresConfig and db.RedisConfig (legacy method)

func (*Config) ToGormConfig

func (c *Config) ToGormConfig() db.GormConfig

ToGormConfig converts Config to db.GormConfig for GORM database connections

func (*Config) ToRedisConfig

func (c *Config) ToRedisConfig() db.RedisConfig

ToRedisConfig converts Config to db.RedisConfig

func (*Config) ValidateConfig

func (c *Config) ValidateConfig() error

ValidateConfig validates the configuration

type DatabaseConfig

type DatabaseConfig struct {
	Type string // "postgres" or "oracle"

	// PostgreSQL configuration
	PostgresHost     string
	PostgresPort     string
	PostgresUser     string
	PostgresPassword string
	PostgresDatabase string
	PostgresSSLMode  string

	// Oracle configuration
	OracleUser           string
	OraclePassword       string
	OracleConnectString  string // format: host:port/service or tnsnames alias
	OracleWalletLocation string // path to Oracle wallet for ADB
}

DatabaseConfig holds unified database configuration for both PostgreSQL and Oracle

type DeletionChallenge

type DeletionChallenge struct {
	ChallengeText string    `json:"challenge_text"`
	ExpiresAt     time.Time `json:"expires_at"`
}

DeletionChallenge contains challenge information for user deletion

type DeletionResult

type DeletionResult struct {
	ThreatModelsTransferred int    `json:"threat_models_transferred"`
	ThreatModelsDeleted     int    `json:"threat_models_deleted"`
	UserEmail               string `json:"user_email"`
}

DeletionResult contains statistics about the user deletion operation

type GenericOIDCProvider

type GenericOIDCProvider struct {
	BaseProvider
	// contains filtered or unexported fields
}

GenericOIDCProvider is a generic OIDC provider

func NewGenericOIDCProvider

func NewGenericOIDCProvider(config OAuthProviderConfig, callbackURL string) (*GenericOIDCProvider, error)

NewGenericOIDCProvider creates a new generic OIDC provider

func (*GenericOIDCProvider) ValidateIDToken

func (p *GenericOIDCProvider) ValidateIDToken(ctx context.Context, idToken string) (*IDTokenClaims, error)

ValidateIDToken validates an ID token

type GroupDeletionResult

type GroupDeletionResult struct {
	ThreatModelsDeleted  int    `json:"threat_models_deleted"`
	ThreatModelsRetained int    `json:"threat_models_retained"`
	GroupName            string `json:"group_name"`
}

GroupDeletionResult contains statistics about the group deletion operation

type Handlers

type Handlers struct {
	// contains filtered or unexported fields
}

Handlers provides HTTP handlers for authentication

func InitAuthWithConfig

func InitAuthWithConfig(router *gin.Engine, unified *config.Config) (*Handlers, error)

InitAuthWithConfig initializes the auth system with unified configuration

func NewHandlers

func NewHandlers(service *Service, config Config) *Handlers

NewHandlers creates new authentication handlers

func (*Handlers) Authorize

func (h *Handlers) Authorize(c *gin.Context)

Authorize redirects to the OAuth provider's authorization page

func (*Handlers) Callback

func (h *Handlers) Callback(c *gin.Context)

Callback handles the OAuth callback

func (*Handlers) Config

func (h *Handlers) Config() Config

Config returns the auth config (getter for unexported field)

func (*Handlers) Exchange

func (h *Handlers) Exchange(c *gin.Context)

Exchange exchanges an authorization code for tokens (legacy endpoint, delegates to handleAuthorizationCodeGrant)

func (*Handlers) GetJWKS

func (h *Handlers) GetJWKS(c *gin.Context)

GetJWKS returns the JSON Web Key Set for JWT signature verification

func (*Handlers) GetOAuthAuthorizationServerMetadata

func (h *Handlers) GetOAuthAuthorizationServerMetadata(c *gin.Context)

GetOAuthAuthorizationServerMetadata returns OAuth 2.0 Authorization Server metadata

func (*Handlers) GetOAuthProtectedResourceMetadata

func (h *Handlers) GetOAuthProtectedResourceMetadata(c *gin.Context)

GetOAuthProtectedResourceMetadata returns OAuth 2.0 protected resource metadata as per RFC 9728

func (*Handlers) GetOpenIDConfiguration

func (h *Handlers) GetOpenIDConfiguration(c *gin.Context)

GetOpenIDConfiguration returns OpenID Connect Discovery metadata

func (*Handlers) GetProviders

func (h *Handlers) GetProviders(c *gin.Context)

GetProviders returns the available OAuth providers

func (*Handlers) GetSAMLMetadata

func (h *Handlers) GetSAMLMetadata(c *gin.Context, providerID string)

GetSAMLMetadata returns SAML service provider metadata

func (*Handlers) GetSAMLProviders

func (h *Handlers) GetSAMLProviders(c *gin.Context)

GetSAMLProviders returns the available SAML providers

func (*Handlers) InitiateSAMLLogin

func (h *Handlers) InitiateSAMLLogin(c *gin.Context, providerID string, clientCallback *string)

InitiateSAMLLogin starts SAML authentication flow

func (*Handlers) IntrospectToken

func (h *Handlers) IntrospectToken(c *gin.Context)

IntrospectToken handles token introspection requests per RFC 7662

func (*Handlers) Logout

func (h *Handlers) Logout(c *gin.Context)

Logout blacklists a JWT token

func (*Handlers) Me

func (h *Handlers) Me(c *gin.Context)

Me returns the current user

func (*Handlers) ProcessSAMLLogout

func (h *Handlers) ProcessSAMLLogout(c *gin.Context, providerID string, samlRequest string)

ProcessSAMLLogout handles SAML single logout

func (*Handlers) ProcessSAMLResponse

func (h *Handlers) ProcessSAMLResponse(c *gin.Context, providerID string, samlResponse string, relayState string)

ProcessSAMLResponse handles SAML assertion consumer service

func (*Handlers) Refresh

func (h *Handlers) Refresh(c *gin.Context)

Refresh refreshes an access token

func (*Handlers) Service

func (h *Handlers) Service() *Service

Service returns the auth service (getter for unexported field)

func (*Handlers) SetAdminChecker

func (h *Handlers) SetAdminChecker(checker AdminChecker)

SetAdminChecker sets the admin checker for the handlers

func (*Handlers) Token

func (h *Handlers) Token(c *gin.Context)

Token exchanges an authorization code for tokens

type IDTokenClaims

type IDTokenClaims struct {
	Subject       string `json:"sub"`
	Email         string `json:"email,omitempty"`
	EmailVerified bool   `json:"email_verified,omitempty"`
	Name          string `json:"name,omitempty"`
	GivenName     string `json:"given_name,omitempty"`
	FamilyName    string `json:"family_name,omitempty"`
	Picture       string `json:"picture,omitempty"`
	Locale        string `json:"locale,omitempty"`
	Issuer        string `json:"iss"`
	Audience      string `json:"aud"`
	ExpiresAt     int64  `json:"exp"`
	IssuedAt      int64  `json:"iat"`
}

IDTokenClaims contains the claims from an ID token

type InMemoryStateStore

type InMemoryStateStore struct {
	// contains filtered or unexported fields
}

InMemoryStateStore implements StateStore using in-memory storage

func NewInMemoryStateStore

func NewInMemoryStateStore() *InMemoryStateStore

NewInMemoryStateStore creates a new in-memory state store

func (*InMemoryStateStore) Close

func (s *InMemoryStateStore) Close()

Close stops the cleanup goroutine

func (*InMemoryStateStore) DeletePKCEChallenge

func (s *InMemoryStateStore) DeletePKCEChallenge(ctx context.Context, state string) error

DeletePKCEChallenge removes PKCE challenge from store

func (*InMemoryStateStore) DeleteState

func (s *InMemoryStateStore) DeleteState(ctx context.Context, state string) error

DeleteState removes a state from the store

func (*InMemoryStateStore) GetCallbackURL

func (s *InMemoryStateStore) GetCallbackURL(ctx context.Context, state string) (string, error)

GetCallbackURL retrieves the callback URL for a state

func (*InMemoryStateStore) GetPKCEChallenge

func (s *InMemoryStateStore) GetPKCEChallenge(ctx context.Context, state string) (challenge, method string, err error)

GetPKCEChallenge retrieves PKCE code challenge and method for a state

func (*InMemoryStateStore) StoreCallbackURL

func (s *InMemoryStateStore) StoreCallbackURL(ctx context.Context, state, callbackURL string, ttl time.Duration) error

StoreCallbackURL stores a callback URL with a state

func (*InMemoryStateStore) StorePKCEChallenge

func (s *InMemoryStateStore) StorePKCEChallenge(ctx context.Context, state, codeChallenge, challengeMethod string, ttl time.Duration) error

StorePKCEChallenge stores PKCE code challenge with associated method

func (*InMemoryStateStore) StoreState

func (s *InMemoryStateStore) StoreState(ctx context.Context, state, data string, ttl time.Duration) error

StoreState stores state with associated data

func (*InMemoryStateStore) ValidateState

func (s *InMemoryStateStore) ValidateState(ctx context.Context, state string) (string, error)

ValidateState validates state and returns associated data

type JWK

type JWK struct {
	KeyType   string   `json:"kty"`
	Use       string   `json:"use,omitempty"`
	KeyOps    []string `json:"key_ops,omitempty"`
	KeyID     string   `json:"kid,omitempty"`
	Algorithm string   `json:"alg,omitempty"`
	// RSA parameters
	N string `json:"n,omitempty"` // RSA modulus
	E string `json:"e,omitempty"` // RSA exponent
	// ECDSA parameters
	Curve string `json:"crv,omitempty"` // Elliptic curve
	X     string `json:"x,omitempty"`   // X coordinate
	Y     string `json:"y,omitempty"`   // Y coordinate
}

JWK represents a JSON Web Key

type JWKSResponse

type JWKSResponse struct {
	Keys []JWK `json:"keys"`
}

JWKSResponse represents a JSON Web Key Set response

type JWTConfig

type JWTConfig struct {
	Secret            string // Used for HS256
	ExpirationSeconds int
	SigningMethod     string // HS256, RS256, ES256
	KeyID             string // Key ID for JWKS (defaults to "1")
	// RSA Keys (for RS256)
	RSAPrivateKeyPath string // Path to RSA private key file
	RSAPublicKeyPath  string // Path to RSA public key file
	RSAPrivateKey     string // RSA private key as string (alternative to file path)
	RSAPublicKey      string // RSA public key as string (alternative to file path)
	// ECDSA Keys (for ES256)
	ECDSAPrivateKeyPath string // Path to ECDSA private key file
	ECDSAPublicKeyPath  string // Path to ECDSA public key file
	ECDSAPrivateKey     string // ECDSA private key as string (alternative to file path)
	ECDSAPublicKey      string // ECDSA public key as string (alternative to file path)
}

JWTConfig holds JWT configuration

type JWTKeyManager

type JWTKeyManager struct {
	// contains filtered or unexported fields
}

JWTKeyManager manages JWT signing and verification keys

func NewJWTKeyManager

func NewJWTKeyManager(config JWTConfig) (*JWTKeyManager, error)

NewJWTKeyManager creates a new JWT key manager

func SetupTestKeyManager

func SetupTestKeyManager(t *testing.T) *JWTKeyManager

SetupTestKeyManager creates a key manager for testing

func (*JWTKeyManager) CreateToken

func (m *JWTKeyManager) CreateToken(claims jwt.Claims) (string, error)

CreateToken creates a new JWT token with the configured signing method

func (*JWTKeyManager) GetPublicKey

func (m *JWTKeyManager) GetPublicKey() interface{}

GetPublicKey returns the public key for JWKS endpoint (for asymmetric methods)

func (*JWTKeyManager) GetSigningMethod

func (m *JWTKeyManager) GetSigningMethod() string

GetSigningMethod returns the current signing method

func (*JWTKeyManager) VerifyToken

func (m *JWTKeyManager) VerifyToken(tokenString string, claims jwt.Claims) (*jwt.Token, error)

VerifyToken verifies a JWT token using the configured verification key

type OAuthAuthorizationServerMetadata

type OAuthAuthorizationServerMetadata struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	JWKSURI                           string   `json:"jwks_uri,omitempty"`
	ScopesSupported                   []string `json:"scopes_supported,omitempty"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	ResponseModesSupported            []string `json:"response_modes_supported,omitempty"`
	GrantTypesSupported               []string `json:"grant_types_supported,omitempty"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported,omitempty"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint,omitempty"`
	RevocationEndpoint                string   `json:"revocation_endpoint,omitempty"`
}

OAuthAuthorizationServerMetadata represents OAuth 2.0 Authorization Server Metadata

type OAuthConfig

type OAuthConfig struct {
	CallbackURL string
	Providers   map[string]OAuthProviderConfig
}

OAuthConfig holds OAuth configuration

type OAuthProtectedResourceMetadata

type OAuthProtectedResourceMetadata struct {
	Resource                              string   `json:"resource"`
	ScopesSupported                       []string `json:"scopes_supported,omitempty"`
	AuthorizationServers                  []string `json:"authorization_servers,omitempty"`
	JWKSURI                               string   `json:"jwks_uri,omitempty"`
	BearerMethodsSupported                []string `json:"bearer_methods_supported,omitempty"`
	ResourceName                          string   `json:"resource_name,omitempty"`
	ResourceDocumentation                 string   `json:"resource_documentation,omitempty"`
	TLSClientCertificateBoundAccessTokens bool     `json:"tls_client_certificate_bound_access_tokens"`
}

OAuthProtectedResourceMetadata represents OAuth 2.0 protected resource metadata as defined in RFC 9728

type OAuthProviderConfig

type OAuthProviderConfig struct {
	ID               string             `json:"id"`
	Name             string             `json:"name"`
	Enabled          bool               `json:"enabled"`
	Icon             string             `json:"icon"`
	ClientID         string             `json:"client_id"`
	ClientSecret     string             `json:"client_secret"`
	AuthorizationURL string             `json:"authorization_url"`
	TokenURL         string             `json:"token_url"`
	UserInfo         []UserInfoEndpoint `json:"userinfo"`
	Issuer           string             `json:"issuer"`
	JWKSURL          string             `json:"jwks_url"`
	Scopes           []string           `json:"scopes"`
	AdditionalParams map[string]string  `json:"additional_params"`
	AuthHeaderFormat string             `json:"auth_header_format,omitempty"` // Default: "Bearer %s"
	AcceptHeader     string             `json:"accept_header,omitempty"`      // Default: "application/json"
}

OAuthProviderConfig holds configuration for an OAuth provider

type OpenIDConfiguration

type OpenIDConfiguration struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	UserInfoEndpoint                  string   `json:"userinfo_endpoint"`
	JWKSURI                           string   `json:"jwks_uri"`
	ScopesSupported                   []string `json:"scopes_supported"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	ResponseModesSupported            []string `json:"response_modes_supported,omitempty"`
	GrantTypesSupported               []string `json:"grant_types_supported,omitempty"`
	SubjectTypesSupported             []string `json:"subject_types_supported"`
	IDTokenSigningAlgValuesSupported  []string `json:"id_token_signing_alg_values_supported"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
	ClaimsSupported                   []string `json:"claims_supported,omitempty"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported,omitempty"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint,omitempty"`
	RevocationEndpoint                string   `json:"revocation_endpoint,omitempty"`
}

OpenIDConfiguration represents the OpenID Connect Discovery metadata

type PostgresConfig

type PostgresConfig struct {
	Host     string
	Port     string
	User     string
	Password string
	Database string
	SSLMode  string
}

PostgresConfig holds PostgreSQL configuration (legacy - for backward compatibility)

type Provider

type Provider interface {
	// GetOAuth2Config returns the OAuth2 configuration
	GetOAuth2Config() *oauth2.Config

	// GetAuthorizationURL returns the authorization URL with the given state
	GetAuthorizationURL(state string) string

	// ExchangeCode exchanges an authorization code for tokens
	ExchangeCode(ctx context.Context, code string) (*TokenResponse, error)

	// GetUserInfo gets user information from the provider
	GetUserInfo(ctx context.Context, accessToken string) (*UserInfo, error)

	// ValidateIDToken validates an ID token
	ValidateIDToken(ctx context.Context, idToken string) (*IDTokenClaims, error)
}

Provider is the interface for OAuth providers

func NewProvider

func NewProvider(config OAuthProviderConfig, callbackURL string) (Provider, error)

NewProvider creates a new OAuth provider based on the provider ID

type ProviderInfo

type ProviderInfo struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Icon        string `json:"icon"`
	AuthURL     string `json:"auth_url"`
	TokenURL    string `json:"token_url"`
	RedirectURI string `json:"redirect_uri"`
	ClientID    string `json:"client_id"`
}

ProviderInfo contains information about an OAuth provider

type RedisConfig

type RedisConfig struct {
	Host     string
	Port     string
	Password string
	DB       int
}

RedisConfig holds Redis configuration

type SAMLConfig

type SAMLConfig struct {
	Enabled   bool                          `json:"enabled"`
	Providers map[string]SAMLProviderConfig `json:"providers"`
}

SAMLConfig holds SAML configuration

type SAMLManager

type SAMLManager struct {
	// contains filtered or unexported fields
}

SAMLManager manages SAML providers

func NewSAMLManager

func NewSAMLManager(service *Service) *SAMLManager

NewSAMLManager creates a new SAML manager

func (*SAMLManager) GetProvider

func (m *SAMLManager) GetProvider(id string) (*saml.SAMLProvider, error)

GetProvider returns a SAML provider by ID

func (*SAMLManager) InitializeProviders

func (m *SAMLManager) InitializeProviders(config SAMLConfig, stateStore StateStore) error

InitializeProviders initializes all configured SAML providers

func (*SAMLManager) ListProviders

func (m *SAMLManager) ListProviders() []string

ListProviders returns a list of configured SAML provider IDs

func (*SAMLManager) ProcessSAMLResponse

func (m *SAMLManager) ProcessSAMLResponse(ctx context.Context, providerID string, samlResponse string, relayState string) (*User, *TokenPair, error)

ProcessSAMLResponse processes a SAML response for any provider

type SAMLProviderConfig

type SAMLProviderConfig struct {
	ID                string `json:"id"`
	Name              string `json:"name"`
	Enabled           bool   `json:"enabled"`
	Icon              string `json:"icon"`
	EntityID          string `json:"entity_id"`
	MetadataURL       string `json:"metadata_url"`
	MetadataXML       string `json:"metadata_xml"`
	ACSURL            string `json:"acs_url"`
	SLOURL            string `json:"slo_url"`
	SPPrivateKey      string `json:"sp_private_key"`
	SPPrivateKeyPath  string `json:"sp_private_key_path"`
	SPCertificate     string `json:"sp_certificate"`
	SPCertificatePath string `json:"sp_certificate_path"`
	IDPMetadataURL    string `json:"idp_metadata_url"`
	IDPMetadataXML    string `json:"idp_metadata_xml"`
	AllowIDPInitiated bool   `json:"allow_idp_initiated"`
	ForceAuthn        bool   `json:"force_authn"`
	SignRequests      bool   `json:"sign_requests"`
	NameIDAttribute   string `json:"name_id_attribute"`
	EmailAttribute    string `json:"email_attribute"`
	NameAttribute     string `json:"name_attribute"`
	GroupsAttribute   string `json:"groups_attribute"`
}

SAMLProviderConfig holds configuration for a SAML provider

type SAMLProviderInfo

type SAMLProviderInfo struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Icon        string `json:"icon"`
	AuthURL     string `json:"auth_url"`
	MetadataURL string `json:"metadata_url"`
	EntityID    string `json:"entity_id"`
	ACSURL      string `json:"acs_url"`
	SLOURL      string `json:"slo_url,omitempty"`
}

SAMLProviderInfo contains public information about a SAML provider

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides authentication and authorization functionality

func NewService

func NewService(dbManager *db.Manager, config Config) (*Service, error)

NewService creates a new authentication service

func (*Service) CacheUser

func (s *Service) CacheUser(ctx context.Context, user User) error

CacheUser stores a user in Redis cache with multiple lookup keys

func (*Service) CacheUserGroups

func (s *Service) CacheUserGroups(ctx context.Context, email, idp string, groups []string) error

CacheUserGroups caches user groups in Redis for the session duration

func (*Service) ClearUserGroups

func (s *Service) ClearUserGroups(ctx context.Context, email string) error

ClearUserGroups clears cached user groups from Redis (used on logout)

func (*Service) CreateClientCredential

func (s *Service) CreateClientCredential(ctx context.Context, params ClientCredentialCreateParams) (*ClientCredential, error)

CreateClientCredential creates a new client credential in the database

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, user User) (User, error)

CreateUser creates a new user

func (*Service) DeactivateClientCredential

func (s *Service) DeactivateClientCredential(ctx context.Context, id uuid.UUID, ownerUUID uuid.UUID) error

DeactivateClientCredential deactivates a client credential (soft delete)

func (*Service) DeleteClientCredential

func (s *Service) DeleteClientCredential(ctx context.Context, id uuid.UUID, ownerUUID uuid.UUID) error

DeleteClientCredential permanently deletes a client credential

func (*Service) DeleteGroupAndData

func (s *Service) DeleteGroupAndData(ctx context.Context, groupName string) (*GroupDeletionResult, error)

DeleteGroupAndData deletes a TMI-managed group and handles threat model cleanup Groups are always provider-independent (provider="*") in TMI

func (*Service) DeleteUser

func (s *Service) DeleteUser(ctx context.Context, id string) error

DeleteUser deletes a user by internal UUID

func (*Service) DeleteUserAndData

func (s *Service) DeleteUserAndData(ctx context.Context, userEmail string) (*DeletionResult, error)

DeleteUserAndData deletes a user and handles ownership transfer for threat models

func (*Service) GenerateDeletionChallenge

func (s *Service) GenerateDeletionChallenge(ctx context.Context, userEmail string) (*DeletionChallenge, error)

GenerateDeletionChallenge creates a challenge token for user deletion

func (*Service) GenerateTokens

func (s *Service) GenerateTokens(ctx context.Context, user User) (TokenPair, error)

GenerateTokens generates a new JWT token pair for a user

func (*Service) GenerateTokensWithUserInfo

func (s *Service) GenerateTokensWithUserInfo(ctx context.Context, user User, userInfo *UserInfo) (TokenPair, error)

GenerateTokensWithUserInfo generates a new JWT token pair for a user with optional provider UserInfo

func (*Service) GetCachedGroups

func (s *Service) GetCachedGroups(ctx context.Context, email string) (string, []string, error)

GetCachedGroups retrieves cached user groups from Redis

func (*Service) GetCachedUserByEmail

func (s *Service) GetCachedUserByEmail(ctx context.Context, email string) (*User, error)

GetCachedUserByEmail retrieves a user from cache by email

func (*Service) GetCachedUserByID

func (s *Service) GetCachedUserByID(ctx context.Context, userID string) (*User, error)

GetCachedUserByID retrieves a user from cache by internal UUID

func (*Service) GetCachedUserByProvider

func (s *Service) GetCachedUserByProvider(ctx context.Context, provider, providerUserID string) (*User, error)

GetCachedUserByProvider retrieves a user from cache by provider and provider user ID

func (*Service) GetClientCredentialByClientID

func (s *Service) GetClientCredentialByClientID(ctx context.Context, clientID string) (*ClientCredential, error)

GetClientCredentialByClientID retrieves a client credential by its client_id

func (*Service) GetKeyManager

func (s *Service) GetKeyManager() *JWTKeyManager

GetKeyManager returns the JWT key manager (getter for unexported field)

func (*Service) GetPrimaryProviderID

func (s *Service) GetPrimaryProviderID(ctx context.Context, userID string) (string, error)

GetPrimaryProviderID gets the provider user ID for a user Note: In the new architecture, each user has exactly one provider stored directly on the users table

func (*Service) GetSAMLManager

func (s *Service) GetSAMLManager() *SAMLManager

GetSAMLManager returns the SAML manager (getter for unexported field)

func (*Service) GetUserByAnyProviderID

func (s *Service) GetUserByAnyProviderID(ctx context.Context, providerUserID string) (User, error)

GetUserByAnyProviderID gets a user by provider ID across all providers This allows provider-independent authorization using IdP user IDs NOTE: This can return ambiguous results if the same provider_user_id exists for multiple providers

func (*Service) GetUserByEmail

func (s *Service) GetUserByEmail(ctx context.Context, email string) (User, error)

GetUserByEmail gets a user by email

func (*Service) GetUserByID

func (s *Service) GetUserByID(ctx context.Context, id string) (User, error)

GetUserByID gets a user by internal UUID

func (*Service) GetUserByProviderAndEmail

func (s *Service) GetUserByProviderAndEmail(ctx context.Context, provider, email string) (User, error)

GetUserByProviderAndEmail gets a user by provider and email address This is used as a fallback when provider_user_id doesn't match but same provider + email does

func (*Service) GetUserByProviderID

func (s *Service) GetUserByProviderID(ctx context.Context, provider, providerUserID string) (User, error)

GetUserByProviderID gets a user by provider and provider user ID

func (*Service) GetUserProviders

func (s *Service) GetUserProviders(ctx context.Context, userID string) ([]UserProvider, error)

GetUserProviders gets the OAuth provider for a user Note: In the new architecture, each user has exactly one provider

func (*Service) HandleClientCredentialsGrant

func (s *Service) HandleClientCredentialsGrant(ctx context.Context, clientID, clientSecret string) (*TokenPair, error)

HandleClientCredentialsGrant processes OAuth 2.0 Client Credentials Grant (RFC 6749 Section 4.4) Returns an access token for machine-to-machine authentication

func (*Service) InvalidateUserCache

func (s *Service) InvalidateUserCache(ctx context.Context, user User) error

InvalidateUserCache removes a user from all cache keys

func (*Service) InvalidateUserSessions

func (s *Service) InvalidateUserSessions(ctx context.Context, userID string) error

InvalidateUserSessions invalidates all sessions for a user

func (*Service) ListClientCredentialsByOwner

func (s *Service) ListClientCredentialsByOwner(ctx context.Context, ownerUUID uuid.UUID) ([]*ClientCredential, error)

ListClientCredentialsByOwner retrieves all client credentials for a given owner

func (*Service) RefreshToken

func (s *Service) RefreshToken(ctx context.Context, refreshToken string) (TokenPair, error)

RefreshToken refreshes an access token using a refresh token

func (*Service) RevokeToken

func (s *Service) RevokeToken(ctx context.Context, refreshToken string) error

RevokeToken revokes a refresh token

func (*Service) UpdateClientCredentialLastUsed

func (s *Service) UpdateClientCredentialLastUsed(ctx context.Context, id uuid.UUID) error

UpdateClientCredentialLastUsed updates the last_used_at timestamp for a client credential

func (*Service) UpdateUser

func (s *Service) UpdateUser(ctx context.Context, user User) error

UpdateUser updates an existing user

func (*Service) ValidateDeletionChallenge

func (s *Service) ValidateDeletionChallenge(ctx context.Context, userEmail, challengeText string) error

ValidateDeletionChallenge verifies the challenge string matches the stored token

func (*Service) ValidateToken

func (s *Service) ValidateToken(tokenString string) (*Claims, error)

ValidateToken validates a JWT token

type StateStore

type StateStore interface {
	// StoreState stores state with associated data and expiration
	StoreState(ctx context.Context, state, data string, ttl time.Duration) error
	// ValidateState checks if state is valid and returns associated data
	ValidateState(ctx context.Context, state string) (string, error)
	// GetCallbackURL retrieves the callback URL associated with a state
	GetCallbackURL(ctx context.Context, state string) (string, error)
	// StoreCallbackURL stores a callback URL with a state
	StoreCallbackURL(ctx context.Context, state, callbackURL string, ttl time.Duration) error
	// DeleteState removes state from store
	DeleteState(ctx context.Context, state string) error
	// StorePKCEChallenge stores PKCE code challenge with associated method
	StorePKCEChallenge(ctx context.Context, state, codeChallenge, challengeMethod string, ttl time.Duration) error
	// GetPKCEChallenge retrieves PKCE code challenge and method for a state
	GetPKCEChallenge(ctx context.Context, state string) (challenge, method string, err error)
	// DeletePKCEChallenge removes PKCE challenge from store
	DeletePKCEChallenge(ctx context.Context, state string) error
}

StateStore is an interface for storing and retrieving state information

type TestHelper

type TestHelper struct {
	DB          *sql.DB
	Mock        sqlmock.Sqlmock
	Redis       *redis.Client
	MiniRedis   *miniredis.Miniredis
	KeyManager  *JWTKeyManager
	StateStore  StateStore
	TestContext context.Context
}

TestHelper provides utilities for testing auth package functionality

func NewTestHelper

func NewTestHelper(t *testing.T) *TestHelper

NewTestHelper creates a new test helper with mocked dependencies

func (*TestHelper) Cleanup

func (h *TestHelper) Cleanup()

Cleanup releases all resources held by the test helper

func (*TestHelper) FastForwardRedis

func (h *TestHelper) FastForwardRedis(duration time.Duration)

FastForwardRedis advances time in miniredis for TTL testing

func (*TestHelper) FlushRedis

func (h *TestHelper) FlushRedis()

FlushRedis clears all keys in miniredis

func (*TestHelper) GetRedisKey

func (h *TestHelper) GetRedisKey(key string) (string, error)

GetRedisKey gets a key from miniredis for testing

func (*TestHelper) SetRedisKey

func (h *TestHelper) SetRedisKey(key, value string, expiration time.Duration) error

SetRedisKey sets a key in miniredis for testing

type TestProvider

type TestProvider struct {
	*BaseProvider
	// contains filtered or unexported fields
}

TestProvider implements the TMI internal OAuth provider In dev/test builds (TMI_BUILD_MODE=dev|test): supports Authorization Code flow with ephemeral user creation In production builds: Only supports Client Credentials Grant for machine-to-machine authentication

func NewTestProvider

func NewTestProvider(config OAuthProviderConfig, callbackURL string) *TestProvider

NewTestProvider creates a new test OAuth provider

func (*TestProvider) ExchangeCode

func (p *TestProvider) ExchangeCode(ctx context.Context, code string) (*TokenResponse, error)

ExchangeCode validates the authorization code and returns tokens only for valid codes

func (*TestProvider) GetAuthorizationURL

func (p *TestProvider) GetAuthorizationURL(state string) string

GetAuthorizationURL returns the test authorization URL For the test provider, we'll create a direct callback URL instead of an external redirect

func (*TestProvider) GetUserInfo

func (p *TestProvider) GetUserInfo(ctx context.Context, accessToken string) (*UserInfo, error)

GetUserInfo returns fake user information

func (*TestProvider) ValidateIDToken

func (p *TestProvider) ValidateIDToken(ctx context.Context, idToken string) (*IDTokenClaims, error)

ValidateIDToken validates the test ID token (always succeeds)

type TokenBlacklist

type TokenBlacklist struct {
	// contains filtered or unexported fields
}

TokenBlacklist manages blacklisted JWT tokens using Redis

func NewTokenBlacklist

func NewTokenBlacklist(redisClient *redis.Client, keyManager *JWTKeyManager) *TokenBlacklist

NewTokenBlacklist creates a new token blacklist service

func (*TokenBlacklist) BlacklistToken

func (tb *TokenBlacklist) BlacklistToken(ctx context.Context, tokenString string) error

BlacklistToken adds a JWT token to the blacklist

func (*TokenBlacklist) CleanupExpiredTokens

func (tb *TokenBlacklist) CleanupExpiredTokens(ctx context.Context) error

CleanupExpiredTokens removes expired entries from the blacklist This is handled automatically by Redis TTL, but this method can be used for monitoring or manual cleanup if needed

func (*TokenBlacklist) IsTokenBlacklisted

func (tb *TokenBlacklist) IsTokenBlacklisted(ctx context.Context, tokenString string) (bool, error)

IsTokenBlacklisted checks if a JWT token is blacklisted

type TokenIntrospectionResponse

type TokenIntrospectionResponse struct {
	Active    bool   `json:"active"`
	Sub       string `json:"sub,omitempty"`
	Email     string `json:"email,omitempty"`
	Name      string `json:"name,omitempty"`
	Iat       int64  `json:"iat,omitempty"`
	Exp       int64  `json:"exp,omitempty"`
	Aud       string `json:"aud,omitempty"`
	Iss       string `json:"iss,omitempty"`
	TokenType string `json:"token_type,omitempty"`
	Scope     string `json:"scope,omitempty"`
}

TokenIntrospectionResponse represents the response from token introspection

type TokenPair

type TokenPair struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int    `json:"expires_in"`
	TokenType    string `json:"token_type"`
}

TokenPair contains an access token and a refresh token

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	RefreshToken string `json:"refresh_token,omitempty"`
	ExpiresIn    int    `json:"expires_in"`
	IDToken      string `json:"id_token,omitempty"`
}

TokenResponse contains the response from the token endpoint

type TokenTestCase

type TokenTestCase struct {
	Name           string
	User           User
	ExpectedError  bool
	ExpectedClaims func(*testing.T, *Claims)
}

TokenTestCase represents a test case for token operations

type User

type User struct {
	InternalUUID   string     `json:"internal_uuid"`    // Internal system UUID (cached but excluded from API responses via convertUserToAPIResponse)
	Provider       string     `json:"provider"`         // OAuth provider: "tmi", "google", "github", "microsoft", "azure"
	ProviderUserID string     `json:"provider_user_id"` // Provider's user ID (from JWT sub claim)
	Email          string     `json:"email"`
	Name           string     `json:"name"` // Display name for UI presentation
	EmailVerified  bool       `json:"email_verified"`
	AccessToken    *string    `json:"-"`                // OAuth access token (not exposed in JSON) - nullable
	RefreshToken   *string    `json:"-"`                // OAuth refresh token (not exposed in JSON) - nullable
	TokenExpiry    *time.Time `json:"-"`                // Token expiration time (not exposed in JSON) - nullable
	Groups         []string   `json:"groups,omitempty"` // Groups from identity provider (not stored in DB)
	IsAdmin        bool       `json:"is_admin"`         // Whether user has administrator privileges
	CreatedAt      time.Time  `json:"created_at"`
	ModifiedAt     time.Time  `json:"modified_at"`
	LastLogin      *time.Time `json:"last_login,omitempty"` // nullable - may be NULL for auto-created admin users
}

User represents a user in the system

func CreateTestUser

func CreateTestUser(provider, email string) User

CreateTestUser creates a test user with default values

func CreateTestUserWithGroups

func CreateTestUserWithGroups(provider, email string, groups []string) User

CreateTestUserWithGroups creates a test user with specific groups

func CreateTestUserWithRole

func CreateTestUserWithRole(provider, email string, isAdmin bool) User

CreateTestUserWithRole creates a test user with specific admin status

type UserInfo

type UserInfo struct {
	ID            string   `json:"id,omitempty"`
	Email         string   `json:"email,omitempty"`
	EmailVerified bool     `json:"email_verified,omitempty"`
	Name          string   `json:"name,omitempty"`
	GivenName     string   `json:"given_name,omitempty"`
	FamilyName    string   `json:"family_name,omitempty"`
	Picture       string   `json:"picture,omitempty"`
	Locale        string   `json:"locale,omitempty"`
	IdP           string   `json:"idp,omitempty"`    // Identity provider ID
	Groups        []string `json:"groups,omitempty"` // Groups from identity provider
}

UserInfo contains user information from the provider

func CreateTestUserInfo

func CreateTestUserInfo(email, name, idp string, groups []string) *UserInfo

CreateTestUserInfo creates UserInfo for testing OAuth responses

type UserInfoEndpoint

type UserInfoEndpoint struct {
	URL    string            `json:"url"`
	Claims map[string]string `json:"claims"`
}

UserInfoEndpoint represents a single userinfo endpoint and its claim mappings

type UserProvider

type UserProvider struct {
	ID             string    `json:"id"`
	UserID         string    `json:"user_id"`
	Provider       string    `json:"provider"`
	ProviderUserID string    `json:"provider_user_id"`
	Email          string    `json:"email"`
	IsPrimary      bool      `json:"is_primary"`
	CreatedAt      time.Time `json:"created_at"`
	LastLogin      time.Time `json:"last_login,omitempty"`
}

UserProvider represents a user's OAuth provider

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL