127 lines
4.6 KiB
Markdown
127 lines
4.6 KiB
Markdown
# 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 Mail Service REST
|
|
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 + Accept-Language
|
|
Gateway->>Auth: POST /api/v1/public/auth/send-email-code + Accept-Language
|
|
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: POST /api/v1/internal/login-code-deliveries + Idempotency-Key=challenge_id
|
|
Mail-->>Auth: 200 {outcome=sent|suppressed} / 503
|
|
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, stored preferred_language + time_zone)
|
|
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}
|
|
```
|
|
|
|
Auth uses the dedicated trusted `Mail Service` REST route
|
|
`POST /api/v1/internal/login-code-deliveries`.
|
|
It sends the created `challenge_id` as the raw `Idempotency-Key` header
|
|
value.
|
|
For this boundary, `sent` means durable acceptance into the mail-delivery
|
|
pipeline; SMTP completion may still happen later in `Mail Service` workers.
|
|
|
|
## 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
|