Appearance
Note: This document is superseded by Client Authentication Workflow (Detailed).
Client Authentication
Client accounts are scoped to a specific agency. These accounts are disjoint, meaning a single email can be registered in multiple agencies without any connection between them.
Registration Flow (Email + Password)
Client registration requires an agencyId.
- Request Registration: The
RegisterClientCommandis executed. It checks if theagencyIdis valid and if the email is already used within that specific agency. - Verify Email: The
VerifyEmailClientCommandis executed. It activates the client account scoped to the agency and returns a Token Pair.
sequenceDiagram
participant Client as Frontend (Panel)
participant API as ClientAuthController
participant Bus as CommandBus
participant Handler as RegisterClientHandler
participant DB as Identity Database
participant Pub as IdentityPublisher
Client->>API: POST /auth/client/register {email, agencyId, ...}
API->>Bus: Execute RegisterClientCommand
Bus->>Handler: execute()
Handler->>DB: Check if agency exists
Handler->>DB: Save Client (isActive: false)
Handler->>DB: Save Verification Token
Handler->>Pub: publishClientRegistered()
Pub-->>Client: Email with code (via EventBus)
Handler-->>API: Result.ok
API-->>Client: 200 OK (Verification code sent)
Login Flow (Email + Password)
Login is handled by the LocalClientStrategy. The agencyId must be provided in the request body.
sequenceDiagram
participant Client as Frontend (Panel)
participant Guard as LocalClientAuthGuard
participant Strat as LocalClientStrategy
participant API as ClientAuthController
participant Bus as CommandBus
participant Handler as LoginClientHandler
Client->>Guard: POST /auth/client/login {email, password, agencyId}
Guard->>Strat: validate(email, password, agencyId)
Strat->>Strat: Check password (HashingService)
Strat-->>Guard: return Client entity
Guard->>API: req.user = Client
API->>Bus: Execute LoginClientCommand(Client)
Bus->>Handler: execute()
Handler-->>API: TokenPair {accessToken, refreshToken}
API-->>Client: 200 OK (Tokens)
Google OAuth Flow
Client Google OAuth is uniquely scoped using the state parameter in the OAuth 2.0 flow.
- Redirect: User is sent to Google's consent screen via
ClientAuthController.googleRedirect?agencyId=.... TheagencyIdis embedded in thestateparameter. - Callback: Google redirects back to
ClientAuthController.googleCallbackwithcodeandstate(which contains ouragencyId). - Command Execution:
GoogleLoginClientCommanduses theagencyIdto correctly scope the login/registration.
sequenceDiagram
participant User as User Browser
participant API as ClientAuthController
participant Bus as CommandBus
participant Handler as GoogleLoginClientHandler
User->>API: GET /auth/client/google?agencyId=...
API->>API: Prepare OAuth URL (state=agencyId)
API->>User: Redirect to Google
User->>User: Consent & Authenticate
User->>API: GET /auth/client/google/callback?code=...&state=agencyId
API->>Bus: Execute GoogleLoginClientCommand(code, agencyId)
Bus->>Handler: execute()
Handler->>Handler: Exchange code for profile
Handler->>Handler: Link or Create Client (scoped to agencyId)
Handler-->>API: TokenPair
API-->>User: 200 OK (Tokens)