Account
Overview
The Account domain is a default domain in comby, representing user accounts and managing their lifecycle, credentials, sessions, and related data. It encapsulates core functionalities for account management in a centralized, event-sourced architecture. The domain is implemented through the Account aggregate, which provides a robust structure for modeling user accounts, handling domain events, and enforcing business rules.
Concept
What is an Account?
An Account represents a user's authentication entity in the system. It is tenant-independent and manages credentials, sessions, and authentication states. Accounts can have multiple identities across different tenants.
Key Characteristics:
- Tenant-Independent: Accounts belong to the "anonymous" tenant, allowing cross-tenant identities
- Multi-Auth Support: Supports both email/password and OPAQUE authentication
- Session Management: Tracks active user sessions with expiration
- State-Based: Accounts have states (registered, active, blocked, removed)
An Account can be associated with multiple Identities, each of which is linked to a specific Tenant. This allows a user with a single account to log in to multiple tenants.
Architecture
Hierarchy
System
└── Anonymous Tenant
└── Accounts
├── Credentials (Email/Password or OPAQUE)
├── Sessions (Session management)
└── Identities (Cross-tenant associations)Related Entities
Account is connected to:
- Identity: Accounts have multiple identities across different tenants
- Tenant: Identities are associated with specific tenants
- Session: Tracks active authentication sessions
- Invitation: Can be used for invitation-based registration
Authentication Models
1. Email/Password Authentication
Traditional authentication using email and password.
Features:
- Password complexity validation
- Password hashing
- Rate limiting
- MFA support
2. OPAQUE Authentication
Modern passwordless authentication using the OPAQUE protocol.
Features:
- No password storage on server
- Resistant to pre-computation attacks
- Forward secrecy
- Mutual authentication
Account States
| State | Description |
|---|---|
registered | Account created but not yet activated |
active | Account is active and can authenticate |
blocked | Account is blocked and cannot authenticate |
removed | Account is marked for deletion |
Email & Password with OPAQUE (v2.2+)
OPAQUE (Oblivious Pseudorandom Function with Authenticated Key Exchange) is a Password-Authenticated Key Exchange (PAKE) protocol that enables secure authentication without exposing passwords to the server. The comby implementation uses Ristretto255 (prime-order elliptic curve group) and HKDF/HMAC for key derivation.
- No plaintext passwords on the server: No plaintext password ever reaches the server. The server never sees or stores the user’s actual password.
- Private key is never stored in plaintext: The client’s long-term private key is encrypted with a password-derived secret (via OPRF). The server only stores this encrypted envelope.
- Mutual authentication: Both the client and server generate cryptographic proofs during login to authenticate each other. To recover the private key, the client must know the password and interact with the server’s OPRF.
- Server-stored data: Envelope, clientPublicKey, serverPublicKey and email is safe to expose without compromising passwords
- Security guarantees:
- Resistant to offline dictionary attacks
- Forward secrecy through ephemeral Diffie-Hellman keys
- Replay protection via nonces
- Binding proofs to prevent man-in-the-middle or session confusion attacks
You can enable OPAQUE at runtime or as an environment variable:
// enable OPAQUE as environment variable
COMBY_DEFAULT_ACCOUNT_REGISTRATION_TYPES="opaque"// enable OPAQUE at runtime - but before default registration (and seeding)
comby.DEFAULT_ACCOUNT_REGISTRATION_TYPES="opaque" // or "opaque,emailpassword" to enable both
//You can also change the OPAQUE Server Private Key:
// or as environment variable with prefix: COMBY_
comby.DEFAULT_ACCOUNT_OPAQUE_SERVER_PRIVATE_KEY="your-private-key-value-will-be-kdfed-sha-256"Cryptographic Components in comby OPAQUE
Elliptic Curve Group
- Ristretto255 - Prime-order group, 128-bit security; Used for OPRF, identity key pair, and ephemeral Diffie-Hellman
Key Derivation & Hashing
- Hash-to-Curve: Ristretto255 hash-to-element with domain separation string OPAQUE-oprf
- SHA-512: Hash function for HKDF; Used in HMAC for proofs
- HKDF (HMAC-based Key Derivation Function) with SHA-512: Used to derive encryption keys from OPRF output and session keys from ECDH shared secret
- SHA-256: Used on server for deriving the OPRF private key from an application constant
Encryption
- AES-256-GCM (WebCrypto API on client): Encrypts the client’s private key into the envelope; 12-byte random nonce per encryption
- Message Authentication HMAC-SHA-512: Used for client proof and server proof in the login phase; Binds session parameters, nonces, and OPRF result
Randomness
- Crypto-secure RNG: crypto.getRandomValues on client (browser); crypto/rand on server (Go); Used for blinding factors, nonces, and ephemeral keys
Structure
The Account struct serves as the root aggregate, holding entities Credentials and a collection of Session objects. Credentials contains attributes for email, password, and the next allowed login time. Session stores details about active user sessions, including a unique session UUID, session key, and expiration time. The relationships illustrate how an account aggregates these entities to manage authentication and session handling.
Use Cases
1. Standard User Registration and Login
1. User registers → POST /api/accounts/register/emailpassword
2. MFA challenge sent via email
3. User confirms → POST /api/accounts/register/confirm
4. Account created with state "active"
5. User logs in → POST /api/accounts/login/emailpassword
6. Session created2. Invitation-Based Registration
1. Admin creates invitation
2. User receives invitation token
3. User registers with token → AccountCommandRegister with invitationToken
4. Account linked to tenant via invitation3. Password Reset Flow
1. User requests reset → POST /api/accounts/password-reset/emailpassword
2. MFA challenge sent via email
3. User confirms with new password → POST /api/accounts/password-reset/confirm
4. Password updated4. OPAQUE Authentication Flow
1. Registration:
- Step 1: Client sends OPRF request
- Step 2: Client sends credential record
2. Login:
- Step 1: Client sends OPRF request
- Step 2: Client authenticates with session dataRegistration Modes
The system supports three registration modes:
1. Public Registration
comby.DEFAULT_ACCOUNT_REGISTRATION_MODE = comby.DEFAULT_ACCOUNT_REGISTRATION_MODE_PUBLICAnyone can register without restrictions.
2. Invitation-Only
comby.DEFAULT_ACCOUNT_REGISTRATION_MODE = comby.DEFAULT_ACCOUNT_REGISTRATION_MODE_INVITATION_ONLYUsers need a valid invitation token to register.
3. Disabled
comby.DEFAULT_ACCOUNT_REGISTRATION_MODE = comby.DEFAULT_ACCOUNT_REGISTRATION_MODE_DISABLEDRegistration is completely disabled.
Security Features
Password Requirements
- Minimum length
- Complexity requirements (uppercase, lowercase, numbers, special characters)
- Validated via
comby.ValidatePassword()
Rate Limiting
NextLoginAllowedAtfield prevents brute-force attacks- Configurable login throttling
Session Management
- Unique session UUIDs
- Session keys for authentication
- Expiration timestamps
- Multiple concurrent sessions supported
Refresh Tokens for Persistent Authentication
Refresh tokens enable long-lived authentication for mobile apps and persistent sessions. Users authenticate once and remain logged in across app restarts.
Key Features:
- Single-use tokens with automatic rotation
NotBeforetimestamp prevents excessive refresh attempts- Device binding for audit and selective revocation
- Configurable session and token durations
Configuration:
# Session duration in seconds (default: 30 days = 2592000)
COMBY_DEFAULT_SESSION_DURATION_SECONDS=2592000
# Refresh token lifetime in seconds (default: 1 year = 31536000)
COMBY_DEFAULT_REFRESH_TOKEN_DURATION_SECONDS=31536000
# NotBefore window: RT usable X seconds before session expires (default: 7 days = 604800)
COMBY_DEFAULT_REFRESH_TOKEN_NOT_BEFORE_SECONDS=604800API Endpoints:
| Method | Path | Description |
|---|---|---|
| POST | /api/accounts/login/confirm | Login with optional refresh token creation |
| POST | /api/auth/token/refresh | Refresh session using refresh token |
| DELETE | /api/accounts/{accountUuid}/refresh-tokens/{refreshTokenUuid} | Revoke single refresh token |
| DELETE | /api/accounts/{accountUuid}/refresh-tokens | Revoke all refresh tokens |
Requesting a Refresh Token during Login:
To receive a refresh token, set createRefreshToken: true in the login confirmation request:
// POST /api/accounts/login/confirm
const response = await fetch('/api/accounts/login/confirm', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
oneTimeToken: '123456',
// Enable refresh token creation
createRefreshToken: true,
// Optional: Device info for audit and management
deviceId: 'unique-device-id',
deviceName: 'iPhone 15 Pro',
deviceType: 'mobile' // mobile | desktop | tablet | unknown
})
})
const data = await response.json()
// Response includes:
// {
// "item": { ... account data ... },
// "refreshToken": "accountUuid:refreshTokenUuid:tokenValue",
// "notBefore": 1234567890000000000,
// "notBeforeIn": 1987200
// }Mobile Integration Example:
// After login, store refresh token securely
const { refreshToken } = await loginResponse.json()
await SecureStore.setItemAsync('refreshToken', refreshToken)
// Refresh session when needed
async function refreshSession() {
const rt = await SecureStore.getItemAsync('refreshToken')
const res = await fetch('/api/auth/token/refresh', {
method: 'POST',
body: JSON.stringify({ refreshToken: rt }),
})
if (res.ok) {
const { refreshToken: newRT } = await res.json()
await SecureStore.setItemAsync('refreshToken', newRT)
return true
}
return false // User must login again
}MFA Support
- One-time tokens via email
- Confirmation steps for sensitive operations
- Token validation and expiration
Commands
- AccountCommandActivate
- AccountCommandCreate
- AccountCommandLogin
- AccountCommandCreateLoginSession
- AccountCommandLoginOAuth
- AccountCommandLogout
- AccountCommandPasswordReset
- AccountCommandRegister
- AccountCommandCreateRegistration
- AccountCommandRemove
- AccountCommandRemoveAttribute
- AccountCommandSetAttribute
- AccountCommandUpdate
- AccountCommandUpdateCredentials
- AccountCommandUpdateState
AccountCommandActivate
AccountCommandActivate is a domain command to activate an account.
Domain Command Struct:
type AccountCommandActivate struct {
// Outline of the command
Email string `json:"email"` // Email of the account to activate.
}Domain Command Handling Method: AccountCommandActivate is a domain command handler handling the activation of an account. (AccountCommandActivate)
func (ch *commandHandler) AccountCommandActivate(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandActivate) ([]comby.Event, error)AccountCommandCreate
Domain Command Struct:
type AccountCommandCreate struct {
AccountUuid string `json:"accountUuid"`
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
AuthModel string `json:"authModel,omitempty"` // default: emailpassword (available: emailpassword, opaque)
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandCreate(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandCreate) ([]comby.Event, error)AccountCommandLogin
AccountCommandLogin validates credentials and creates a session in one step. DEPRECATED: Use AccountCommandCreateLoginSession for the new MFA flow.
Domain Command Struct:
type AccountCommandLogin struct {
AuthModel string `json:"authModel,omitempty"` // "emailPassword" or "opaque"
SessionUuid string `json:"sessionUuid"`
SessionKey string `json:"sessionKey"`
Email string `json:"email"`
// emailpassword only fields
Password string `json:"password"`
// opaque only fields
SessionData []byte `json:"sessionData"` // OPAQUE session key data
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandLogin(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandLogin) ([]comby.Event, error)AccountCommandCreateLoginSession
AccountCommandCreateLoginSession creates a login session after credentials have been validated. This is used in the new MFA flow where credentials are validated before MFA.
Domain Command Struct:
type AccountCommandCreateLoginSession struct {
AuthModel string `json:"authModel"` // "emailPassword" or "opaque"
SessionUuid string `json:"sessionUuid"`
SessionKey string `json:"sessionKey"`
Email string `json:"email"`
}Domain Command Handling Method: AccountCommandCreateLoginSession handler creates a login session after credentials have been validated.
func (ch *commandHandler) AccountCommandCreateLoginSession(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandCreateLoginSession) ([]comby.Event, error)AccountCommandLoginOAuth
TODO: MOBVE TO LOGIN OPTION!
Domain Command Struct:
type AccountCommandLoginOAuth struct {
AccountUuid string `json:"accountUuid"`
Email string `json:"email,omitempty"`
NewPassword string `json:"newPassword,omitempty"`
SessionUuid string `json:"sessionUuid"`
SessionKey string `json:"sessionKey"`
Attributes string `json:"attributes,omitempty"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandLoginOAuth(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandLoginOAuth) ([]comby.Event, error)AccountCommandLogout
AccountCommandLogout handles logging out of a user account or session, with strict access control to ensure security and proper authorization.
This command enforces the following rules:
- Self-Logout:
- A user can log out their own account or session.
- This ensures users have full control over their own sessions while preventing unauthorized access to other accounts.
- System Tenant Authorization:
- Only the system tenant is permitted to log out other users or their sessions.
- This restriction ensures that account-wide or cross-tenant session management is tightly controlled and limited to system-level administrators.
Domain Command Struct:
type AccountCommandLogout struct {
AccountUuid string `json:"accountUuid,omitempty"`
SessionUuid string `json:"sessionUuid,omitempty"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandLogout(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandLogout) ([]comby.Event, error)AccountCommandPasswordReset
Domain Command Struct:
type AccountCommandPasswordReset struct {
AccountUuid string `json:"accountUuid"`
NewPassword string `json:"newPassword,omitempty"` // emailPassword
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord,omitempty"` // opaque
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandPasswordReset(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandPasswordReset) ([]comby.Event, error)AccountCommandRegister
Domain Command Struct:
type AccountCommandRegister struct {
AuthModel string `json:"authModel,omitempty"` // "emailPassword" or "opaque"
AccountUuid string `json:"accountUuid"`
InvitationToken string `json:"invitationToken,omitempty"`
Email string `json:"email"`
// emailpassword only fields
Password string `json:"password"`
// opaque only fields
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandRegister(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandRegister) ([]comby.Event, error)AccountCommandCreateRegistration
AccountCommandCreateRegistration creates an account after MFA confirmation. This is the new MFA flow where credentials are pre-validated before sending MFA.
Domain Command Struct:
type AccountCommandCreateRegistration struct {
AuthModel string `json:"authModel,omitempty"` // "emailPassword" or "opaque"
AccountUuid string `json:"accountUuid"`
InvitationToken string `json:"invitationToken,omitempty"`
Email string `json:"email"`
// emailpassword only fields
Password string `json:"password"`
// opaque only fields
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandCreateRegistration(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandCreateRegistration) ([]comby.Event, error)AccountCommandRemove
AccountCommandRemove handles the deletion of accounts, with strict rules to ensure proper access control.
This command enforces the following restrictions:
- Self-Deletion Prohibited:
- A user cannot delete their own account under any circumstances. This ensures a safeguard against accidental or unauthorized self-deletion.
- System Tenant Authorization:
- Only system tenants are permitted to delete accounts belonging to other users or tenants.
- This restriction ensures that account deletion is controlled centrally and prevents unauthorized cross-tenant modifications.
Domain Command Struct:
type AccountCommandRemove struct {
AccountUuid string `json:"accountUuid"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandRemove(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandRemove) ([]comby.Event, error)AccountCommandRemoveAttribute
Domain Command Struct:
type AccountCommandRemoveAttribute struct {
AccountUuid string `json:"accountUuid"`
Key string `json:"key"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandRemoveAttribute(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandRemoveAttribute) ([]comby.Event, error)AccountCommandSetAttribute
Domain Command Struct:
type AccountCommandSetAttribute struct {
AccountUuid string `json:"accountUuid"`
Key string `json:"key"`
Value any `json:"value"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandSetAttribute(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandSetAttribute) ([]comby.Event, error)AccountCommandUpdate
Domain Command Struct:
type AccountCommandUpdate struct {
AccountUuid string `json:"accountUuid"`
Attributes string `json:"attributes,omitempty"`
PatchedFields []string `json:"patchedFields"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandUpdate(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandUpdate) ([]comby.Event, error)AccountCommandUpdateCredentials
AccountCommandUpdateCredentials handles updating the credentials (email and password) of an account, with strict access control to ensure security and proper authorization.
This command enforces the following rules:
- Self-Account Update:
- A user can only update the credentials of their own account.
- This restriction ensures users cannot modify the credentials of other accounts, maintaining strict isolation.
- System Tenant Administrator Override:
- The system tenant administrator is allowed to update credentials for any account.
- This provides a controlled mechanism for administrative recovery or management of user credentials.
Domain Command Struct:
type AccountCommandUpdateCredentials struct {
AuthModel string `json:"authModel,omitempty"` // "emailPassword" or "opaque"
AccountUuid string `json:"accountUuid"`
// common fields
CurrentEmail string `json:"currentEmail,omitempty"`
NewEmail string `json:"newEmail,omitempty"`
// emailpassword only fields
CurrentPassword string `json:"currentPassword,omitempty"`
NewPassword string `json:"newPassword,omitempty"`
// opaque only fields
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandUpdateCredentials(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandUpdateCredentials) ([]comby.Event, error)AccountCommandUpdateState
Domain Command Struct:
type AccountCommandUpdateState struct {
AccountUuid string `json:"accountUuid"`
State string `json:"state"`
}Domain Command Handling Method:
func (ch *commandHandler) AccountCommandUpdateState(ctx context.Context, cmd comby.Command, domainCmd *AccountCommandUpdateState) ([]comby.Event, error)Queries
Domain Query Structs:
Domain Query Responses:
AccountQueryList
AccountQueryList returns a list of accounts based on the context of the requestor.
This query exhibits unique behavior, as its results vary depending on the context of the requesting entity. Specifically, the query's outcome can be classified into three distinct cases:
- System Tenant Context:
- When the requestor represents the system tenant, the query retrieves all accounts.
- This includes not only the accounts directly tied to the system tenant but also any identities belonging to other tenants.
- This behavior ensures that the system tenant maintains global visibility across all tenant identities.
- Specific Tenant Context:
- If the requestor represents a specific tenant, the query returns all accounts associated with that tenant.
- Importantly, it excludes accounts or identities that are linked to other tenants.
- This ensures that a tenant's view remains isolated, adhering to a strict multi-tenancy principle.
- Equal Sender and Target Context:
- In cases where an account requests the list of accounts, the query returns only the requesting account itself.
- This includes all identities associated with the requesting account, regardless of their tenant.
- This behavior ensures that the account sees only its own information while maintaining visibility into all related identities.
Domain Query Struct:
type AccountQueryList struct {
Page int64 `json:"page,omitempty"`
PageSize int64 `json:"pageSize,omitempty"`
OrderBy string `json:"orderBy,omitempty"`
Attributes string `json:"attributes,omitempty"`
IncludeHistory bool `json:"includeHistory,omitempty"`
}Domain Query Handling Method:
func (qh *queryHandler) AccountQueryList(ctx context.Context, qry comby.Query, domainQry *AccountQueryList) (*AccountQueryListResponse, error)AccountQueryModelByEmail
Domain Query Struct:
type AccountQueryModelByEmail struct {
Email string `json:"email"`
}Domain Query Handling Method:
func (qh *queryHandler) AccountQueryModelByEmail(ctx context.Context, qry comby.Query, domainQry *AccountQueryModelByEmail) (*AccountQueryItemResponse, error)AccountQueryModelEmailPassword
Domain Query Struct:
type AccountQueryModelEmailPassword struct {
Email string `json:"email"`
Password string `json:"password"`
IncludeLastSession bool `json:"includeLastSession,omitempty"`
IncludeAllSessions bool `json:"includeAllSessions,omitempty"`
}Domain Query Handling Method:
func (qh *queryHandler) AccountQueryModelEmailPassword(ctx context.Context, qry comby.Query, domainQry *AccountQueryModelEmailPassword) (*AccountQueryItemResponse, error)AccountQueryModel
Domain Query Struct:
type AccountQueryModel struct {
AccountUuid string `json:"accountUuid"`
IncludeHistory bool `json:"includeHistory,omitempty"`
}Domain Query Handling Method:
func (qh *queryHandler) AccountQueryModel(ctx context.Context, qry comby.Query, domainQry *AccountQueryModel) (*AccountQueryItemResponse, error)AccountQueryListResponse
type AccountQueryListResponse struct {
Items []*readmodel.AccountModel `json:"items,omitempty"`
Total int64 `json:"total,omitempty"`
Page int64 `json:"page,omitempty"`
PageSize int64 `json:"pageSize,omitempty"`
}AccountQueryItemResponse
type AccountQueryItemResponse struct {
Item *readmodel.AccountModel `json:"item,omitempty"`
}Events
- AccountLoggedInEvent
- AccountLoggedOutEvent
- AccountPasswordResetEvent
- AccountRegisteredEvent
- AccountRemovedEvent
- AccountAttributeRemovedEvent
- AccountAttributeSetEvent
- AccountUpdatedEvent
- AccountCredentialsUpdatedEvent
- AccountStateUpdatedEvent
AccountLoggedInEvent
Domain Event Struct:
type AccountLoggedInEvent struct {
AuthModel string `json:"authModel,omitempty"`
SessionUuid string `json:"sessionUuid"`
SessionKey string `json:"sessionKey"`
ExpiredAt int64 `json:"expiredAt"`
}Domain Event Handling Method:
func (agg *Account) AccountLoggedInEvent(ctx context.Context, evt comby.Event, domainEvt *AccountLoggedInEvent) (error)AccountLoggedOutEvent
Domain Event Struct:
type AccountLoggedOutEvent struct {
SessionUuid string `json:"sessionUuid"`
}Domain Event Handling Method:
func (agg *Account) AccountLoggedOutEvent(ctx context.Context, evt comby.Event, domainEvt *AccountLoggedOutEvent) (error)AccountPasswordResetEvent
Domain Event Struct:
type AccountPasswordResetEvent struct {
State string `json:"state"`
NewHashedPassword string `json:"newHashedPassword,omitempty"`
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord,omitempty"`
}Domain Event Handling Method:
func (agg *Account) AccountPasswordResetEvent(ctx context.Context, evt comby.Event, domainEvt *AccountPasswordResetEvent) (error)AccountRegisteredEvent
Domain Event Struct:
type AccountRegisteredEvent struct {
State string `json:"state,omitempty"`
AuthModel string `json:"authModel,omitempty"`
Email string `json:"email,omitempty"`
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord,omitempty"`
}Domain Event Handling Method:
func (agg *Account) AccountRegisteredEvent(ctx context.Context, evt comby.Event, domainEvt *AccountRegisteredEvent) (error)AccountRemovedEvent
Domain Event Struct:
type AccountRemovedEvent struct {
State string `json:"state,omitempty"`
Reason string `json:"reason,omitempty"`
}Domain Event Handling Method:
func (agg *Account) AccountRemovedEvent(ctx context.Context, evt comby.Event, domainEvt *AccountRemovedEvent) (error)AccountAttributeRemovedEvent
Domain Event Struct:
type AccountAttributeRemovedEvent struct {
Key string `json:"key"`
}Domain Event Handling Method:
func (agg *Account) AccountAttributeRemovedEvent(ctx context.Context, evt comby.Event, domainEvt *AccountAttributeRemovedEvent) (error)AccountAttributeSetEvent
Domain Event Struct:
type AccountAttributeSetEvent struct {
Key string `json:"key"`
Value any `json:"value"`
}Domain Event Handling Method:
func (agg *Account) AccountAttributeSetEvent(ctx context.Context, evt comby.Event, domainEvt *AccountAttributeSetEvent) (error)AccountUpdatedEvent
Domain Event Struct:
type AccountUpdatedEvent struct {
Attributes string `json:"attributes,omitempty"`
}Domain Event Handling Method:
func (agg *Account) AccountUpdatedEvent(ctx context.Context, evt comby.Event, domainEvt *AccountUpdatedEvent) (error)AccountCredentialsUpdatedEvent
Domain Event Struct:
type AccountCredentialsUpdatedEvent struct {
AuthModel string `json:"authModel,omitempty"`
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
OpaqueCredentialRecord *opaque.OpaqueCredentialRecord `json:"opaqueCredentialRecord,omitempty"`
}Domain Event Handling Method:
func (agg *Account) AccountCredentialsUpdatedEvent(ctx context.Context, evt comby.Event, domainEvt *AccountCredentialsUpdatedEvent) (error)AccountStateUpdatedEvent
Domain Event Struct:
type AccountStateUpdatedEvent struct {
State string `json:"state"`
}Domain Event Handling Method:
func (agg *Account) AccountStateUpdatedEvent(ctx context.Context, evt comby.Event, domainEvt *AccountStateUpdatedEvent) (error)Aggregate
Account represents the root aggregate for managing authentication and session handling.
- Credentials: Attributes for email, password, and the next allowed login time.
- CredentialsOpaque: OPAQUE credentials for passwordless authentication.
- Session: Details about active user sessions, including a unique session UUID, session key, and expiration time.
Aggregate Struct:
type Account struct {
*comby.BaseAggregate
// Entities
Credentials *Credentials
CredentialsOpaque *CredentialsOpaque
Sessions []*Session
// Value Objects
State string
}Methods
- ValidateLoginCredentials
- CreateLoginSession
- Login
- Logout
- PasswordReset
- ValidateRegistration
- CreateAccount
- Register
- Remove
- RemoveAttribute
- SetAttribute
- Update
- UpdateCredentials
- UpdateState
ValidateLoginCredentials
ValidateLoginCredentials validates the login credentials without creating a session. This is used in the pre-auth flow where credentials are validated before MFA.
func (agg *Account) ValidateLoginCredentials(opts ) (error)CreateLoginSession
CreateLoginSession creates a new login session after credentials have been validated. This is used after MFA confirmation in the new pre-auth flow.
func (agg *Account) CreateLoginSession(sessionUuid, sessionKey string, authModel string) (error)Login
Login validates credentials and creates a session in one step. DEPRECATED: Use ValidateLoginCredentials + CreateLoginSession for the new MFA flow.
func (agg *Account) Login(sessionUuid, sessionKey string, opts ) (error)Logout
func (agg *Account) Logout(opts ) (error)PasswordReset
func (agg *Account) PasswordReset(opts ) (error)ValidateRegistration
ValidateRegistration validates registration data without creating events. This should be called BEFORE sending MFA challenge. It validates email format only - email uniqueness must be checked by the caller.
func (agg *Account) ValidateRegistration(opts ) (error)CreateAccount
CreateAccount creates a new account and generates registration events. This should be called AFTER MFA confirmation.
func (agg *Account) CreateAccount(state string, opts ) (error)Register
Register creates a new account with credentials. DEPRECATED: Use ValidateRegistration + CreateAccount for the new MFA flow.
func (agg *Account) Register(state string, opts ) (error)Remove
func (agg *Account) Remove(opts ) (error)RemoveAttribute
func (agg *Account) RemoveAttribute(opts ) (error)SetAttribute
func (agg *Account) SetAttribute(opts ) (error)Update
func (agg *Account) Update(opts ) (error)UpdateCredentials
func (agg *Account) UpdateCredentials(opts ) (error)UpdateState
func (agg *Account) UpdateState(opts ) (error)Event Handlers
AccountReadmodel
| Domain Event | Method |
|---|---|
tenantAggregate.TenantCreatedEvent | TenantCreatedEvent |
tenantAggregate.TenantAttributeRemovedEvent | TenantAttributeRemovedEvent |
tenantAggregate.TenantAttributeSetEvent | TenantAttributeSetEvent |
tenantAggregate.TenantUpdatedEvent | TenantUpdatedEvent |
tenantAggregate.TenantRemovedEvent | TenantRemovedEvent |
identityAggregate.IdentityAttributeRemovedEvent | IdentityAttributeRemovedEvent |
identityAggregate.IdentityCreatedEvent | IdentityCreatedEvent |
identityAggregate.IdentityAttributeSetEvent | IdentityAttributeSetEvent |
identityAggregate.IdentityRemovedEvent | IdentityRemovedEvent |
identityAggregate.IdentityUpdatedEvent | IdentityUpdatedEvent |
identityAggregate.IdentityProfileUpdatedEvent | IdentityProfileUpdatedEvent |
identityAggregate.IdentityRemovedGroupEvent | IdentityRemovedGroupEvent |
identityAggregate.IdentityAddedGroupEvent | IdentityAddedGroupEvent |
groupAggregate.GroupRemovedEvent | GroupRemovedEvent |
groupAggregate.GroupUpdatedEvent | GroupUpdatedEvent |
groupAggregate.GroupAddedEvent | GroupAddedEvent |
accountAggregate.AccountRegisteredEvent | AccountRegisteredEvent |
accountAggregate.AccountStateUpdatedEvent | AccountStateUpdatedEvent |
accountAggregate.AccountUpdatedEvent | AccountUpdatedEvent |
accountAggregate.AccountAttributeRemovedEvent | AccountAttributeRemovedEvent |
accountAggregate.AccountAttributeSetEvent | AccountAttributeSetEvent |
accountAggregate.AccountLoggedOutEvent | AccountLoggedOutEvent |
accountAggregate.AccountLoggedInEvent | AccountLoggedInEvent |
accountAggregate.AccountCredentialsUpdatedEvent | AccountCredentialsUpdatedEvent |
accountAggregate.AccountRemovedEvent | AccountRemovedEvent |
accountAggregate.AccountPasswordResetEvent | AccountPasswordResetEvent |
Custom Permissions
| Name | Type | Comment |
|---|---|---|
| AccountCommandActivate | Command | Activate an existing account |
| AccountCommandPasswordReset | Command | Reset password of an existing account |
| AccountCommandCreate | Command | Create new account manually |
| AccountCommandLoginOAuth | Command | Login into an existing account using OAuth |
| AccountCommandLogin | Command | Login into an existing account |
| AccountCommandCreateLoginSession | Command | Create a login session after credentials have been validated |
| AccountCommandLogout | Command | Logout an account |
| AccountCommandRegister | Command | Register new account |
| AccountCommandCreateRegistration | Command | Create new account registration |
| AccountCommandRemove | Command | Remove existing account |
| AccountCommandUpdateCredentials | Command | Update credentials of an existing account |
| AccountCommandUpdate | Command | Update account |
| AccountCommandSetAttribute | Command | Set single attribute of an existing account |
| AccountCommandRemoveAttribute | Command | Remove single attribute of an existing account |
| AccountCommandUpdateState | Command | Update state of an existing account |
| AccountQueryModelEmailPassword | Query | Request account details by email and password |
| AccountQueryModel | Query | Request account details |