1153 lines
30 KiB
Markdown
1153 lines
30 KiB
Markdown
# Auth / Session Service Implementation Plan
|
|
|
|
This plan has been already implemented and stays here for historical reasons.
|
|
|
|
It should NOT be threated as source of truth for service functionality.
|
|
|
|
## Purpose
|
|
|
|
This plan describes a detailed, incremental implementation path for
|
|
[`Auth / Session Service`](README.md) that integrates with the existing
|
|
`Edge Gateway`.
|
|
|
|
The plan is intentionally atomic.
|
|
Each stage should be small enough to implement, review, and test without
|
|
overloading development context.
|
|
|
|
## Global Rules for the Entire Plan
|
|
|
|
- keep domain logic independent from concrete storage backends;
|
|
- keep gateway projection separate from source-of-truth records;
|
|
- preserve the existing public auth contract expected by gateway:
|
|
- `send-email-code` -> `challenge_id`
|
|
- `confirm-email-code` -> `device_session_id`
|
|
- keep `confirm-email-code` synchronous;
|
|
- do not introduce a pending async session-provisioning model;
|
|
- use synchronous internal REST where immediate answer is required;
|
|
- use Redis Streams / pub-sub only for session lifecycle propagation and other
|
|
event-style side effects;
|
|
- keep implementation idempotent where retries are expected;
|
|
- design Redis-backed stores behind interfaces so SQL migration remains possible.
|
|
|
|
## Milestone Structure
|
|
|
|
Suggested milestones:
|
|
|
|
1. Domain skeleton and ports
|
|
2. In-memory service behavior and tests
|
|
3. Redis-backed source-of-truth stores
|
|
4. Gateway projection publisher
|
|
5. Public HTTP API
|
|
6. Internal trusted API
|
|
7. Integration with user-service and config-provider ports
|
|
8. Revoke/block flows
|
|
9. Observability and hardening
|
|
10. End-to-end integration with gateway
|
|
|
|
## Suggested Module Structure
|
|
|
|
The structure described below is allowed to be changed
|
|
during the Plan steps implementation.
|
|
|
|
```text
|
|
authsession/
|
|
├── cmd/
|
|
│ └── authsession/
|
|
│ └── main.go
|
|
│
|
|
├── internal/
|
|
│ ├── app/
|
|
│ │ ├── app.go
|
|
│ │ ├── bootstrap.go
|
|
│ │ └── wiring.go
|
|
│ │
|
|
│ ├── config/
|
|
│ │ ├── config.go
|
|
│ │ ├── env.go
|
|
│ │ └── validation.go
|
|
│ │
|
|
│ ├── domain/
|
|
│ │ ├── challenge/
|
|
│ │ │ ├── model.go
|
|
│ │ │ ├── state.go
|
|
│ │ │ ├── policy.go
|
|
│ │ │ └── errors.go
|
|
│ │ │
|
|
│ │ ├── devicesession/
|
|
│ │ │ ├── model.go
|
|
│ │ │ ├── state.go
|
|
│ │ │ ├── revoke.go
|
|
│ │ │ └── errors.go
|
|
│ │ │
|
|
│ │ ├── userresolution/
|
|
│ │ │ ├── model.go
|
|
│ │ │ └── policy.go
|
|
│ │ │
|
|
│ │ ├── sessionlimit/
|
|
│ │ │ ├── model.go
|
|
│ │ │ └── policy.go
|
|
│ │ │
|
|
│ │ └── common/
|
|
│ │ ├── email.go
|
|
│ │ ├── time.go
|
|
│ │ ├── ids.go
|
|
│ │ └── types.go
|
|
│ │
|
|
│ ├── ports/
|
|
│ │ ├── challengestore.go
|
|
│ │ ├── sessionstore.go
|
|
│ │ ├── userdirectory.go
|
|
│ │ ├── configprovider.go
|
|
│ │ ├── mailsender.go
|
|
│ │ ├── projectionpublisher.go
|
|
│ │ ├── clock.go
|
|
│ │ ├── idgenerator.go
|
|
│ │ ├── codegenerator.go
|
|
│ │ └── codehasher.go
|
|
│ │
|
|
│ ├── service/
|
|
│ │ ├── sendemailcode/
|
|
│ │ │ └── service.go
|
|
│ │ ├── confirmemailcode/
|
|
│ │ │ └── service.go
|
|
│ │ ├── getsession/
|
|
│ │ │ └── service.go
|
|
│ │ ├── listusersessions/
|
|
│ │ │ └── service.go
|
|
│ │ ├── revokedevicesession/
|
|
│ │ │ └── service.go
|
|
│ │ ├── revokeallusersessions/
|
|
│ │ │ └── service.go
|
|
│ │ ├── blockuser/
|
|
│ │ │ └── service.go
|
|
│ │ └── shared/
|
|
│ │ ├── normalize.go
|
|
│ │ ├── projection.go
|
|
│ │ └── publicerrors.go
|
|
│ │
|
|
│ ├── api/
|
|
│ │ ├── publichttp/
|
|
│ │ │ ├── handler_send_email_code.go
|
|
│ │ │ ├── handler_confirm_email_code.go
|
|
│ │ │ ├── dto.go
|
|
│ │ │ └── errors.go
|
|
│ │ │
|
|
│ │ └── internalhttp/
|
|
│ │ ├── handler_get_session.go
|
|
│ │ ├── handler_list_user_sessions.go
|
|
│ │ ├── handler_revoke_device_session.go
|
|
│ │ ├── handler_revoke_all_user_sessions.go
|
|
│ │ ├── handler_block_user.go
|
|
│ │ ├── dto.go
|
|
│ │ └── errors.go
|
|
│ │
|
|
│ ├── adapters/
|
|
│ │ ├── redis/
|
|
│ │ │ ├── challengestore/
|
|
│ │ │ │ └── store.go
|
|
│ │ │ ├── sessionstore/
|
|
│ │ │ │ └── store.go
|
|
│ │ │ ├── configprovider/
|
|
│ │ │ │ └── provider.go
|
|
│ │ │ └── gatewayprojection/
|
|
│ │ │ ├── publisher.go
|
|
│ │ │ ├── snapshot.go
|
|
│ │ │ └── stream.go
|
|
│ │ │
|
|
│ │ ├── userservice/
|
|
│ │ │ ├── client.go
|
|
│ │ │ ├── mapper.go
|
|
│ │ │ └── stub.go
|
|
│ │ │
|
|
│ │ ├── mail/
|
|
│ │ │ ├── stub.go
|
|
│ │ │ └── rest_client.go
|
|
│ │ │
|
|
│ │ ├── crypto/
|
|
│ │ │ ├── codehasher.go
|
|
│ │ │ └── publickey.go
|
|
│ │ │
|
|
│ │ ├── clock/
|
|
│ │ │ └── system.go
|
|
│ │ │
|
|
│ │ └── id/
|
|
│ │ ├── challengeid.go
|
|
│ │ └── devicesessionid.go
|
|
│ │
|
|
│ ├── observability/
|
|
│ │ ├── logging.go
|
|
│ │ ├── metrics.go
|
|
│ │ └── tracing.go
|
|
│ │
|
|
│ └── testkit/
|
|
│ ├── fixtures.go
|
|
│ ├── fake_clock.go
|
|
│ ├── fake_idgen.go
|
|
│ ├── fake_mail.go
|
|
│ ├── fake_userdir.go
|
|
│ └── fake_projection.go
|
|
│
|
|
├── api/
|
|
│ ├── public-openapi.yaml
|
|
│ └── internal-openapi.yaml
|
|
│
|
|
└── README.md
|
|
```
|
|
|
|
### Description
|
|
|
|
- `cmd/authsession` — service entry point: process startup, configuration loading, application assembly, and HTTP server startup.
|
|
|
|
- `internal/app` — top-level application orchestration layer: dependency initialization, runtime bootstrap, and component wiring.
|
|
|
|
- `internal/config` — service configuration loading, normalization, and validation from environment and other sources.
|
|
|
|
- `internal/domain/challenge` — domain model for the `send_email_code` / `confirm_email_code` challenge flow: states, transitions, TTL/retry policies, and domain errors.
|
|
|
|
- `internal/domain/devicesession` — domain model for `device_session`: session state, revocation, revoke reasons, and related domain errors.
|
|
|
|
- `internal/domain/userresolution` — domain model for user resolution by email through user-service: existing user, allowed registration, or blocked user.
|
|
|
|
- `internal/domain/sessionlimit` — domain model and policy rules for active `device_session` limits.
|
|
|
|
- `internal/domain/common` — shared domain value objects and helper types: email, time, identifiers, and common primitive types.
|
|
|
|
- `internal/ports` — interfaces for all external dependencies: source-of-truth stores, user-service, mail delivery, config, projection publisher, clock, generators, and hashing.
|
|
|
|
- `internal/service/sendemailcode` — use case for sending a code: email normalization, challenge lifecycle, suppression/send decision, and success-shaped public response.
|
|
|
|
- `internal/service/confirmemailcode` — use case for confirming a code: challenge validation, public-key validation, resolve/create user flow, session-limit enforcement, `device_session` creation, and projection publication.
|
|
|
|
- `internal/service/getsession` — use case for reading a single `device_session` for the trusted internal API.
|
|
|
|
- `internal/service/listusersessions` — use case for listing user sessions for the trusted internal API.
|
|
|
|
- `internal/service/revokedevicesession` — use case for revoking a single device session and publishing the updated gateway projection.
|
|
|
|
- `internal/service/revokeallusersessions` — use case for revoking all active sessions of a user and publishing the resulting updates.
|
|
|
|
- `internal/service/blockuser` — use case for blocking a user/email and revoking active sessions according to policy.
|
|
|
|
- `internal/service/shared` — shared application-layer code: normalization helpers, gateway projection builders, and public error mapping.
|
|
|
|
- `internal/api/publichttp` — public HTTP API for gateway integration: handlers, DTOs, and error mapping for `send_email_code` and `confirm_email_code`.
|
|
|
|
- `internal/api/internalhttp` — trusted internal HTTP API: revoke/read/list/block endpoints, DTOs, and separate internal error policy.
|
|
|
|
- `internal/adapters/redis/challengestore` — Redis adapter for source-of-truth challenge storage.
|
|
|
|
- `internal/adapters/redis/sessionstore` — Redis adapter for source-of-truth `device_session` storage.
|
|
|
|
- `internal/adapters/redis/configprovider` — Redis adapter for dynamic configuration, such as active-session limits.
|
|
|
|
- `internal/adapters/redis/gatewayprojection` — Redis adapter for the `Edge Gateway` integration projection: KV snapshots and lifecycle updates in streams.
|
|
|
|
- `internal/adapters/userservice` — user-service integration adapter: REST client, response-to-domain mapping, and stub implementation for early stages.
|
|
|
|
- `internal/adapters/mail` — mail-delivery adapter: development stub and future REST mail-service client.
|
|
|
|
- `internal/adapters/crypto` — cryptographic adapters: confirmation-code hashing and `client_public_key` validation/parsing.
|
|
|
|
- `internal/adapters/clock` — system clock implementation.
|
|
|
|
- `internal/adapters/id` — generation of stable domain identifiers such as `challenge_id` and `device_session_id`.
|
|
|
|
- `internal/observability` — service logging, metrics, and tracing.
|
|
|
|
- `internal/testkit` — test fixtures, fake/mock dependencies, and shared helpers for unit and integration tests.
|
|
|
|
- `api/public-openapi.yaml` — formal specification of the public HTTP API.
|
|
|
|
- `api/internal-openapi.yaml` — formal specification of the trusted internal HTTP API.
|
|
|
|
- `README.md` — architectural service description covering its role in the system, contracts, domain rules, and integrations.
|
|
|
|
---
|
|
|
|
## ~~Stage 1.~~ Freeze the Service Contract
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Write down the exact service-level contracts before implementation starts.
|
|
|
|
### Tasks
|
|
|
|
- freeze public auth use cases:
|
|
- `send_email_code`
|
|
- `confirm_email_code`
|
|
- freeze internal trusted use cases:
|
|
- `GetSession`
|
|
- `ListUserSessions`
|
|
- `RevokeDeviceSession`
|
|
- `RevokeAllUserSessions`
|
|
- `BlockUser`
|
|
- define canonical request/response DTOs for the service boundary;
|
|
- define client-safe error classes for the public auth API;
|
|
- define richer internal error classes for logs and internal API.
|
|
|
|
### Deliverables
|
|
|
|
- service contract notes in repo docs;
|
|
- initial error catalog;
|
|
- agreement on public vs internal API boundaries.
|
|
|
|
### Exit Criteria
|
|
|
|
- no unresolved ambiguity around public auth input/output shapes;
|
|
- no unresolved ambiguity around internal revoke/read operations.
|
|
|
|
---
|
|
|
|
## ~~Stage 2.~~ Define Core Domain Types
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Create the minimal domain model without any transport or storage code.
|
|
|
|
### Tasks
|
|
|
|
- define challenge aggregate concept;
|
|
- define device-session aggregate concept;
|
|
- define revoke reason model;
|
|
- define user resolution result model:
|
|
- existing user
|
|
- creatable user
|
|
- blocked user
|
|
- define session-limit decision model;
|
|
- define mail-delivery result model;
|
|
- define projection snapshot model for gateway integration;
|
|
- define domain statuses and allowed transitions.
|
|
|
|
### Important Constraints
|
|
|
|
- challenge and session models must not depend on Redis-specific encoding;
|
|
- gateway projection model must be separate from domain entities.
|
|
|
|
### Deliverables
|
|
|
|
- domain package with types only;
|
|
- transition invariants documented in code comments and tests.
|
|
|
|
### Exit Criteria
|
|
|
|
- domain package compiles without storage adapters;
|
|
- status transitions are covered by unit tests.
|
|
|
|
---
|
|
|
|
## ~~Stage 3.~~ Define Service Ports
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Create clean interfaces around every external dependency.
|
|
|
|
### Tasks
|
|
|
|
Define interfaces conceptually equivalent to:
|
|
|
|
- `ChallengeStore`
|
|
- `SessionStore`
|
|
- `UserDirectory` / `UserResolver`
|
|
- `ConfigProvider`
|
|
- `MailSender`
|
|
- `GatewaySessionProjectionPublisher`
|
|
- `Clock`
|
|
- `IDGenerator`
|
|
- `CodeGenerator`
|
|
- `CodeHasher`
|
|
|
|
### Notes
|
|
|
|
- `ChallengeStore` and `SessionStore` are source-of-truth ports;
|
|
- `GatewaySessionProjectionPublisher` is an integration port, not a domain
|
|
store;
|
|
- `UserDirectory` must support existing / creatable / blocked decisions and
|
|
user creation when allowed;
|
|
- `ConfigProvider` must support "limit absent" as a first-class case.
|
|
|
|
### Deliverables
|
|
|
|
- interface package or packages;
|
|
- port-level test doubles.
|
|
|
|
### Exit Criteria
|
|
|
|
- service layer can be implemented against interfaces only.
|
|
|
|
---
|
|
|
|
## ~~Stage 4.~~ Implement Pure Domain Services In Memory
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Implement the auth logic once, against in-memory stores and adapters.
|
|
|
|
### Tasks
|
|
|
|
Implement core use cases:
|
|
|
|
- `SendEmailCode`
|
|
- `ConfirmEmailCode`
|
|
- `GetSession`
|
|
- `ListUserSessions`
|
|
- `RevokeDeviceSession`
|
|
- `RevokeAllUserSessions`
|
|
- `BlockUser`
|
|
|
|
### Required Behaviors
|
|
|
|
#### SendEmailCode
|
|
|
|
- normalize email;
|
|
- consult `UserDirectory` policy if needed;
|
|
- create challenge;
|
|
- generate secure code;
|
|
- store only hashed code;
|
|
- attempt delivery or suppress it;
|
|
- always return a success-shaped result with `challenge_id`.
|
|
|
|
#### ConfirmEmailCode
|
|
|
|
- load challenge;
|
|
- validate expiration and status;
|
|
- validate code hash;
|
|
- validate `client_public_key` format;
|
|
- handle idempotent repeat confirm for same successful challenge and same key;
|
|
- resolve/create user through `UserDirectory`;
|
|
- reject blocked user;
|
|
- load session-limit config;
|
|
- count active sessions;
|
|
- reject if limit exceeded;
|
|
- create session;
|
|
- store session;
|
|
- move challenge into short-window confirmed state;
|
|
- publish session projection;
|
|
- return `device_session_id`.
|
|
|
|
#### Revoke Flows
|
|
|
|
- update source of truth;
|
|
- publish revoked projection for every affected session.
|
|
|
|
### Deliverables
|
|
|
|
- service layer with in-memory dependencies;
|
|
- unit tests for every public behavior.
|
|
|
|
### Exit Criteria
|
|
|
|
- full service logic is testable without Redis or HTTP;
|
|
- edge cases are covered by unit tests.
|
|
|
|
---
|
|
|
|
## ~~Stage 5.~~ Design Challenge Rules in Detail
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Remove ambiguity from challenge handling before persistent adapters are written.
|
|
|
|
### Tasks
|
|
|
|
- define challenge TTL;
|
|
- define max confirm attempts;
|
|
- define resend behavior policy, if any;
|
|
- define short idempotency window after successful confirm;
|
|
- define state machine for:
|
|
- new challenge
|
|
- sent/suppressed
|
|
- confirmed
|
|
- expired
|
|
- failed
|
|
- define exact behavior for repeated confirms:
|
|
- same code + same key -> same session id
|
|
- same code + different key -> fail
|
|
- expired challenge -> fail
|
|
- too many attempts -> fail
|
|
|
|
### Deliverables
|
|
|
|
- explicit challenge policy spec in code comments/tests.
|
|
|
|
### Exit Criteria
|
|
|
|
- no hidden challenge behavior remains undecided.
|
|
|
|
---
|
|
|
|
## ~~Stage 6.~~ Define Public Error Policy
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Make public auth failures predictable and safe.
|
|
|
|
### Tasks
|
|
|
|
Decide exact client-safe categories for:
|
|
|
|
- malformed e-mail;
|
|
- malformed `client_public_key`;
|
|
- unknown challenge;
|
|
- expired challenge;
|
|
- invalid code;
|
|
- blocked by policy at confirm stage;
|
|
- session limit exceeded;
|
|
- temporarily unavailable.
|
|
|
|
### Additional Rules
|
|
|
|
- `send_email_code` must not reveal whether the e-mail exists or is blocked;
|
|
- public errors should be normalized for gateway passthrough;
|
|
- internal logs and traces may keep richer reasons.
|
|
|
|
### Deliverables
|
|
|
|
- public error mapping table;
|
|
- internal error hierarchy.
|
|
|
|
### Exit Criteria
|
|
|
|
- gateway adapter behavior can be implemented without guesswork.
|
|
|
|
---
|
|
|
|
## ~~Stage 7.~~ Implement Redis ChallengeStore
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Add the first persistent backend for challenges.
|
|
|
|
### Tasks
|
|
|
|
- implement challenge read/write/update operations in Redis KV;
|
|
- define Redis key scheme for challenges;
|
|
- store hashed codes only;
|
|
- store challenge status and timestamps;
|
|
- support atomic compare-and-set style updates where required;
|
|
- support expiration cleanup through TTL and/or explicit status.
|
|
|
|
### Important Design Rule
|
|
|
|
The interface must not expose Redis primitives directly.
|
|
|
|
### Deliverables
|
|
|
|
- Redis-backed challenge store adapter;
|
|
- adapter integration tests against Redis.
|
|
|
|
### Exit Criteria
|
|
|
|
- challenge lifecycle works against Redis under concurrent access assumptions.
|
|
|
|
---
|
|
|
|
## ~~Stage 8.~~ Implement Redis SessionStore
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Add the first persistent backend for sessions.
|
|
|
|
### Tasks
|
|
|
|
- implement create/read/list/revoke operations;
|
|
- define Redis key scheme for sessions;
|
|
- support listing all sessions for one user;
|
|
- support revoking one session;
|
|
- support revoking all sessions for one user;
|
|
- support block-related session revocation;
|
|
- support active-session counting for limit enforcement;
|
|
- store revoke reason and actor metadata.
|
|
|
|
### Important Design Rule
|
|
|
|
The session source-of-truth record must remain distinct from gateway projection
|
|
encoding.
|
|
|
|
### Deliverables
|
|
|
|
- Redis-backed session store adapter;
|
|
- adapter integration tests.
|
|
|
|
### Exit Criteria
|
|
|
|
- all session lifecycle operations are persistent and testable.
|
|
|
|
---
|
|
|
|
## ~~Stage 9.~~ Implement Redis ConfigProvider
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Support dynamic session-limit configuration.
|
|
|
|
### Tasks
|
|
|
|
- implement config lookup from Redis KV;
|
|
- define config key scheme for auth-service settings;
|
|
- support:
|
|
- limit present with integer value
|
|
- limit absent
|
|
- invalid config value
|
|
- define fallback behavior for invalid config read.
|
|
|
|
### Required Behavior
|
|
|
|
- missing config -> no session-count limit;
|
|
- invalid config -> fail closed or fail safe according to explicit decision;
|
|
- document the chosen policy.
|
|
|
|
### Deliverables
|
|
|
|
- Redis-backed config adapter;
|
|
- tests for absent, valid, and invalid values.
|
|
|
|
### Exit Criteria
|
|
|
|
- session-limit logic no longer depends on hard-coded constants.
|
|
|
|
---
|
|
|
|
## ~~Stage 10.~~ Implement Gateway Session Projection Publisher
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Bridge auth source-of-truth state into gateway-facing cache/projection state.
|
|
|
|
### Tasks
|
|
|
|
- define exact projection snapshot structure consumed by gateway;
|
|
- define Redis KV key scheme for gateway session lookup;
|
|
- define Redis Stream schema for session lifecycle updates;
|
|
- implement projection write on session create;
|
|
- implement projection update on session revoke;
|
|
- implement projection update for bulk revoke/all;
|
|
- make publication idempotent and retry-safe.
|
|
|
|
### Important Constraints
|
|
|
|
- projection publisher should accept domain session data and transform it;
|
|
- it must not force domain logic to know Redis snapshot shape.
|
|
|
|
### Deliverables
|
|
|
|
- Redis-backed projection publisher;
|
|
- integration tests that emulate gateway expectations.
|
|
|
|
### Exit Criteria
|
|
|
|
- created sessions appear in gateway-readable projection;
|
|
- revoked sessions produce gateway-readable invalidation/update records.
|
|
|
|
---
|
|
|
|
## ~~Stage 11.~~ Implement Stub MailSender
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Introduce the mail-delivery port without coupling auth logic to one concrete delivery transport.
|
|
|
|
### Tasks
|
|
|
|
- create a stub adapter with deterministic success/failure modes;
|
|
- record delivery attempts for tests;
|
|
- support explicit suppression mode for blocked/hidden flows;
|
|
- ensure service logic can distinguish:
|
|
- sent
|
|
- suppressed
|
|
- failed
|
|
|
|
### Deliverables
|
|
|
|
- stub mail adapter;
|
|
- tests around challenge delivery state transitions.
|
|
|
|
### Exit Criteria
|
|
|
|
- auth logic is fully testable without real mail infrastructure.
|
|
|
|
---
|
|
|
|
## ~~Stage 12.~~ Implement Stub UserDirectory
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Introduce the user-service dependency before its real service exists.
|
|
|
|
### Tasks
|
|
|
|
- create an in-memory or stub REST-like adapter that can return:
|
|
- existing user
|
|
- creatable user
|
|
- blocked user
|
|
- support create-on-confirm behavior;
|
|
- support lookups by normalized email;
|
|
- support user block state.
|
|
|
|
### Deliverables
|
|
|
|
- stub user-service adapter;
|
|
- integration tests for auth flows.
|
|
|
|
### Exit Criteria
|
|
|
|
- auth-service no longer needs to fake user decisions internally.
|
|
|
|
---
|
|
|
|
## ~~Stage 13.~~ Implement Public HTTP API
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Expose the synchronous public auth flow expected by gateway.
|
|
|
|
### Tasks
|
|
|
|
- create HTTP handlers for:
|
|
- `send_email_code`
|
|
- `confirm_email_code`
|
|
- define JSON DTOs matching gateway expectations;
|
|
- implement request validation;
|
|
- implement response normalization;
|
|
- implement mapping from internal errors to public client-safe errors;
|
|
- add request timeout handling and structured logging.
|
|
|
|
### Important Constraints
|
|
|
|
- keep semantics aligned with gateway adapter expectations;
|
|
- do not expose internal admin/session methods on the public listener.
|
|
|
|
### Deliverables
|
|
|
|
- public HTTP server;
|
|
- handler tests;
|
|
- end-to-end tests through HTTP.
|
|
|
|
### Exit Criteria
|
|
|
|
- gateway can call the service through a real HTTP adapter.
|
|
|
|
---
|
|
|
|
## ~~Stage 14.~~ Implement Internal Trusted API
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Expose lifecycle and read operations for trusted internal callers.
|
|
|
|
### Tasks
|
|
|
|
Implement internal endpoints for:
|
|
|
|
- `GetSession`
|
|
- `ListUserSessions`
|
|
- `RevokeDeviceSession`
|
|
- `RevokeAllUserSessions`
|
|
- `BlockUser`
|
|
|
|
Optional additions later:
|
|
|
|
- unblock flow;
|
|
- challenge inspection.
|
|
|
|
### Notes
|
|
|
|
- this may use REST for simplicity;
|
|
- authentication/authorization of internal callers can be stubbed initially if
|
|
there is not yet a platform-wide internal auth mechanism.
|
|
|
|
### Deliverables
|
|
|
|
- internal HTTP API;
|
|
- handler tests.
|
|
|
|
### Exit Criteria
|
|
|
|
- session lifecycle can be driven without touching Redis manually.
|
|
|
|
---
|
|
|
|
## ~~Stage 15.~~ Implement Revoke Logic Thoroughly
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Make revoke behavior explicit and reliable.
|
|
|
|
### Tasks
|
|
|
|
For `RevokeDeviceSession`:
|
|
|
|
- load target session;
|
|
- no-op or explicit result if already revoked;
|
|
- persist revoke metadata;
|
|
- publish revoked projection.
|
|
|
|
For `RevokeAllUserSessions`:
|
|
|
|
- list active sessions for user;
|
|
- revoke each relevant session;
|
|
- publish projection for each affected session;
|
|
- preserve reason metadata.
|
|
|
|
For `BlockUser`:
|
|
|
|
- mark user blocked through `UserDirectory` or trusted policy adapter;
|
|
- revoke all active sessions;
|
|
- ensure future auth flow is denied at confirm stage and mail can be suppressed
|
|
at send stage.
|
|
|
|
### Deliverables
|
|
|
|
- complete revoke implementation;
|
|
- tests for single, bulk, and block flows.
|
|
|
|
### Exit Criteria
|
|
|
|
- gateway-facing revoke propagation is available for all revoke models.
|
|
|
|
---
|
|
|
|
## ~~Stage 16.~~ Add Consistency Safeguards
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Reduce create/revoke drift between source of truth and gateway projection.
|
|
|
|
### Tasks
|
|
|
|
- identify all places where source-of-truth write and projection publish happen;
|
|
- add retry strategy for projection writes;
|
|
- make projection publication idempotent;
|
|
- define recovery behavior if projection publish fails after source-of-truth
|
|
success;
|
|
- add dead-letter or repair strategy placeholder if needed later;
|
|
- document the consistency model.
|
|
|
|
### Preferred Short-Term Outcome
|
|
|
|
- source-of-truth success is never reported as auth success unless projection
|
|
write/publish reached the required success threshold, or the failure handling
|
|
policy is explicit and tested.
|
|
|
|
### Deliverables
|
|
|
|
- consistency policy document;
|
|
- tests for partial failure scenarios.
|
|
|
|
### Exit Criteria
|
|
|
|
- known failure windows are explicit and bounded.
|
|
|
|
---
|
|
|
|
## ~~Stage 17.~~ Add Public Anti-Abuse Hooks
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Prepare the auth service for safe interaction behind gateway public routing.
|
|
|
|
### Tasks
|
|
|
|
- add service-level hooks for challenge resend throttling;
|
|
- add max-attempt handling per challenge;
|
|
- add metrics for suppressed/blocked/sent flows;
|
|
- preserve soft anti-enumeration outward behavior.
|
|
|
|
### Notes
|
|
|
|
Gateway already applies public-edge rate limits.
|
|
This stage is about auth-specific flow protection, not replacing gateway limits.
|
|
|
|
### Deliverables
|
|
|
|
- abuse-control policy inside auth domain;
|
|
- tests for throttling and attempt exhaustion.
|
|
|
|
### Exit Criteria
|
|
|
|
- auth flow cannot be trivially abused through repeated confirm attempts.
|
|
|
|
---
|
|
|
|
## ~~Stage 18.~~ Add Observability
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Make the service operable from the beginning.
|
|
|
|
### Tasks
|
|
|
|
- structured logs for all major state transitions;
|
|
- metrics for all major operations;
|
|
- tracing spans for public auth flow and internal API;
|
|
- redact secrets and codes from logs;
|
|
- include stable identifiers such as challenge id, device session id, user id,
|
|
and reason codes where safe.
|
|
|
|
### Minimum Metrics
|
|
|
|
- challenges created;
|
|
- deliveries sent/suppressed/failed;
|
|
- confirm attempts;
|
|
- confirm successes/failures;
|
|
- sessions created;
|
|
- session limit rejections;
|
|
- sessions revoked by reason;
|
|
- projection publish failures;
|
|
- user-resolution outcomes.
|
|
|
|
### Deliverables
|
|
|
|
- metrics endpoint wiring if needed;
|
|
- logging/tracing middleware;
|
|
- observability tests where practical.
|
|
|
|
### Exit Criteria
|
|
|
|
- production debugging is possible without adding ad hoc logs later.
|
|
|
|
---
|
|
|
|
## ~~Stage 19.~~ Add Gateway-Compatibility Tests
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Test auth-service not just in isolation, but against gateway expectations.
|
|
|
|
### Tasks
|
|
|
|
- verify public auth HTTP DTO compatibility;
|
|
- verify `confirm-email-code` returns ready `device_session_id`;
|
|
- verify created session projection is readable by a gateway-compatible reader;
|
|
- verify revoked projection invalidates session;
|
|
- verify repeated confirm returns same session id in idempotency window;
|
|
- verify blocked e-mail still keeps `send_email_code` outwardly success-shaped;
|
|
- verify session limit exceeded returns stable client-visible error;
|
|
- verify malformed `client_public_key` is rejected.
|
|
|
|
### Deliverables
|
|
|
|
- integration test suite focused on gateway contract.
|
|
|
|
### Exit Criteria
|
|
|
|
- no ambiguity remains about integration with existing gateway behavior.
|
|
|
|
---
|
|
|
|
## ~~Stage 20.~~ Add Real REST Adapter to User Service Contract
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Prepare for future extraction of `User Service`.
|
|
|
|
### Tasks
|
|
|
|
- define internal REST client for user resolution/create/block operations;
|
|
- keep stub implementation for tests;
|
|
- add timeout, retry, and error mapping policy;
|
|
- define normalized email rules at the boundary.
|
|
|
|
### Deliverables
|
|
|
|
- REST client adapter for future user-service;
|
|
- compatibility tests using stub server.
|
|
|
|
### Exit Criteria
|
|
|
|
- auth-service can later switch from stub to real user-service with no domain
|
|
rewrite.
|
|
|
|
---
|
|
|
|
## ~~Stage 21.~~ Add Real Mail Adapter Contract
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Prepare for later internal mail-service-backed delivery.
|
|
|
|
### Tasks
|
|
|
|
- define mail adapter request/response contract;
|
|
- preserve current stub for tests;
|
|
- define delivery timeout and error mapping;
|
|
- define how suppression vs explicit failure is represented.
|
|
|
|
### Deliverables
|
|
|
|
- mail adapter interface finalized;
|
|
- optional HTTP client adapter skeleton.
|
|
|
|
### Exit Criteria
|
|
|
|
- auth flow is decoupled from the future mail implementation.
|
|
|
|
---
|
|
|
|
## ~~Stage 22.~~ Production Hardening Pass
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Review edge cases before calling the service implementation complete.
|
|
|
|
### Tasks
|
|
|
|
- test Redis reconnect behavior;
|
|
- test duplicate publish behavior;
|
|
- test crash/restart around confirm and revoke flows;
|
|
- test large numbers of active sessions per user;
|
|
- test concurrent confirms against the same challenge;
|
|
- test concurrent revoke and confirm races;
|
|
- test block-user during active auth flow;
|
|
- test expired challenge cleanup strategy.
|
|
|
|
### Deliverables
|
|
|
|
- hardening checklist;
|
|
- race-condition tests;
|
|
- operational notes.
|
|
|
|
### Exit Criteria
|
|
|
|
- no major known race remains undocumented.
|
|
|
|
---
|
|
|
|
## ~~Stage 23.~~ Optional Cleanup and Migration Readiness
|
|
|
|
Status: implemented.
|
|
|
|
### Goal
|
|
|
|
Make future SQL migration realistic.
|
|
|
|
### Tasks
|
|
|
|
- review whether domain services leak Redis assumptions;
|
|
- ensure all store interfaces are storage-agnostic;
|
|
- isolate key naming, stream naming, and projection serialization;
|
|
- add adapter contract tests reusable by future SQL backends.
|
|
|
|
### Deliverables
|
|
|
|
- backend-agnostic adapter tests;
|
|
- migration readiness notes.
|
|
|
|
### Exit Criteria
|
|
|
|
- a future SQL backend can be added without reworking service-layer logic.
|
|
|
|
---
|
|
|
|
## Recommended First Working Slice
|
|
|
|
If implementation needs an aggressively small first milestone, do this subset
|
|
first:
|
|
|
|
1. domain types
|
|
2. service ports
|
|
3. in-memory service logic
|
|
4. stub `UserDirectory`
|
|
5. stub `MailSender`
|
|
6. public HTTP API
|
|
7. Redis `SessionStore`
|
|
8. Redis `ChallengeStore`
|
|
9. Redis projection publisher
|
|
10. gateway-compatibility tests for:
|
|
- send-email-code
|
|
- confirm-email-code
|
|
- session projection after confirm
|
|
|
|
This gives an end-to-end happy path quickly, without waiting for revoke/admin
|
|
and full hardening.
|
|
|
|
## Recommended Second Slice
|
|
|
|
1. internal trusted API
|
|
2. session-limit config provider
|
|
3. revoke-device
|
|
4. revoke-all
|
|
5. block-user
|
|
6. observability
|
|
7. consistency safeguards
|
|
8. hardening tests
|
|
|
|
## Final Acceptance Criteria
|
|
|
|
The service can be considered implementation-ready when all of the following
|
|
are true:
|
|
|
|
- gateway can call public auth routes synchronously;
|
|
- `confirm-email-code` returns a ready `device_session_id`;
|
|
- the created session appears in gateway-compatible projection storage;
|
|
- revoked sessions publish gateway-compatible revoke updates;
|
|
- repeated successful confirm returns the same session id during the short
|
|
idempotency window;
|
|
- session creation respects dynamic limit config;
|
|
- user block prevents future auth flow and can revoke active sessions;
|
|
- all storage is hidden behind interfaces;
|
|
- auth-service is not required on the authenticated command hot path;
|
|
- logs, metrics, and tests cover the full lifecycle.
|
|
|
|
## Implementation Order Summary
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A["Freeze contracts"]
|
|
B["Domain model"]
|
|
C["Ports"]
|
|
D["In-memory service logic"]
|
|
E["Redis stores"]
|
|
F["Projection publisher"]
|
|
G["Public HTTP API"]
|
|
H["Internal trusted API"]
|
|
I["Revoke and block flows"]
|
|
J["Observability and hardening"]
|
|
K["Gateway compatibility tests"]
|
|
|
|
A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K
|
|
```
|