auth

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 23, 2026 License: GPL-3.0 Imports: 31 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrOAuthDisabled       = errors.New("OAuth is disabled")
	ErrProviderDisabled    = errors.New("OAuth provider is disabled")
	ErrInvalidProvider     = errors.New("invalid OAuth provider")
	ErrInvalidState        = errors.New("invalid OAuth state")
	ErrOAuthExchangeFailed = errors.New("failed to exchange OAuth code")
	ErrOAuthUserInfoFailed = errors.New("failed to get user info from OAuth provider")
)

OAuth errors.

View Source
var (
	ErrInvalidCredentials       = errors.New("invalid email or password")
	ErrAccountLocked            = errors.New("account is locked due to too many failed attempts")
	ErrAccountSuspended         = errors.New("account is suspended")
	ErrEmailNotVerified         = errors.New("email is not verified")
	ErrRegistrationDisabled     = errors.New("registration is disabled")
	ErrEmailAlreadyExists       = errors.New("email already exists")
	ErrInvalidResetToken        = errors.New("invalid or expired reset token")
	ErrInvalidVerificationToken = errors.New("invalid or expired verification token")
	ErrPasswordMismatch         = errors.New("current password is incorrect")
	ErrSessionLimitReached      = errors.New("maximum number of active sessions reached")
	ErrTenantAccessDenied       = errors.New("user does not have access to this tenant")
	ErrTenantRequired           = errors.New("tenant_id is required")
)

AuthService errors.

View Source
var (
	ErrSSOTenantNotFound      = errors.New("tenant not found")
	ErrSSONoActiveProviders   = errors.New("no active SSO providers for this tenant")
	ErrSSOProviderNotFound    = errors.New("SSO provider not configured for this tenant")
	ErrSSOProviderInactive    = errors.New("SSO provider is not active")
	ErrSSOInvalidState        = errors.New("invalid SSO state token")
	ErrSSOExchangeFailed      = errors.New("failed to exchange authorization code")
	ErrSSOUserInfoFailed      = errors.New("failed to get user info from SSO provider")
	ErrSSODomainNotAllowed    = errors.New("email domain not allowed for this SSO provider")
	ErrSSODecryptionFailed    = errors.New("failed to decrypt client secret")
	ErrSSOProviderUnsupported = errors.New("unsupported SSO provider type")
	ErrSSOInvalidRedirectURI  = errors.New("invalid redirect URI")
	ErrSSOInvalidDefaultRole  = errors.New("invalid default role")
	ErrSSONoEmail             = errors.New("SSO provider did not return an email address")
)

SSO errors.

View Source
var ErrTicketNotFound = errors.New("ws ticket not found")

ErrTicketNotFound is returned by RedeemTicket when the ticket is missing, already consumed, or expired. Callers MUST treat all three the same (do not echo distinct error messages to the client — that would be an enumeration oracle).

Functions

func SMTPConfigFromIntegrationMeta

func SMTPConfigFromIntegrationMeta() map[string]string

SMTPConfigFromIntegrationMeta extracts SMTP config fields for creating an email integration. Used by the UI when creating/editing an email notification integration.

Types

type AcceptInvitationWithRefreshTokenInput

type AcceptInvitationWithRefreshTokenInput struct {
	RefreshToken    string `json:"refresh_token" validate:"required"`
	InvitationToken string `json:"invitation_token" validate:"required"`
}

AcceptInvitationWithRefreshTokenInput represents the input for accepting an invitation.

type AcceptInvitationWithRefreshTokenResult

type AcceptInvitationWithRefreshTokenResult struct {
	AccessToken  string               `json:"access_token"`
	RefreshToken string               `json:"refresh_token"` // Rotated refresh token
	ExpiresAt    time.Time            `json:"expires_at"`
	Tenant       TenantMembershipInfo `json:"tenant"`
	Role         string               `json:"role"`
}

AcceptInvitationWithRefreshTokenResult represents the result of accepting an invitation.

type AuthService

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

AuthService handles authentication operations.

func NewAuthService

func NewAuthService(
	userRepo userdom.Repository,
	sessionRepo sessiondom.Repository,
	refreshTokenRepo sessiondom.RefreshTokenRepository,
	tenantRepo tenantdom.Repository,
	auditService *auditapp.AuditService,
	cfg config.AuthConfig,
	log *logger.Logger,
) *AuthService

NewAuthService creates a new AuthService.

func (*AuthService) AcceptInvitationWithRefreshToken

AcceptInvitationWithRefreshToken accepts an invitation using a refresh token. This endpoint is for users who were invited but don't have a tenant yet, so they only have a refresh token (no access token).

func (*AuthService) ChangePassword

func (s *AuthService) ChangePassword(ctx context.Context, userID string, input ChangePasswordInput) error

ChangePassword changes a user's password (requires authentication).

func (*AuthService) CreateFirstTeam

func (s *AuthService) CreateFirstTeam(ctx context.Context, input CreateFirstTeamInput) (*CreateFirstTeamResult, error)

CreateFirstTeam creates the first team for a user who has no tenants. This endpoint uses refresh_token for authentication since user has no access_token yet.

func (*AuthService) ExchangeToken

func (s *AuthService) ExchangeToken(ctx context.Context, input ExchangeTokenInput) (*ExchangeTokenResult, error)

ExchangeToken exchanges a global refresh token for a tenant-scoped access token. This is the main method for getting access tokens after login.

func (*AuthService) ForgotPassword

func (s *AuthService) ForgotPassword(ctx context.Context, input ForgotPasswordInput) (*ForgotPasswordResult, error)

ForgotPassword initiates a password reset.

func (*AuthService) GenerateWSToken

func (s *AuthService) GenerateWSToken(ctx context.Context, userID, tenantID string) (string, error)

GenerateWSToken generates a short-lived token for WebSocket authentication. This is needed because WebSocket connections cannot use httpOnly cookies when the connection is cross-origin (different port in development). The token is valid for 30 seconds - just enough time to establish the connection.

func (*AuthService) Login

func (s *AuthService) Login(ctx context.Context, input LoginInput) (*LoginResult, error)

Login authenticates a user and creates a session. Returns a global refresh token and list of tenant memberships. Client should call ExchangeToken to get a tenant-scoped access token.

func (*AuthService) Logout

func (s *AuthService) Logout(ctx context.Context, sessionID string) error

Logout revokes a session.

func (*AuthService) RefreshToken

func (s *AuthService) RefreshToken(ctx context.Context, input RefreshTokenInput) (*RefreshTokenResult, error)

RefreshToken rotates the refresh token and issues new tenant-scoped access token. This implements token rotation for security while providing tenant-scoped access.

func (*AuthService) Register

func (s *AuthService) Register(ctx context.Context, input RegisterInput) (*RegisterResult, error)

Register creates a new local user account. Security note: To prevent email enumeration attacks, this method returns a success result even if the email already exists. The caller should always display a generic "check your email" message regardless of the result.

func (*AuthService) ResetPassword

func (s *AuthService) ResetPassword(ctx context.Context, input ResetPasswordInput) error

ResetPassword resets a user's password using the reset token.

func (*AuthService) SetRoleService

func (s *AuthService) SetRoleService(roleService *accesscontrol.RoleService)

SetRoleService sets the role service for database-driven permissions. When set, the auth service will fetch permissions from the database instead of using hardcoded role-permission mappings.

func (*AuthService) SetSMTPChecker

func (s *AuthService) SetSMTPChecker(checker SMTPAvailabilityCheck)

SetSMTPChecker injects the SMTP availability checker used for smart email verification (auto mode). If not set, the service falls back to the global RequireEmailVerification flag from config.

func (*AuthService) ValidateAccessToken

func (s *AuthService) ValidateAccessToken(tokenString string) (*jwt.Claims, error)

ValidateAccessToken validates an access token and returns the claims.

func (*AuthService) VerifyEmail

func (s *AuthService) VerifyEmail(ctx context.Context, token string) error

VerifyEmail verifies a user's email with the verification token.

type AuthorizationURLInput

type AuthorizationURLInput struct {
	Provider      OAuthProvider
	RedirectURI   string // Frontend callback URL
	FinalRedirect string // Where to redirect after successful auth
}

AuthorizationURLInput represents input for getting authorization URL.

type AuthorizationURLResult

type AuthorizationURLResult struct {
	AuthorizationURL string `json:"authorization_url"`
	State            string `json:"state"`
}

AuthorizationURLResult represents the result of getting authorization URL.

type CallbackInput

type CallbackInput struct {
	Provider    OAuthProvider
	Code        string
	State       string
	RedirectURI string
}

CallbackInput represents the OAuth callback input.

type CallbackResult

type CallbackResult struct {
	AccessToken  string        `json:"access_token"`
	RefreshToken string        `json:"refresh_token"`
	ExpiresIn    int64         `json:"expires_in"`
	TokenType    string        `json:"token_type"`
	User         *userdom.User `json:"user"`
}

CallbackResult represents the OAuth callback result.

type ChangePasswordInput

type ChangePasswordInput struct {
	CurrentPassword string `json:"current_password" validate:"required"`
	NewPassword     string `json:"new_password" validate:"required,min=8,max=128"`
}

ChangePasswordInput represents the input for changing password.

type CreateFirstTeamInput

type CreateFirstTeamInput struct {
	RefreshToken string `json:"refresh_token" validate:"required"`
	TeamName     string `json:"team_name" validate:"required,min=2,max=100"`
	TeamSlug     string `json:"team_slug" validate:"required,min=3,max=50"`
}

CreateFirstTeamInput represents the input for creating first team.

type CreateFirstTeamResult

type CreateFirstTeamResult struct {
	AccessToken  string               `json:"access_token"`
	RefreshToken string               `json:"refresh_token"` // Rotated refresh token
	ExpiresAt    time.Time            `json:"expires_at"`
	Tenant       TenantMembershipInfo `json:"tenant"`
}

CreateFirstTeamResult represents the result of creating first team.

type CreateProviderInput

type CreateProviderInput struct {
	TenantID         string
	Provider         string
	DisplayName      string
	ClientID         string
	ClientSecret     string // Plaintext - will be encrypted
	IssuerURL        string
	TenantIdentifier string
	Scopes           []string
	AllowedDomains   []string
	AutoProvision    bool
	DefaultRole      string
	CreatedBy        string
}

CreateProviderInput is the input for creating an identity provider config.

type EmailService

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

EmailService handles sending emails for various application events. Supports per-tenant SMTP via TenantSMTPResolver: if a tenant has a custom email integration configured, it uses that SMTP server instead of the system default.

func NewEmailService

func NewEmailService(sender emaildom.Sender, cfg config.SMTPConfig, appName string, log *logger.Logger) *EmailService

NewEmailService creates a new EmailService.

func (*EmailService) HasSystemSMTP

func (s *EmailService) HasSystemSMTP() bool

HasSystemSMTP implements SMTPAvailabilityCheck. Returns true if the system-wide SMTP sender is configured.

func (*EmailService) HasTenantSMTP

func (s *EmailService) HasTenantSMTP(ctx context.Context, tenantID string) bool

HasTenantSMTP implements SMTPAvailabilityCheck. Returns true if the given tenant has a custom SMTP integration configured. tenantID may be empty for self-registration without tenant context.

func (*EmailService) IsConfigured

func (s *EmailService) IsConfigured() bool

IsConfigured returns true if email service is properly configured.

func (*EmailService) SendMemberReactivatedEmail

func (s *EmailService) SendMemberReactivatedEmail(
	ctx context.Context,
	recipientEmail, recipientName, teamName, actorName, tenantID string,
) error

SendMemberReactivatedEmail notifies a user that their access has been restored. Same best-effort semantics as SendMemberSuspendedEmail.

func (*EmailService) SendMemberSuspendedEmail

func (s *EmailService) SendMemberSuspendedEmail(
	ctx context.Context,
	recipientEmail, recipientName, teamName, actorName, tenantID string,
) error

SendMemberSuspendedEmail notifies a user that their tenant access has been suspended. Uses per-tenant SMTP if configured. Best-effort: returns nil and logs a warning if email is not configured for the tenant — the suspend operation should succeed even when the user can't be notified.

func (*EmailService) SendPasswordChangedEmail

func (s *EmailService) SendPasswordChangedEmail(ctx context.Context, userEmail, userName, ipAddress string) error

SendPasswordChangedEmail sends a notification that the password was changed.

func (*EmailService) SendPasswordResetEmail

func (s *EmailService) SendPasswordResetEmail(ctx context.Context, userEmail, userName, token string, expiresIn time.Duration, ipAddress string) error

SendPasswordResetEmail sends a password reset link to a user.

func (*EmailService) SendTeamInvitationEmail

func (s *EmailService) SendTeamInvitationEmail(ctx context.Context, recipientEmail, inviterName, teamName, token string, expiresIn time.Duration, tenantID ...string) error

SendTeamInvitationEmail sends a team invitation email. Uses per-tenant SMTP if configured, otherwise falls back to system SMTP.

func (*EmailService) SendVerificationEmail

func (s *EmailService) SendVerificationEmail(ctx context.Context, userEmail, userName, token string, expiresIn time.Duration) error

SendVerificationEmail sends an email verification link to a user.

func (*EmailService) SendWelcomeEmail

func (s *EmailService) SendWelcomeEmail(ctx context.Context, userEmail, userName string) error

SendWelcomeEmail sends a welcome email to a new user.

func (*EmailService) SetTenantSMTPResolver

func (s *EmailService) SetTenantSMTPResolver(resolver TenantSMTPResolver)

SetTenantSMTPResolver sets the per-tenant SMTP resolver.

type ExchangeTokenInput

type ExchangeTokenInput struct {
	RefreshToken string `json:"refresh_token" validate:"required"`
	TenantID     string `json:"tenant_id" validate:"required"`
}

ExchangeTokenInput represents the input for token exchange.

type ExchangeTokenResult

type ExchangeTokenResult struct {
	AccessToken string
	TenantID    string
	TenantSlug  string
	Role        string
	ExpiresAt   time.Time
}

ExchangeTokenResult represents the result of token exchange.

type ForgotPasswordInput

type ForgotPasswordInput struct {
	Email string `json:"email" validate:"required,email"`
}

ForgotPasswordInput represents the input for password reset request.

type ForgotPasswordResult

type ForgotPasswordResult struct {
	Token string // Reset token (should be sent via email in production)
}

ForgotPasswordResult represents the result of password reset request.

type IntegrationSMTPResolver

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

IntegrationSMTPResolver resolves per-tenant SMTP config from notification integrations. When a tenant creates an email integration (category=notification, provider=email), the SMTP settings are stored encrypted in the integration's config/credentials.

func NewIntegrationSMTPResolver

func NewIntegrationSMTPResolver(repo integration.Repository, log *logger.Logger) *IntegrationSMTPResolver

NewIntegrationSMTPResolver creates a new resolver.

func (*IntegrationSMTPResolver) GetTenantSMTPConfig

func (r *IntegrationSMTPResolver) GetTenantSMTPConfig(ctx context.Context, tenantID string) (*emaildom.Config, error)

GetTenantSMTPConfig looks up the tenant's email integration and returns SMTP config. Returns nil if no email integration is configured for this tenant.

type LoginInput

type LoginInput struct {
	Email     string `json:"email" validate:"required,email"`
	Password  string `json:"password" validate:"required"`
	IPAddress string `json:"-"`
	UserAgent string `json:"-"`
}

LoginInput represents the input for login.

type LoginResult

type LoginResult struct {
	User         *userdom.User
	RefreshToken string // Global refresh token (no tenant context)
	ExpiresAt    time.Time
	SessionID    string
	Tenants      []TenantMembershipInfo // Active tenants user can access
	// SuspendedTenants lists tenants where this user has a suspended
	// membership. The user has zero access to these tenants — the field
	// exists purely so the UI can show "your access to {name} is
	// suspended" instead of bouncing the user to /onboarding/create-team
	// when they have no active memberships.
	SuspendedTenants []TenantMembershipInfo
}

LoginResult represents the result of login. Returns a global refresh token and list of tenant memberships. Client must call ExchangeToken to get a tenant-scoped access token.

type OAuthProvider

type OAuthProvider string

OAuthProvider represents a supported OAuth provider.

const (
	OAuthProviderGoogle    OAuthProvider = "google"
	OAuthProviderGitHub    OAuthProvider = "github"
	OAuthProviderMicrosoft OAuthProvider = "microsoft"
)

func (OAuthProvider) IsValid

func (p OAuthProvider) IsValid() bool

IsValid checks if the provider is valid.

func (OAuthProvider) ToAuthProvider

func (p OAuthProvider) ToAuthProvider() userdom.AuthProvider

ToAuthProvider converts OAuthProvider to userdom.AuthProvider.

type OAuthService

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

OAuthService handles OAuth authentication.

func NewOAuthService

func NewOAuthService(
	userRepo userdom.Repository,
	sessionRepo sessiondom.Repository,
	refreshTokenRepo sessiondom.RefreshTokenRepository,
	oauthCfg config.OAuthConfig,
	authCfg config.AuthConfig,
	log *logger.Logger,
) *OAuthService

NewOAuthService creates a new OAuthService.

func (*OAuthService) GetAuthorizationURL

func (s *OAuthService) GetAuthorizationURL(ctx context.Context, input AuthorizationURLInput) (*AuthorizationURLResult, error)

GetAuthorizationURL returns the OAuth authorization URL for the specified provider.

func (*OAuthService) GetAvailableProviders

func (s *OAuthService) GetAvailableProviders() []ProviderInfo

GetAvailableProviders returns a list of available OAuth providers.

func (*OAuthService) HandleCallback

func (s *OAuthService) HandleCallback(ctx context.Context, input CallbackInput) (*CallbackResult, error)

HandleCallback handles the OAuth callback.

type OAuthUserInfo

type OAuthUserInfo struct {
	ID        string
	Email     string
	Name      string
	AvatarURL string
}

OAuthUserInfo represents user information from OAuth provider.

type ProviderInfo

type ProviderInfo struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Enabled bool   `json:"enabled"`
}

ProviderInfo represents information about an OAuth provider.

type RefreshTokenInput

type RefreshTokenInput struct {
	RefreshToken string `json:"refresh_token" validate:"required"`
	TenantID     string `json:"tenant_id" validate:"required"`
	IPAddress    string `json:"-"`
	UserAgent    string `json:"-"`
}

RefreshTokenInput represents the input for token refresh. Requires tenant_id to generate tenant-scoped access token.

type RefreshTokenResult

type RefreshTokenResult struct {
	AccessToken      string    // Tenant-scoped access token
	RefreshToken     string    // New global refresh token (rotated)
	TenantID         string    // Tenant ID the access token is scoped to
	TenantSlug       string    // Tenant slug
	Role             string    // User's role in this tenant
	ExpiresAt        time.Time // Access token expiration
	RefreshExpiresAt time.Time // Refresh token expiration (for cookie)
}

RefreshTokenResult represents the result of token refresh. Returns a new global refresh token and tenant-scoped access token.

type RegisterInput

type RegisterInput struct {
	Email    string `json:"email" validate:"required,email,max=255"`
	Password string `json:"password" validate:"required,min=8,max=128"`
	Name     string `json:"name" validate:"required,max=255"`
	// InvitationToken is optional: when a user registers via an
	// invitation link, the client passes the token here so the register
	// flow can resolve the target tenant and apply that tenant's email
	// verification rule (instead of the platform default). The token
	// itself is NOT consumed here — invitation acceptance still happens
	// in a separate POST /invitations/{token}/accept call.
	InvitationToken string `json:"invitation_token,omitempty"`
}

RegisterInput represents the input for user registration.

type RegisterResult

type RegisterResult struct {
	User                 *userdom.User
	VerificationToken    string // Only returned if email verification is required
	RequiresVerification bool
	EmailExisted         bool // Set to true if email already exists (for anti-enumeration)
}

RegisterResult represents the result of registration.

type ResetPasswordInput

type ResetPasswordInput struct {
	Token       string `json:"token" validate:"required"`
	NewPassword string `json:"new_password" validate:"required,min=8,max=128"`
}

ResetPasswordInput represents the input for password reset.

type SMTPAvailabilityCheck

type SMTPAvailabilityCheck interface {
	// HasSystemSMTP returns true if the platform has system-wide SMTP configured.
	HasSystemSMTP() bool
	// HasTenantSMTP returns true if the given tenant has a custom SMTP integration.
	// tenantID may be empty for self-registration (no tenant context yet).
	HasTenantSMTP(ctx context.Context, tenantID string) bool
}

SMTPAvailabilityCheck reports whether outbound email is available, either via the system SMTP config or for a specific tenant. Used by smart email verification to skip verification when no email channel exists.

type SSOAuthorizeInput

type SSOAuthorizeInput struct {
	OrgSlug     string
	Provider    string
	RedirectURI string // Frontend callback URL
}

SSOAuthorizeInput is the input for generating an SSO authorization URL.

type SSOAuthorizeResult

type SSOAuthorizeResult struct {
	AuthorizationURL string `json:"authorization_url"`
	State            string `json:"state"`
}

SSOAuthorizeResult is the result of generating an SSO authorization URL.

type SSOCallbackInput

type SSOCallbackInput struct {
	Provider    string
	Code        string
	State       string
	RedirectURI string
}

SSOCallbackInput is the input for handling an SSO callback.

type SSOCallbackResult

type SSOCallbackResult struct {
	AccessToken  string        `json:"access_token"`
	RefreshToken string        `json:"refresh_token"`
	ExpiresIn    int64         `json:"expires_in"`
	TokenType    string        `json:"token_type"`
	User         *userdom.User `json:"user"`
	TenantID     string        `json:"tenant_id"`
	TenantSlug   string        `json:"tenant_slug"`
}

SSOCallbackResult is the result of a successful SSO callback.

type SSOProviderInfo

type SSOProviderInfo struct {
	ID          string `json:"id"`
	Provider    string `json:"provider"`
	DisplayName string `json:"display_name"`
}

SSOProviderInfo represents a public SSO provider for a tenant.

type SSOService

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

SSOService handles per-tenant SSO authentication.

func NewSSOService

func NewSSOService(
	ipRepo identityproviderdom.Repository,
	tenantRepo tenantdom.Repository,
	userRepo userdom.Repository,
	sessionRepo sessiondom.Repository,
	refreshTokenRepo sessiondom.RefreshTokenRepository,
	encryptor crypto.Encryptor,
	authCfg config.AuthConfig,
	log *logger.Logger,
) *SSOService

NewSSOService creates a new SSOService.

func (*SSOService) CreateProvider

CreateProvider creates a new identity provider configuration for a tenant.

func (*SSOService) DeleteProvider

func (s *SSOService) DeleteProvider(ctx context.Context, tenantID, id string) error

DeleteProvider deletes an identity provider configuration.

func (*SSOService) GenerateAuthorizeURL

func (s *SSOService) GenerateAuthorizeURL(ctx context.Context, input SSOAuthorizeInput) (*SSOAuthorizeResult, error)

GenerateAuthorizeURL builds the OAuth authorization URL for a tenant's SSO provider.

func (*SSOService) GetProvider

func (s *SSOService) GetProvider(ctx context.Context, tenantID, id string) (*identityproviderdom.IdentityProvider, error)

GetProvider retrieves a provider configuration by ID.

func (*SSOService) GetProvidersForTenant

func (s *SSOService) GetProvidersForTenant(ctx context.Context, orgSlug string) ([]SSOProviderInfo, error)

GetProvidersForTenant returns active SSO providers for a tenant identified by slug.

func (*SSOService) HandleCallback

func (s *SSOService) HandleCallback(ctx context.Context, input SSOCallbackInput) (*SSOCallbackResult, error)

HandleCallback handles the SSO OAuth callback.

func (*SSOService) ListProviders

func (s *SSOService) ListProviders(ctx context.Context, tenantID string) ([]*identityproviderdom.IdentityProvider, error)

ListProviders lists all identity provider configurations for a tenant.

func (*SSOService) SetTenantMemberRepo

func (s *SSOService) SetTenantMemberRepo(repo TenantMemberCreator)

SetTenantMemberRepo sets the tenant membership creator for auto-provisioning.

func (*SSOService) UpdateProvider

UpdateProvider updates an identity provider configuration.

type SSOUserInfo

type SSOUserInfo struct {
	Email     string
	Name      string
	AvatarURL string
}

SSOUserInfo represents user info from SSO provider.

type SessionInfo

type SessionInfo struct {
	ID             string `json:"id"`
	IPAddress      string `json:"ip_address,omitempty"`
	UserAgent      string `json:"user_agent,omitempty"`
	LastActivityAt string `json:"last_activity_at"`
	CreatedAt      string `json:"created_at"`
	IsCurrent      bool   `json:"is_current"`
}

SessionInfo represents session information returned to the user.

type SessionResult

type SessionResult struct {
	AccessToken  string
	RefreshToken string
}

SessionResult represents session creation result.

type SessionService

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

SessionService handles session management operations.

func NewSessionService

func NewSessionService(
	sessionRepo sessiondom.Repository,
	refreshTokenRepo sessiondom.RefreshTokenRepository,
	log *logger.Logger,
) *SessionService

NewSessionService creates a new SessionService.

func (*SessionService) CleanupExpiredSessions

func (s *SessionService) CleanupExpiredSessions(ctx context.Context) (int64, int64, error)

CleanupExpiredSessions removes expired sessions and tokens. This should be called periodically (e.g., by a cron job).

func (*SessionService) CountActiveSessions

func (s *SessionService) CountActiveSessions(ctx context.Context, userID string) (int, error)

CountActiveSessions returns the count of active sessions for a user.

func (*SessionService) GetSessionByAccessToken

func (s *SessionService) GetSessionByAccessToken(ctx context.Context, accessToken string) (*sessiondom.Session, error)

GetSessionByAccessToken retrieves a session by its access token.

func (*SessionService) ListUserSessions

func (s *SessionService) ListUserSessions(ctx context.Context, userID string, currentSessionID string) ([]SessionInfo, error)

ListUserSessions returns all active sessions for a user.

func (*SessionService) RevokeAllSessions

func (s *SessionService) RevokeAllSessions(ctx context.Context, userID, exceptSessionID string) error

RevokeAllSessions revokes all sessions for a user except the current one.

func (*SessionService) RevokeSession

func (s *SessionService) RevokeSession(ctx context.Context, userID, sessionID string) error

RevokeSession revokes a specific session for a user.

func (*SessionService) SetPermissionServices

func (s *SessionService) SetPermissionServices(
	cacheSvc *accesscontrol.PermissionCacheService,
	versionSvc *accesscontrol.PermissionVersionService,
	tenantRepo TenantMembershipProvider,
)

SetPermissionServices sets the permission cache and version services. This enables cache invalidation when sessions are revoked.

func (*SessionService) UpdateSessionActivity

func (s *SessionService) UpdateSessionActivity(ctx context.Context, sessionID string) error

UpdateSessionActivity updates the last activity time for a session.

func (*SessionService) ValidateSession

func (s *SessionService) ValidateSession(ctx context.Context, sessionID string) (*sessiondom.Session, error)

ValidateSession checks if a session is valid.

type SettingsStorageResolver

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

SettingsStorageResolver resolves per-tenant storage config from the settings table.

func NewSettingsStorageResolver

func NewSettingsStorageResolver(db *sql.DB, enc crypto.Encryptor, log *logger.Logger) *SettingsStorageResolver

NewSettingsStorageResolver creates a new resolver.

func (*SettingsStorageResolver) GetTenantStorageConfig

func (r *SettingsStorageResolver) GetTenantStorageConfig(ctx context.Context, tenantID string) (*attachment.StorageConfig, error)

GetTenantStorageConfig reads the storage_config setting for a tenant. Returns nil if not configured (tenant uses default provider).

func (*SettingsStorageResolver) SaveTenantStorageConfig

func (r *SettingsStorageResolver) SaveTenantStorageConfig(ctx context.Context, tenantID string, cfg attachment.StorageConfig) error

SaveTenantStorageConfig upserts the storage config for a tenant.

type TenantMemberCreator

type TenantMemberCreator interface {
	CreateMembership(ctx context.Context, m *tenantdom.Membership) error
}

TenantMemberCreator creates tenant memberships for auto-provisioned users.

type TenantMembershipInfo

type TenantMembershipInfo struct {
	TenantID   string `json:"tenant_id"`
	TenantSlug string `json:"tenant_slug"`
	TenantName string `json:"tenant_name"`
	Role       string `json:"role"`
}

TenantMembershipInfo represents a tenant membership for API responses.

type TenantMembershipProvider

type TenantMembershipProvider interface {
	GetUserTenantIDs(ctx context.Context, userID shared.ID) ([]string, error)
}

TenantMembershipProvider provides tenant membership information. Used to get all tenants a user belongs to for cache invalidation.

type TenantSMTPResolver

type TenantSMTPResolver interface {
	GetTenantSMTPConfig(ctx context.Context, tenantID string) (*emaildom.Config, error)
}

TenantSMTPResolver resolves per-tenant SMTP configuration from integrations. Returns nil if tenant has no custom SMTP config (fallback to system default).

type UpdateProviderInput

type UpdateProviderInput struct {
	ID               string
	TenantID         string // For authorization check
	DisplayName      *string
	ClientID         *string
	ClientSecret     *string // Plaintext - will be encrypted if provided
	IssuerURL        *string
	TenantIdentifier *string
	Scopes           []string
	AllowedDomains   []string
	AutoProvision    *bool
	DefaultRole      *string
	IsActive         *bool
}

UpdateProviderInput is the input for updating an identity provider config.

type WSTicketClaims

type WSTicketClaims struct {
	UserID   string `json:"user_id"`
	TenantID string `json:"tenant_id"`
	IssuedAt int64  `json:"iat"`
}

WSTicketClaims is the payload persisted under each ticket. It is the minimum required to authenticate a WS upgrade as the issuing user/tenant.

type WSTicketService

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

WSTicketService issues and redeems single-use WebSocket tickets.

func NewWSTicketService

func NewWSTicketService(store WSTicketStore, ttl time.Duration, log *logger.Logger) *WSTicketService

NewWSTicketService constructs the service. ttl defaults to 30s when zero.

func (*WSTicketService) IssueTicket

func (s *WSTicketService) IssueTicket(ctx context.Context, userID, tenantID string) (string, error)

IssueTicket mints a new opaque ticket and stores the caller's identity under it. The returned string is what the client passes as ?ticket= on the WebSocket upgrade.

func (*WSTicketService) RedeemTicket

func (s *WSTicketService) RedeemTicket(ctx context.Context, ticket string) (*WSTicketClaims, error)

RedeemTicket atomically looks up and consumes a ticket. On success returns the claims it was issued with. ticket must be the raw opaque string returned from IssueTicket.

func (*WSTicketService) TTLSeconds

func (s *WSTicketService) TTLSeconds() int

TTLSeconds returns the configured TTL in seconds for HTTP responses.

type WSTicketStore

type WSTicketStore interface {
	// Set stores value at key with TTL. Must overwrite existing keys
	// (the random ticket space is large enough that collisions are
	// negligible, and overwrite is safer than failing silently).
	Set(ctx context.Context, key, value string, ttl time.Duration) error
	// GetDel atomically reads and deletes a key, returning the stored value.
	// Returns ("", false, nil) when the key does not exist.
	GetDel(ctx context.Context, key string) (string, bool, error)
}

WSTicketStore is the minimal Redis surface the ticket service needs. Keeping this narrow makes testing easy and prevents coupling to the full Redis client surface.

Jump to

Keyboard shortcuts

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