feat: authsession service
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# Auth, Revoke, and Repair Flows
|
||||
|
||||
## Public Auth Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Gateway
|
||||
participant Auth
|
||||
participant Abuse as Resend throttle
|
||||
participant User as UserDirectory
|
||||
participant Mail as MailSender
|
||||
participant Challenge as ChallengeStore
|
||||
participant Session as SessionStore
|
||||
participant Config as ConfigProvider
|
||||
participant Projection as Gateway projection publisher
|
||||
|
||||
Client->>Gateway: POST /api/v1/public/auth/send-email-code
|
||||
Gateway->>Auth: POST /api/v1/public/auth/send-email-code
|
||||
Auth->>Abuse: check and reserve cooldown
|
||||
alt throttled
|
||||
Abuse-->>Auth: throttled
|
||||
Auth->>Challenge: create delivery_throttled challenge
|
||||
Auth-->>Gateway: 200 {challenge_id}
|
||||
else allowed
|
||||
Abuse-->>Auth: allowed
|
||||
Auth->>User: ResolveByEmail(email)
|
||||
User-->>Auth: existing / creatable / blocked
|
||||
Auth->>Challenge: create pending challenge
|
||||
alt blocked
|
||||
Auth->>Challenge: mark delivery_suppressed
|
||||
else not blocked
|
||||
Auth->>Mail: SendLoginCode(email, code)
|
||||
Mail-->>Auth: sent / suppressed / failure
|
||||
Auth->>Challenge: persist final delivery outcome
|
||||
end
|
||||
Auth-->>Gateway: 200 {challenge_id}
|
||||
end
|
||||
|
||||
Client->>Gateway: POST /api/v1/public/auth/confirm-email-code
|
||||
Gateway->>Auth: POST /api/v1/public/auth/confirm-email-code
|
||||
Auth->>Challenge: load and validate challenge
|
||||
Auth->>User: EnsureUserByEmail(email)
|
||||
User-->>Auth: existing / created / blocked
|
||||
Auth->>Config: LoadSessionLimit()
|
||||
Auth->>Session: CountActiveByUserID(user_id)
|
||||
Auth->>Session: create device session
|
||||
Auth->>Challenge: CAS to confirmed_pending_expire
|
||||
Auth->>Session: reread current stored session view
|
||||
Auth->>Projection: publish gateway snapshot
|
||||
Auth-->>Gateway: 200 {device_session_id}
|
||||
```
|
||||
|
||||
## Revoke and Block Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Caller as Trusted internal caller
|
||||
participant Auth
|
||||
participant User as UserDirectory
|
||||
participant Session as SessionStore
|
||||
participant Projection as Gateway projection publisher
|
||||
participant Gateway
|
||||
|
||||
Caller->>Auth: revoke or block request
|
||||
alt block by user or email
|
||||
Auth->>User: apply block mutation
|
||||
User-->>Auth: blocked / already_blocked
|
||||
end
|
||||
Auth->>Session: revoke one or many sessions
|
||||
Session-->>Auth: updated source-of-truth sessions
|
||||
loop each affected session
|
||||
Auth->>Projection: publish revoked snapshot
|
||||
end
|
||||
Auth-->>Caller: 200 acknowledgement
|
||||
Projection-->>Gateway: revoked session snapshot
|
||||
```
|
||||
|
||||
## Projection Repair On Retry
|
||||
|
||||
Projection writes happen after source-of-truth updates. If projection publish
|
||||
fails after state is already stored, the caller sees `service_unavailable`, and
|
||||
the repair path is to repeat the same request.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Auth
|
||||
participant Challenge as ChallengeStore
|
||||
participant Session as SessionStore
|
||||
participant Projection as Gateway projection publisher
|
||||
|
||||
Client->>Auth: confirm-email-code
|
||||
Auth->>Challenge: validate challenge
|
||||
Auth->>Session: create session
|
||||
Auth->>Challenge: persist confirmed_pending_expire
|
||||
Auth->>Projection: publish snapshot
|
||||
Projection-->>Auth: failure
|
||||
Auth-->>Client: 503 service_unavailable
|
||||
|
||||
Client->>Auth: repeat same confirm-email-code
|
||||
Auth->>Challenge: load confirmed_pending_expire challenge
|
||||
Auth->>Session: load stored session from confirmation metadata
|
||||
Auth->>Projection: republish current stored session view
|
||||
Projection-->>Auth: success
|
||||
Auth-->>Client: 200 {device_session_id}
|
||||
```
|
||||
|
||||
## Confirm-Race Cleanup
|
||||
|
||||
Concurrent identical confirms are allowed to race at the store level, but the
|
||||
service converges them back to one surviving active session.
|
||||
|
||||
- the winning CAS stores challenge confirmation metadata and publishes the
|
||||
surviving session snapshot
|
||||
- a superseded session created by a losing racing request is revoked
|
||||
best-effort with `reason_code=confirm_race_repair`
|
||||
- cleanup uses the same projection helper, but cleanup failure is not part of
|
||||
the caller-visible success contract
|
||||
Reference in New Issue
Block a user