@rineex/auth-core 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Architecture.md +257 -0
- package/CHANGELOG.md +16 -0
- package/Definition.md +1490 -0
- package/Develop.md +0 -0
- package/RULES.md +1470 -0
- package/eslint.config.mjs +58 -0
- package/package.json +22 -20
- package/src/domain/aggregates/authentication-attempt.aggregate.ts +119 -0
- package/src/domain/entities/identity.entity.ts +13 -0
- package/src/domain/events/authentication-failed.event.ts +24 -0
- package/src/domain/events/authentication-started.event.ts +29 -0
- package/src/domain/events/authentication-succeeded.event.ts +24 -0
- package/src/domain/value-objects/auth-attempt-id.vo.ts +19 -0
- package/src/domain/value-objects/auth-method.vo.ts +21 -0
- package/src/domain/value-objects/auth-status.vo.ts +38 -0
- package/src/domain/value-objects/identity-id.vo.ts +22 -0
- package/src/index.ts +1 -0
- package/src/ports/inbound/auth-method.port.ts +18 -0
- package/src/ports/outbound/authentication-attempt.repository.port.ts +11 -0
- package/src/types/auth-context.type.ts +11 -0
- package/tsconfig.build.json +6 -0
- package/tsconfig.json +25 -0
- package/tsup.config.ts +13 -0
- package/vitest.config.ts +12 -0
- package/dist/index.d.mts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -18
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +0 -1
package/Definition.md
ADDED
|
@@ -0,0 +1,1490 @@
|
|
|
1
|
+
## Step 1 — Define **Auth Method SPI (Plugin Contract)**
|
|
2
|
+
|
|
3
|
+
This is the **most critical step**. If this is wrong, everything after becomes
|
|
4
|
+
rigid.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Auth Method SPI — Domain-Level Contract
|
|
9
|
+
|
|
10
|
+
## 1. Goal of This Step
|
|
11
|
+
|
|
12
|
+
Define **how authentication methods plug into the core** without:
|
|
13
|
+
|
|
14
|
+
- Modifying domain logic
|
|
15
|
+
- Adding conditionals (`if password`, `if oauth`)
|
|
16
|
+
- Leaking protocol / provider / infra concerns
|
|
17
|
+
- Forcing storage or transport choices
|
|
18
|
+
|
|
19
|
+
This SPI must support:
|
|
20
|
+
|
|
21
|
+
- Password
|
|
22
|
+
- Passwordless
|
|
23
|
+
- OTP
|
|
24
|
+
- OAuth / OIDC
|
|
25
|
+
- Social login
|
|
26
|
+
- Future methods (passkeys, DID, etc.)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 2. What an Auth Method IS (and is NOT)
|
|
31
|
+
|
|
32
|
+
### ✅ IS
|
|
33
|
+
|
|
34
|
+
- A **capability descriptor**
|
|
35
|
+
- A **set of required inputs**
|
|
36
|
+
- A **type of proof produced**
|
|
37
|
+
- A **participant in a flow**
|
|
38
|
+
|
|
39
|
+
### ❌ IS NOT
|
|
40
|
+
|
|
41
|
+
- A service with business logic
|
|
42
|
+
- A protocol implementation
|
|
43
|
+
- A provider SDK wrapper
|
|
44
|
+
- A controller or handler
|
|
45
|
+
- A persistence concern
|
|
46
|
+
|
|
47
|
+
If logic creeps in here → stop.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. Core Domain Abstractions
|
|
52
|
+
|
|
53
|
+
### 3.1 AuthMethodType (Value Object)
|
|
54
|
+
|
|
55
|
+
Represents **identity**, not behavior.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
AuthMethodType
|
|
59
|
+
- value: string
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Rules:
|
|
63
|
+
|
|
64
|
+
- Stable identifier
|
|
65
|
+
- Configurable
|
|
66
|
+
- No enums hardcoded in domain
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
|
|
70
|
+
- `password`
|
|
71
|
+
- `passwordless_email`
|
|
72
|
+
- `otp_totp`
|
|
73
|
+
- `oauth_oidc`
|
|
74
|
+
- `social_google`
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### 3.2 AuthMethodDefinition (Domain Object)
|
|
79
|
+
|
|
80
|
+
This is the **plugin contract**.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
AuthMethodDefinition
|
|
84
|
+
- type: AuthMethodType
|
|
85
|
+
- supportedFactors: Set<AuthFactorType>
|
|
86
|
+
- requiredInputs: Set<AuthInputType>
|
|
87
|
+
- outputProof: AuthProofType
|
|
88
|
+
- challengeCapable: boolean
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This object:
|
|
92
|
+
|
|
93
|
+
- Is immutable
|
|
94
|
+
- Is registered at startup
|
|
95
|
+
- Contains **no logic**
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 4. Auth Inputs (What the method needs)
|
|
100
|
+
|
|
101
|
+
Auth methods declare **what they need**, not _how it arrives_.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
AuthInputType -
|
|
105
|
+
identifier -
|
|
106
|
+
secret -
|
|
107
|
+
otp -
|
|
108
|
+
assertion -
|
|
109
|
+
authorization_code -
|
|
110
|
+
device_context -
|
|
111
|
+
redirect_context;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Rules:
|
|
115
|
+
|
|
116
|
+
- Transport-agnostic
|
|
117
|
+
- Serializable
|
|
118
|
+
- Validated at boundaries
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 5. Auth Proof (What the method produces)
|
|
123
|
+
|
|
124
|
+
Auth methods **do not authenticate**. They produce **proof**.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
AuthProofType - password_proof - otp_proof - oauth_proof - assertion_proof;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The **domain decides** what to do with the proof.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 6. Verification Responsibility (Important)
|
|
135
|
+
|
|
136
|
+
Auth Methods **do not verify themselves**.
|
|
137
|
+
|
|
138
|
+
Verification is done via **ports**:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
AuthProofVerifierPort
|
|
142
|
+
- verify(proof, context): VerificationResult
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
This allows:
|
|
146
|
+
|
|
147
|
+
- Swapping providers
|
|
148
|
+
- Mocking
|
|
149
|
+
- Enterprise overrides
|
|
150
|
+
- Multiple verification strategies
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 7. Method Registration Model
|
|
155
|
+
|
|
156
|
+
Auth methods are **registered**, not hardcoded.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
AuthMethodRegistry - register(definition) - get(type) - list();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Rules:
|
|
163
|
+
|
|
164
|
+
- Registry is read-only at runtime
|
|
165
|
+
- Domain depends only on interface
|
|
166
|
+
- Infrastructure provides implementations
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 8. Example (Conceptual, Not Implementation)
|
|
171
|
+
|
|
172
|
+
| Method | Inputs | Proof | Factor |
|
|
173
|
+
| ---------- | ------------------- | --------------- | ---------- |
|
|
174
|
+
| Password | identifier + secret | password_proof | knowledge |
|
|
175
|
+
| Magic Link | identifier | assertion_proof | possession |
|
|
176
|
+
| OTP | identifier + otp | otp_proof | possession |
|
|
177
|
+
| OAuth | authorization_code | oauth_proof | delegated |
|
|
178
|
+
| API Token | token | assertion_proof | possession |
|
|
179
|
+
|
|
180
|
+
Notice:
|
|
181
|
+
|
|
182
|
+
- No HTTP
|
|
183
|
+
- No redirects
|
|
184
|
+
- No JWT
|
|
185
|
+
- No providers
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 9. What This Enables
|
|
190
|
+
|
|
191
|
+
With this SPI, you can:
|
|
192
|
+
|
|
193
|
+
- Add a new auth method **without touching domain logic**
|
|
194
|
+
- Compose methods into MFA
|
|
195
|
+
- Enable / disable methods via config
|
|
196
|
+
- Support enterprise overrides
|
|
197
|
+
- Keep core stable for years
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 10. Hard Validation Checklist
|
|
202
|
+
|
|
203
|
+
Before moving forward, confirm:
|
|
204
|
+
|
|
205
|
+
- No logic inside method definitions
|
|
206
|
+
- No branching by method type
|
|
207
|
+
- No enum explosion
|
|
208
|
+
- No provider coupling
|
|
209
|
+
- No storage assumptions
|
|
210
|
+
|
|
211
|
+
If any fails → redesign now.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Step 1 Status
|
|
216
|
+
|
|
217
|
+
✅ Auth Method SPI defined ✅ Extensible ✅ Domain-pure ✅ Hexagonal-safe
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
# Step 2 — Authentication Flow DSL (Orchestration Model)
|
|
222
|
+
|
|
223
|
+
This step defines **how authentication happens**, without:
|
|
224
|
+
|
|
225
|
+
- Hard-coding flows
|
|
226
|
+
- Coupling to methods
|
|
227
|
+
- Assuming HTTP redirects
|
|
228
|
+
- Embedding logic in code paths
|
|
229
|
+
|
|
230
|
+
If flows are not modeled explicitly, you will **never** support enterprise auth
|
|
231
|
+
cleanly.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 1. Purpose of Authentication Flow
|
|
236
|
+
|
|
237
|
+
An **Authentication Flow** answers one question:
|
|
238
|
+
|
|
239
|
+
> _“In what order, under what conditions, and with which rules are auth methods
|
|
240
|
+
> executed?”_
|
|
241
|
+
|
|
242
|
+
It must support:
|
|
243
|
+
|
|
244
|
+
- Single-step auth (password, social)
|
|
245
|
+
- Multi-step auth (OTP, MFA)
|
|
246
|
+
- Conditional auth (risk-based)
|
|
247
|
+
- Enterprise SSO
|
|
248
|
+
- Future orchestration (passkeys, step-up)
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 2. Core Principle (Non-Negotiable)
|
|
253
|
+
|
|
254
|
+
**Flows are data, not code.**
|
|
255
|
+
|
|
256
|
+
No:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
if (method === 'password') { ... }
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Instead:
|
|
263
|
+
|
|
264
|
+
- Declarative steps
|
|
265
|
+
- Explicit transitions
|
|
266
|
+
- Policy-driven decisions
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 3. Flow as a Domain Concept
|
|
271
|
+
|
|
272
|
+
### AuthenticationFlow (Domain Object)
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
AuthenticationFlow
|
|
276
|
+
- flowId
|
|
277
|
+
- name
|
|
278
|
+
- steps: AuthFlowStep[]
|
|
279
|
+
- entryConditions
|
|
280
|
+
- exitConditions
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Rules:
|
|
284
|
+
|
|
285
|
+
- Immutable
|
|
286
|
+
- Versionable
|
|
287
|
+
- Serializable
|
|
288
|
+
- Loaded at startup or via config
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 4. Flow Step Model
|
|
293
|
+
|
|
294
|
+
### AuthFlowStep
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
AuthFlowStep
|
|
298
|
+
- stepId
|
|
299
|
+
- authMethodType
|
|
300
|
+
- required: boolean
|
|
301
|
+
- onSuccess: Transition
|
|
302
|
+
- onFailure: Transition
|
|
303
|
+
- onChallenge?: Transition
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Each step:
|
|
307
|
+
|
|
308
|
+
- Executes **exactly one Auth Method**
|
|
309
|
+
- Produces a proof
|
|
310
|
+
- Does NOT decide success globally
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 5. Transition Model
|
|
315
|
+
|
|
316
|
+
### Transition
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
Transition
|
|
320
|
+
- targetStepId | terminalState
|
|
321
|
+
- condition?: PolicyExpression
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Terminal states:
|
|
325
|
+
|
|
326
|
+
- `AUTHENTICATED`
|
|
327
|
+
- `FAILED`
|
|
328
|
+
- `CHALLENGED`
|
|
329
|
+
|
|
330
|
+
This enables:
|
|
331
|
+
|
|
332
|
+
- Retry
|
|
333
|
+
- Step-up
|
|
334
|
+
- Short-circuiting
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 6. Policy Expressions (Referenced, Not Implemented Yet)
|
|
339
|
+
|
|
340
|
+
Flows do **not** evaluate logic themselves.
|
|
341
|
+
|
|
342
|
+
They reference policies:
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
PolicyExpression - policyId - parameters;
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Examples:
|
|
349
|
+
|
|
350
|
+
- `risk.score > threshold`
|
|
351
|
+
- `principal.trustLevel < required`
|
|
352
|
+
- `device.notTrusted`
|
|
353
|
+
|
|
354
|
+
(Policy language comes in Step 4.)
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## 7. AuthenticationAttempt Lifecycle (Flow-Driven)
|
|
359
|
+
|
|
360
|
+
The flow **drives the attempt**, not the other way around.
|
|
361
|
+
|
|
362
|
+
States:
|
|
363
|
+
|
|
364
|
+
- `Initialized`
|
|
365
|
+
- `InProgress`
|
|
366
|
+
- `AwaitingChallenge`
|
|
367
|
+
- `Succeeded`
|
|
368
|
+
- `Failed`
|
|
369
|
+
|
|
370
|
+
Rules:
|
|
371
|
+
|
|
372
|
+
- One flow per attempt
|
|
373
|
+
- Steps are executed sequentially
|
|
374
|
+
- Proofs are accumulated
|
|
375
|
+
- Finalization happens only at terminal state
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 8. Example Flows (Conceptual)
|
|
380
|
+
|
|
381
|
+
### 8.1 Simple Password Flow
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
Step 1: password
|
|
385
|
+
onSuccess → AUTHENTICATED
|
|
386
|
+
onFailure → FAILED
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
### 8.2 Password + OTP (MFA)
|
|
392
|
+
|
|
393
|
+
```
|
|
394
|
+
Step 1: password
|
|
395
|
+
onSuccess → Step 2
|
|
396
|
+
onFailure → FAILED
|
|
397
|
+
|
|
398
|
+
Step 2: otp
|
|
399
|
+
onSuccess → AUTHENTICATED
|
|
400
|
+
onFailure → FAILED
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
### 8.3 Risk-Based Step-Up
|
|
406
|
+
|
|
407
|
+
```
|
|
408
|
+
Step 1: password
|
|
409
|
+
onSuccess →
|
|
410
|
+
if risk.low → AUTHENTICATED
|
|
411
|
+
if risk.high → Step 2
|
|
412
|
+
|
|
413
|
+
Step 2: otp
|
|
414
|
+
onSuccess → AUTHENTICATED
|
|
415
|
+
onFailure → FAILED
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### 8.4 OAuth / Social Login
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
Step 1: oauth_oidc
|
|
424
|
+
onSuccess → AUTHENTICATED
|
|
425
|
+
onFailure → FAILED
|
|
426
|
+
onChallenge → AWAITING_EXTERNAL_ASSERTION
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
No redirects modeled. That’s infrastructure.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 9. What Flows Explicitly Do NOT Know
|
|
434
|
+
|
|
435
|
+
Flows do **not** know about:
|
|
436
|
+
|
|
437
|
+
- HTTP redirects
|
|
438
|
+
- UI screens
|
|
439
|
+
- Cookies
|
|
440
|
+
- Tokens
|
|
441
|
+
- OAuth providers
|
|
442
|
+
- Mobile vs web
|
|
443
|
+
- DB schemas
|
|
444
|
+
|
|
445
|
+
They only know:
|
|
446
|
+
|
|
447
|
+
- Steps
|
|
448
|
+
- Transitions
|
|
449
|
+
- Policies
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## 10. Extensibility Guarantees
|
|
454
|
+
|
|
455
|
+
With this DSL, you can:
|
|
456
|
+
|
|
457
|
+
- Add new auth methods without new flows
|
|
458
|
+
- Add new flows without code changes
|
|
459
|
+
- Customize enterprise flows via config
|
|
460
|
+
- Reuse flows across products
|
|
461
|
+
- Audit authentication behavior deterministically
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 11. Validation Checklist (Must Pass)
|
|
466
|
+
|
|
467
|
+
Before moving forward:
|
|
468
|
+
|
|
469
|
+
✔ Flow is declarative ✔ No branching by method type ✔ No protocol assumptions ✔
|
|
470
|
+
No infrastructure knowledge ✔ Supports MFA and step-up ✔ Serializable and
|
|
471
|
+
versionable
|
|
472
|
+
|
|
473
|
+
If any fails → redesign.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Step 2 Status
|
|
478
|
+
|
|
479
|
+
✅ Authentication Flow DSL defined ✅ Orchestration decoupled from methods ✅
|
|
480
|
+
Enterprise-ready ✅ Hexagonal-safe
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
# Step 3 — **AuthenticationAttempt Lifecycle (Aggregate Rules)**
|
|
485
|
+
|
|
486
|
+
This step defines **the heart of correctness**. If this aggregate is weak,
|
|
487
|
+
you’ll get replay attacks, broken MFA, and inconsistent auth state.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 1. Purpose of AuthenticationAttempt
|
|
492
|
+
|
|
493
|
+
An **AuthenticationAttempt** represents:
|
|
494
|
+
|
|
495
|
+
> _One and only one execution of an authentication flow._
|
|
496
|
+
|
|
497
|
+
It exists to:
|
|
498
|
+
|
|
499
|
+
- Enforce invariants
|
|
500
|
+
- Track progress across steps
|
|
501
|
+
- Collect proofs
|
|
502
|
+
- Coordinate challenges
|
|
503
|
+
- Produce a single outcome
|
|
504
|
+
|
|
505
|
+
It is the **source of truth** for authentication state.
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 2. Why This Must Be an Aggregate Root
|
|
510
|
+
|
|
511
|
+
Because it controls **critical invariants**:
|
|
512
|
+
|
|
513
|
+
- A step cannot be skipped
|
|
514
|
+
- A proof cannot be reused
|
|
515
|
+
- An attempt cannot succeed twice
|
|
516
|
+
- A failed attempt cannot be resumed
|
|
517
|
+
- MFA ordering must be enforced
|
|
518
|
+
|
|
519
|
+
If this is not an aggregate → bugs are guaranteed.
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## 3. AuthenticationAttempt Structure (Conceptual)
|
|
524
|
+
|
|
525
|
+
**Aggregate Root: AuthenticationAttempt**
|
|
526
|
+
|
|
527
|
+
**Key Attributes**
|
|
528
|
+
|
|
529
|
+
- AttemptId
|
|
530
|
+
- FlowId
|
|
531
|
+
- PrincipalId? (optional initially)
|
|
532
|
+
- CurrentStepId
|
|
533
|
+
- Status
|
|
534
|
+
- CollectedProofs
|
|
535
|
+
- StartedAt
|
|
536
|
+
- CompletedAt?
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## 4. Attempt States (Strict State Machine)
|
|
541
|
+
|
|
542
|
+
Only these states are allowed:
|
|
543
|
+
|
|
544
|
+
1. `Initialized`
|
|
545
|
+
2. `InProgress`
|
|
546
|
+
3. `AwaitingChallenge`
|
|
547
|
+
4. `Succeeded`
|
|
548
|
+
5. `Failed`
|
|
549
|
+
|
|
550
|
+
No others. No “partial success”.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## 5. State Transition Rules (Non-Negotiable)
|
|
555
|
+
|
|
556
|
+
### 5.1 Initialization
|
|
557
|
+
|
|
558
|
+
- Created with a Flow
|
|
559
|
+
- No proofs
|
|
560
|
+
- No session
|
|
561
|
+
- Status = `Initialized`
|
|
562
|
+
|
|
563
|
+
Allowed transitions:
|
|
564
|
+
|
|
565
|
+
- → `InProgress`
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
### 5.2 InProgress
|
|
570
|
+
|
|
571
|
+
- Actively executing a flow step
|
|
572
|
+
- Accepts exactly **one proof per step**
|
|
573
|
+
|
|
574
|
+
Allowed transitions:
|
|
575
|
+
|
|
576
|
+
- → `AwaitingChallenge`
|
|
577
|
+
- → `Succeeded`
|
|
578
|
+
- → `Failed`
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
### 5.3 AwaitingChallenge
|
|
583
|
+
|
|
584
|
+
Used when:
|
|
585
|
+
|
|
586
|
+
- External action is required
|
|
587
|
+
- OTP sent
|
|
588
|
+
- OAuth assertion pending
|
|
589
|
+
- Push approval pending
|
|
590
|
+
|
|
591
|
+
Rules:
|
|
592
|
+
|
|
593
|
+
- No new step allowed
|
|
594
|
+
- Only challenge response accepted
|
|
595
|
+
|
|
596
|
+
Allowed transitions:
|
|
597
|
+
|
|
598
|
+
- → `InProgress`
|
|
599
|
+
- → `Failed`
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
### 5.4 Succeeded (Terminal)
|
|
604
|
+
|
|
605
|
+
Rules:
|
|
606
|
+
|
|
607
|
+
- Immutable
|
|
608
|
+
- Produces AuthenticationSession
|
|
609
|
+
- No further actions allowed
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
### 5.5 Failed (Terminal)
|
|
614
|
+
|
|
615
|
+
Rules:
|
|
616
|
+
|
|
617
|
+
- Immutable
|
|
618
|
+
- No retry inside same attempt
|
|
619
|
+
- New attempt required
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## 6. Proof Handling Rules
|
|
624
|
+
|
|
625
|
+
Proofs are **append-only**.
|
|
626
|
+
|
|
627
|
+
Rules:
|
|
628
|
+
|
|
629
|
+
- One proof per step
|
|
630
|
+
- Proof must match expected AuthMethodType
|
|
631
|
+
- Proof must be verified before progressing
|
|
632
|
+
- Proofs cannot be modified or deleted
|
|
633
|
+
|
|
634
|
+
This guarantees:
|
|
635
|
+
|
|
636
|
+
- Auditability
|
|
637
|
+
- Determinism
|
|
638
|
+
- Replay prevention
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## 7. Step Advancement Rules
|
|
643
|
+
|
|
644
|
+
The aggregate enforces:
|
|
645
|
+
|
|
646
|
+
- Steps must be executed in order
|
|
647
|
+
- Transition conditions must be satisfied
|
|
648
|
+
- Skipping steps is forbidden
|
|
649
|
+
- Optional steps are flow-defined, not attempt-defined
|
|
650
|
+
|
|
651
|
+
The attempt **does not decide** what the next step is. It **asks the flow**.
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## 8. Failure Semantics (Important)
|
|
656
|
+
|
|
657
|
+
Failures are **final**.
|
|
658
|
+
|
|
659
|
+
Examples:
|
|
660
|
+
|
|
661
|
+
- Wrong password → Failed
|
|
662
|
+
- OTP expired → Failed
|
|
663
|
+
- OAuth assertion invalid → Failed
|
|
664
|
+
|
|
665
|
+
Retries:
|
|
666
|
+
|
|
667
|
+
- Require a **new AuthenticationAttempt**
|
|
668
|
+
- Rate limiting is policy/infrastructure concern
|
|
669
|
+
|
|
670
|
+
This avoids:
|
|
671
|
+
|
|
672
|
+
- State confusion
|
|
673
|
+
- Timing attacks
|
|
674
|
+
- Complex rollback logic
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## 9. Relationship to Other Aggregates
|
|
679
|
+
|
|
680
|
+
- Uses **AuthenticationFlow** (read-only)
|
|
681
|
+
- Produces **AuthenticationSession**
|
|
682
|
+
- References **Principal**, but does not own it
|
|
683
|
+
- Uses **Policies**, but does not evaluate them
|
|
684
|
+
|
|
685
|
+
No bidirectional coupling.
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## 10. What AuthenticationAttempt Does NOT Do
|
|
690
|
+
|
|
691
|
+
Explicitly forbidden:
|
|
692
|
+
|
|
693
|
+
- Creating credentials
|
|
694
|
+
- Issuing tokens
|
|
695
|
+
- Storing secrets
|
|
696
|
+
- Evaluating risk
|
|
697
|
+
- Talking to HTTP
|
|
698
|
+
- Calling providers
|
|
699
|
+
|
|
700
|
+
It enforces **process**, not mechanics.
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## 11. Invariant Checklist (Must Always Hold)
|
|
705
|
+
|
|
706
|
+
✔ One flow per attempt ✔ One terminal state only ✔ No step skipping ✔ No proof
|
|
707
|
+
reuse ✔ No resurrection after failure ✔ Deterministic outcome
|
|
708
|
+
|
|
709
|
+
If any invariant breaks → security issue.
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## 12. Step 3 Status
|
|
714
|
+
|
|
715
|
+
✅ Aggregate boundaries defined ✅ State machine enforced ✅ MFA-safe ✅
|
|
716
|
+
Replay-safe ✅ Audit-ready
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
# Step 4 — **Authentication Policy Model (Risk, Conditions, Step-Up)**
|
|
721
|
+
|
|
722
|
+
This step defines **who is allowed to authenticate, under what conditions, and
|
|
723
|
+
with which strength** — without hard-coding logic.
|
|
724
|
+
|
|
725
|
+
If policies are not modeled cleanly, you will:
|
|
726
|
+
|
|
727
|
+
- Hard-code MFA rules
|
|
728
|
+
- Fork enterprise behavior
|
|
729
|
+
- Break extensibility
|
|
730
|
+
- Lose auditability
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## 1. Purpose of Policy in Auth Domain
|
|
735
|
+
|
|
736
|
+
A **Policy** answers questions like:
|
|
737
|
+
|
|
738
|
+
- Is this authentication allowed?
|
|
739
|
+
- Is step-up required?
|
|
740
|
+
- Which flow should apply?
|
|
741
|
+
- Is this context risky?
|
|
742
|
+
- Is the current proof sufficient?
|
|
743
|
+
|
|
744
|
+
Policies **do not authenticate**. They **constrain and steer** authentication.
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
## 2. Core Principle (Non-Negotiable)
|
|
749
|
+
|
|
750
|
+
**Policies are declarative and evaluative — never procedural.**
|
|
751
|
+
|
|
752
|
+
No:
|
|
753
|
+
|
|
754
|
+
```ts
|
|
755
|
+
if (ip === 'x') requireOtp();
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
Yes:
|
|
759
|
+
|
|
760
|
+
- Policy definitions
|
|
761
|
+
- Policy evaluation results
|
|
762
|
+
- Policy-driven decisions
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
## 3. Policy as a First-Class Domain Concept
|
|
767
|
+
|
|
768
|
+
### AuthenticationPolicy (Domain Object)
|
|
769
|
+
|
|
770
|
+
```ts
|
|
771
|
+
AuthenticationPolicy
|
|
772
|
+
- policyId
|
|
773
|
+
- name
|
|
774
|
+
- scope
|
|
775
|
+
- rules: PolicyRule[]
|
|
776
|
+
- effect
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
Rules:
|
|
780
|
+
|
|
781
|
+
- Immutable
|
|
782
|
+
- Versionable
|
|
783
|
+
- Serializable
|
|
784
|
+
- Configurable per tenant / environment
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
## 4. Policy Scope
|
|
789
|
+
|
|
790
|
+
Policies apply at different levels:
|
|
791
|
+
|
|
792
|
+
```ts
|
|
793
|
+
PolicyScope =
|
|
794
|
+
| Global
|
|
795
|
+
| Principal
|
|
796
|
+
| AuthMethod
|
|
797
|
+
| AuthFlow
|
|
798
|
+
| Resource
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
Examples:
|
|
802
|
+
|
|
803
|
+
- Global MFA enforcement
|
|
804
|
+
- Principal-specific restrictions
|
|
805
|
+
- Method-specific constraints
|
|
806
|
+
- Flow selection rules
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
## 5. Policy Rules (Atomic Conditions)
|
|
811
|
+
|
|
812
|
+
### PolicyRule
|
|
813
|
+
|
|
814
|
+
```ts
|
|
815
|
+
PolicyRule
|
|
816
|
+
- condition: ConditionExpression
|
|
817
|
+
- action: PolicyAction
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
Each rule:
|
|
821
|
+
|
|
822
|
+
- Evaluates **one condition**
|
|
823
|
+
- Produces **one action**
|
|
824
|
+
- Has no side effects
|
|
825
|
+
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
## 6. Condition Model (What can be checked)
|
|
829
|
+
|
|
830
|
+
Conditions evaluate **context**, never infrastructure.
|
|
831
|
+
|
|
832
|
+
```ts
|
|
833
|
+
ConditionExpression - subject - operator - value;
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Common Subjects
|
|
837
|
+
|
|
838
|
+
- risk.score
|
|
839
|
+
- principal.trustLevel
|
|
840
|
+
- device.trusted
|
|
841
|
+
- location.country
|
|
842
|
+
- time.window
|
|
843
|
+
- auth.method
|
|
844
|
+
- auth.factor
|
|
845
|
+
- attempt.count
|
|
846
|
+
|
|
847
|
+
### Operators
|
|
848
|
+
|
|
849
|
+
- equals
|
|
850
|
+
- notEquals
|
|
851
|
+
- greaterThan
|
|
852
|
+
- lessThan
|
|
853
|
+
- in
|
|
854
|
+
- notIn
|
|
855
|
+
|
|
856
|
+
---
|
|
857
|
+
|
|
858
|
+
## 7. Policy Actions (What can be enforced)
|
|
859
|
+
|
|
860
|
+
Actions **do not perform authentication**.
|
|
861
|
+
|
|
862
|
+
```ts
|
|
863
|
+
PolicyAction =
|
|
864
|
+
| Allow
|
|
865
|
+
| Deny
|
|
866
|
+
| RequireStepUp
|
|
867
|
+
| SelectFlow
|
|
868
|
+
| LimitTrustLevel
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
Examples:
|
|
872
|
+
|
|
873
|
+
- Require OTP if risk > threshold
|
|
874
|
+
- Deny auth from blocked country
|
|
875
|
+
- Force enterprise SSO
|
|
876
|
+
- Downgrade session trust
|
|
877
|
+
|
|
878
|
+
---
|
|
879
|
+
|
|
880
|
+
## 8. Policy Evaluation Result
|
|
881
|
+
|
|
882
|
+
Policies return **decisions**, not behavior.
|
|
883
|
+
|
|
884
|
+
```ts
|
|
885
|
+
PolicyEvaluationResult
|
|
886
|
+
- decision
|
|
887
|
+
- requiredFlow?
|
|
888
|
+
- requiredAuthFactors?
|
|
889
|
+
- maxTrustLevel?
|
|
890
|
+
- reasons[]
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
This allows:
|
|
894
|
+
|
|
895
|
+
- Explainability
|
|
896
|
+
- Auditing
|
|
897
|
+
- Compliance
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
## 9. Policy Evaluation Responsibility
|
|
902
|
+
|
|
903
|
+
Policies are **evaluated by a Domain Service**, not entities.
|
|
904
|
+
|
|
905
|
+
```ts
|
|
906
|
+
AuthenticationPolicyEvaluator
|
|
907
|
+
- evaluate(context): PolicyEvaluationResult
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
Context includes:
|
|
911
|
+
|
|
912
|
+
- Principal snapshot
|
|
913
|
+
- AuthenticationAttempt snapshot
|
|
914
|
+
- Device/context snapshot
|
|
915
|
+
- Risk assessment (via port)
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## 10. Relationship with Authentication Flow
|
|
920
|
+
|
|
921
|
+
Policies can:
|
|
922
|
+
|
|
923
|
+
- Select a flow
|
|
924
|
+
- Alter transitions
|
|
925
|
+
- Require additional steps
|
|
926
|
+
|
|
927
|
+
Flows **reference policies**, but do not contain logic.
|
|
928
|
+
|
|
929
|
+
This separation allows:
|
|
930
|
+
|
|
931
|
+
- Same flow, different behavior
|
|
932
|
+
- Enterprise overrides
|
|
933
|
+
- Runtime reconfiguration
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
## 11. Example Policies (Conceptual)
|
|
938
|
+
|
|
939
|
+
### 11.1 Risk-Based MFA
|
|
940
|
+
|
|
941
|
+
```
|
|
942
|
+
IF risk.score > 70
|
|
943
|
+
THEN RequireStepUp (otp)
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
---
|
|
947
|
+
|
|
948
|
+
### 11.2 Geo Restriction
|
|
949
|
+
|
|
950
|
+
```
|
|
951
|
+
IF location.country IN blockedCountries
|
|
952
|
+
THEN Deny
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
---
|
|
956
|
+
|
|
957
|
+
### 11.3 Trust Downgrade
|
|
958
|
+
|
|
959
|
+
```
|
|
960
|
+
IF device.trusted = false
|
|
961
|
+
THEN LimitTrustLevel = LOW
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
---
|
|
965
|
+
|
|
966
|
+
### 11.4 Flow Selection
|
|
967
|
+
|
|
968
|
+
```
|
|
969
|
+
IF principal.type = Service
|
|
970
|
+
THEN SelectFlow = m2m_flow
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
---
|
|
974
|
+
|
|
975
|
+
## 12. What Policies Explicitly Do NOT Do
|
|
976
|
+
|
|
977
|
+
Forbidden:
|
|
978
|
+
|
|
979
|
+
- Issuing challenges
|
|
980
|
+
- Sending OTPs
|
|
981
|
+
- Creating sessions
|
|
982
|
+
- Calling providers
|
|
983
|
+
- Accessing databases directly
|
|
984
|
+
- Knowing HTTP headers
|
|
985
|
+
|
|
986
|
+
They only **decide**.
|
|
987
|
+
|
|
988
|
+
---
|
|
989
|
+
|
|
990
|
+
## 13. Extensibility Guarantees
|
|
991
|
+
|
|
992
|
+
With this model you can:
|
|
993
|
+
|
|
994
|
+
- Add new conditions without changing flows
|
|
995
|
+
- Add new actions without breaking domain
|
|
996
|
+
- Support enterprise policy engines later
|
|
997
|
+
- Audit decisions deterministically
|
|
998
|
+
|
|
999
|
+
---
|
|
1000
|
+
|
|
1001
|
+
## 14. Step 4 Status
|
|
1002
|
+
|
|
1003
|
+
✅ Policy model defined ✅ Risk-adaptive ready ✅ Enterprise-grade ✅
|
|
1004
|
+
Explainable and auditable
|
|
1005
|
+
|
|
1006
|
+
---
|
|
1007
|
+
|
|
1008
|
+
# Step 5 — **Credential Lifecycle Modeling**
|
|
1009
|
+
|
|
1010
|
+
This step defines **what a credential is**, how it is created, validated,
|
|
1011
|
+
rotated, revoked, and expired — without storing secrets or coupling to storage.
|
|
1012
|
+
|
|
1013
|
+
If credential lifecycle is vague, security degrades fast.
|
|
1014
|
+
|
|
1015
|
+
---
|
|
1016
|
+
|
|
1017
|
+
## 1. Purpose of Credential in Auth Domain
|
|
1018
|
+
|
|
1019
|
+
A **Credential** represents:
|
|
1020
|
+
|
|
1021
|
+
> _A verifiable authentication capability bound to a Principal._
|
|
1022
|
+
|
|
1023
|
+
It is **not**:
|
|
1024
|
+
|
|
1025
|
+
- A password hash
|
|
1026
|
+
- An OTP secret
|
|
1027
|
+
- A token
|
|
1028
|
+
- A provider artifact
|
|
1029
|
+
|
|
1030
|
+
Those are **infrastructure details**.
|
|
1031
|
+
|
|
1032
|
+
---
|
|
1033
|
+
|
|
1034
|
+
## 2. Credential as a Domain Entity
|
|
1035
|
+
|
|
1036
|
+
### Credential (Entity)
|
|
1037
|
+
|
|
1038
|
+
```ts
|
|
1039
|
+
Credential
|
|
1040
|
+
- CredentialId
|
|
1041
|
+
- PrincipalId
|
|
1042
|
+
- AuthMethodType
|
|
1043
|
+
- AuthFactorType
|
|
1044
|
+
- Status
|
|
1045
|
+
- IssuedAt
|
|
1046
|
+
- ExpiresAt?
|
|
1047
|
+
- LastUsedAt?
|
|
1048
|
+
- Metadata
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
---
|
|
1052
|
+
|
|
1053
|
+
## 3. Credential Status (Finite State)
|
|
1054
|
+
|
|
1055
|
+
```ts
|
|
1056
|
+
CredentialStatus =
|
|
1057
|
+
| Active
|
|
1058
|
+
| Suspended
|
|
1059
|
+
| Revoked
|
|
1060
|
+
| Expired
|
|
1061
|
+
| Compromised
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
Rules:
|
|
1065
|
+
|
|
1066
|
+
- Revoked and Compromised are terminal
|
|
1067
|
+
- Expired is time-based
|
|
1068
|
+
- Suspended is reversible
|
|
1069
|
+
|
|
1070
|
+
---
|
|
1071
|
+
|
|
1072
|
+
## 4. Credential Invariants (Strict)
|
|
1073
|
+
|
|
1074
|
+
A credential must always satisfy:
|
|
1075
|
+
|
|
1076
|
+
- Belongs to exactly one Principal
|
|
1077
|
+
- Is bound to exactly one Auth Method
|
|
1078
|
+
- Cannot be reused across principals
|
|
1079
|
+
- Cannot be reactivated after Revocation
|
|
1080
|
+
- Cannot authenticate if not Active
|
|
1081
|
+
- Cannot exist without lifecycle metadata
|
|
1082
|
+
|
|
1083
|
+
Violation = security bug.
|
|
1084
|
+
|
|
1085
|
+
---
|
|
1086
|
+
|
|
1087
|
+
## 5. Credential Creation Rules
|
|
1088
|
+
|
|
1089
|
+
Credential creation:
|
|
1090
|
+
|
|
1091
|
+
- Is explicit
|
|
1092
|
+
- Requires policy approval
|
|
1093
|
+
- Produces **no secret** in domain
|
|
1094
|
+
- Delegates material generation to infrastructure
|
|
1095
|
+
|
|
1096
|
+
Example:
|
|
1097
|
+
|
|
1098
|
+
- Domain: “Create OTP credential”
|
|
1099
|
+
- Infra: Generates secret, stores it securely
|
|
1100
|
+
|
|
1101
|
+
---
|
|
1102
|
+
|
|
1103
|
+
## 6. Credential Usage Rules
|
|
1104
|
+
|
|
1105
|
+
On each successful authentication:
|
|
1106
|
+
|
|
1107
|
+
- Credential status must be Active
|
|
1108
|
+
- Expiration must be checked
|
|
1109
|
+
- Usage timestamp may be updated
|
|
1110
|
+
- Compromise signals may suspend or revoke
|
|
1111
|
+
|
|
1112
|
+
Credential usage is **observed**, not enforced here.
|
|
1113
|
+
|
|
1114
|
+
---
|
|
1115
|
+
|
|
1116
|
+
## 7. Credential Rotation & Replacement
|
|
1117
|
+
|
|
1118
|
+
Rotation is modeled as:
|
|
1119
|
+
|
|
1120
|
+
- Create new credential
|
|
1121
|
+
- Activate new
|
|
1122
|
+
- Suspend or revoke old
|
|
1123
|
+
|
|
1124
|
+
No mutation-in-place.
|
|
1125
|
+
|
|
1126
|
+
This allows:
|
|
1127
|
+
|
|
1128
|
+
- Auditability
|
|
1129
|
+
- Rollback
|
|
1130
|
+
- Compliance
|
|
1131
|
+
|
|
1132
|
+
---
|
|
1133
|
+
|
|
1134
|
+
## 8. Credential Revocation
|
|
1135
|
+
|
|
1136
|
+
Revocation reasons:
|
|
1137
|
+
|
|
1138
|
+
- User action
|
|
1139
|
+
- Admin action
|
|
1140
|
+
- Policy decision
|
|
1141
|
+
- Risk detection
|
|
1142
|
+
- Breach response
|
|
1143
|
+
|
|
1144
|
+
Revocation:
|
|
1145
|
+
|
|
1146
|
+
- Is immediate
|
|
1147
|
+
- Is irreversible
|
|
1148
|
+
- Must propagate to infra adapters
|
|
1149
|
+
|
|
1150
|
+
---
|
|
1151
|
+
|
|
1152
|
+
## 9. Credential Expiration
|
|
1153
|
+
|
|
1154
|
+
Expiration:
|
|
1155
|
+
|
|
1156
|
+
- Is time-based
|
|
1157
|
+
- Evaluated at authentication time
|
|
1158
|
+
- Does not delete credential
|
|
1159
|
+
- Transitions to Expired
|
|
1160
|
+
|
|
1161
|
+
Deletion is **not** domain responsibility.
|
|
1162
|
+
|
|
1163
|
+
---
|
|
1164
|
+
|
|
1165
|
+
## 10. Relationship to AuthenticationAttempt
|
|
1166
|
+
|
|
1167
|
+
- Attempts **reference** credentials
|
|
1168
|
+
- Attempts do not own credentials
|
|
1169
|
+
- Credential state is checked during verification
|
|
1170
|
+
- No attempt may mutate credential directly
|
|
1171
|
+
|
|
1172
|
+
---
|
|
1173
|
+
|
|
1174
|
+
## 11. Credential Types (Examples)
|
|
1175
|
+
|
|
1176
|
+
| Method | Credential Meaning |
|
|
1177
|
+
| --------- | ---------------------- |
|
|
1178
|
+
| Password | Knowledge credential |
|
|
1179
|
+
| OTP | Possession credential |
|
|
1180
|
+
| OAuth | Delegated credential |
|
|
1181
|
+
| API Token | Possession credential |
|
|
1182
|
+
| Passkey | Possession + inherence |
|
|
1183
|
+
|
|
1184
|
+
Types are **data**, not inheritance.
|
|
1185
|
+
|
|
1186
|
+
---
|
|
1187
|
+
|
|
1188
|
+
## 12. What Credential Does NOT Know
|
|
1189
|
+
|
|
1190
|
+
Explicitly forbidden:
|
|
1191
|
+
|
|
1192
|
+
- Hash algorithms
|
|
1193
|
+
- OTP secrets
|
|
1194
|
+
- Token formats
|
|
1195
|
+
- Storage engines
|
|
1196
|
+
- Providers
|
|
1197
|
+
- Encryption
|
|
1198
|
+
|
|
1199
|
+
Those live behind ports.
|
|
1200
|
+
|
|
1201
|
+
---
|
|
1202
|
+
|
|
1203
|
+
## 13. Ports Related to Credentials
|
|
1204
|
+
|
|
1205
|
+
```ts
|
|
1206
|
+
CredentialRepository;
|
|
1207
|
+
CredentialMaterialStore(infra);
|
|
1208
|
+
CredentialUsageReporter;
|
|
1209
|
+
CredentialRevocationPublisher;
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
Domain only depends on interfaces.
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
## 14. Extensibility Guarantees
|
|
1217
|
+
|
|
1218
|
+
With this model:
|
|
1219
|
+
|
|
1220
|
+
- New credential types require no domain change
|
|
1221
|
+
- Infra can store secrets however it wants
|
|
1222
|
+
- Enterprise policies can control lifecycle
|
|
1223
|
+
- Auditing is deterministic
|
|
1224
|
+
|
|
1225
|
+
---
|
|
1226
|
+
|
|
1227
|
+
## 15. Step 5 Status
|
|
1228
|
+
|
|
1229
|
+
✅ Credential lifecycle defined ✅ Security invariants enforced ✅
|
|
1230
|
+
Storage-agnostic ✅ Enterprise-ready
|
|
1231
|
+
|
|
1232
|
+
---
|
|
1233
|
+
|
|
1234
|
+
We continue. This is the **last foundational domain step**.
|
|
1235
|
+
|
|
1236
|
+
---
|
|
1237
|
+
|
|
1238
|
+
# Step 6 — **AuthenticationSession & Trust Levels**
|
|
1239
|
+
|
|
1240
|
+
This step defines **what “being authenticated” actually means** in your system,
|
|
1241
|
+
independent of tokens, cookies, or transport.
|
|
1242
|
+
|
|
1243
|
+
If this is weak, authorization, SSO, and enterprise security all collapse.
|
|
1244
|
+
|
|
1245
|
+
---
|
|
1246
|
+
|
|
1247
|
+
## 1. Purpose of AuthenticationSession
|
|
1248
|
+
|
|
1249
|
+
An **AuthenticationSession** represents:
|
|
1250
|
+
|
|
1251
|
+
> _A time-bounded, trust-scoped result of a successful authentication._
|
|
1252
|
+
|
|
1253
|
+
It is:
|
|
1254
|
+
|
|
1255
|
+
- The output of Authentication
|
|
1256
|
+
- The input to Authorization
|
|
1257
|
+
- The anchor for SSO, re-auth, and step-up
|
|
1258
|
+
|
|
1259
|
+
It is **not**:
|
|
1260
|
+
|
|
1261
|
+
- A cookie
|
|
1262
|
+
- A JWT
|
|
1263
|
+
- A refresh token
|
|
1264
|
+
- An HTTP session
|
|
1265
|
+
|
|
1266
|
+
Those are representations.
|
|
1267
|
+
|
|
1268
|
+
---
|
|
1269
|
+
|
|
1270
|
+
## 2. AuthenticationSession as Aggregate Root
|
|
1271
|
+
|
|
1272
|
+
### AuthenticationSession (Aggregate Root)
|
|
1273
|
+
|
|
1274
|
+
```ts
|
|
1275
|
+
AuthenticationSession -
|
|
1276
|
+
SessionId -
|
|
1277
|
+
PrincipalId -
|
|
1278
|
+
FlowId -
|
|
1279
|
+
IssuedAt -
|
|
1280
|
+
ExpiresAt -
|
|
1281
|
+
TrustLevel -
|
|
1282
|
+
AuthFactorsUsed -
|
|
1283
|
+
ContextSnapshot -
|
|
1284
|
+
Status;
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
---
|
|
1288
|
+
|
|
1289
|
+
## 3. Session Status (Finite State)
|
|
1290
|
+
|
|
1291
|
+
```ts
|
|
1292
|
+
SessionStatus =
|
|
1293
|
+
| Active
|
|
1294
|
+
| Expired
|
|
1295
|
+
| Revoked
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
Rules:
|
|
1299
|
+
|
|
1300
|
+
- Expired is time-based
|
|
1301
|
+
- Revoked is explicit and terminal
|
|
1302
|
+
- Active is the only usable state
|
|
1303
|
+
|
|
1304
|
+
---
|
|
1305
|
+
|
|
1306
|
+
## 4. Trust Level (Critical Concept)
|
|
1307
|
+
|
|
1308
|
+
### TrustLevel (Value Object)
|
|
1309
|
+
|
|
1310
|
+
Trust is **not binary**.
|
|
1311
|
+
|
|
1312
|
+
```ts
|
|
1313
|
+
TrustLevel =
|
|
1314
|
+
| Anonymous
|
|
1315
|
+
| Low
|
|
1316
|
+
| Medium
|
|
1317
|
+
| High
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
Interpretation:
|
|
1321
|
+
|
|
1322
|
+
- **Anonymous** → unauthenticated
|
|
1323
|
+
- **Low** → weak auth (magic link, social)
|
|
1324
|
+
- **Medium** → single strong factor
|
|
1325
|
+
- **High** → MFA / hardware-backed
|
|
1326
|
+
|
|
1327
|
+
Trust is:
|
|
1328
|
+
|
|
1329
|
+
- Computed from proofs + policies
|
|
1330
|
+
- Stored in session
|
|
1331
|
+
- Used by authorization
|
|
1332
|
+
|
|
1333
|
+
---
|
|
1334
|
+
|
|
1335
|
+
## 5. Trust Level Invariants
|
|
1336
|
+
|
|
1337
|
+
- TrustLevel is **assigned at session creation**
|
|
1338
|
+
- TrustLevel can be **downgraded**
|
|
1339
|
+
- TrustLevel can **never be upgraded in-place**
|
|
1340
|
+
- Upgrade requires **new AuthenticationAttempt**
|
|
1341
|
+
|
|
1342
|
+
This prevents silent privilege escalation.
|
|
1343
|
+
|
|
1344
|
+
---
|
|
1345
|
+
|
|
1346
|
+
## 6. Relationship to AuthenticationAttempt
|
|
1347
|
+
|
|
1348
|
+
- Exactly one session per successful attempt
|
|
1349
|
+
- Attempt produces session
|
|
1350
|
+
- Session references attempt context (read-only)
|
|
1351
|
+
- Session lifecycle is independent afterward
|
|
1352
|
+
|
|
1353
|
+
No circular dependency.
|
|
1354
|
+
|
|
1355
|
+
---
|
|
1356
|
+
|
|
1357
|
+
## 7. Context Snapshot (Why It Exists)
|
|
1358
|
+
|
|
1359
|
+
### ContextSnapshot (Value Object)
|
|
1360
|
+
|
|
1361
|
+
Captures authentication context **at time of issuance**:
|
|
1362
|
+
|
|
1363
|
+
- Device trust
|
|
1364
|
+
- Location
|
|
1365
|
+
- Risk score
|
|
1366
|
+
- Auth methods used
|
|
1367
|
+
- Policies applied
|
|
1368
|
+
|
|
1369
|
+
Why:
|
|
1370
|
+
|
|
1371
|
+
- Auditability
|
|
1372
|
+
- Compliance
|
|
1373
|
+
- Forensic analysis
|
|
1374
|
+
- Future policy checks
|
|
1375
|
+
|
|
1376
|
+
Context is **immutable**.
|
|
1377
|
+
|
|
1378
|
+
---
|
|
1379
|
+
|
|
1380
|
+
## 8. Session Expiration Rules
|
|
1381
|
+
|
|
1382
|
+
Expiration is:
|
|
1383
|
+
|
|
1384
|
+
- Deterministic
|
|
1385
|
+
- Policy-driven
|
|
1386
|
+
- Evaluated by infrastructure
|
|
1387
|
+
- Reflected in domain state
|
|
1388
|
+
|
|
1389
|
+
Domain does not:
|
|
1390
|
+
|
|
1391
|
+
- Refresh sessions
|
|
1392
|
+
- Slide expiration
|
|
1393
|
+
- Issue refresh tokens
|
|
1394
|
+
|
|
1395
|
+
Those are adapters.
|
|
1396
|
+
|
|
1397
|
+
---
|
|
1398
|
+
|
|
1399
|
+
## 9. Session Revocation
|
|
1400
|
+
|
|
1401
|
+
Revocation triggers:
|
|
1402
|
+
|
|
1403
|
+
- User logout
|
|
1404
|
+
- Admin action
|
|
1405
|
+
- Credential revocation
|
|
1406
|
+
- Risk detection
|
|
1407
|
+
- Policy violation
|
|
1408
|
+
|
|
1409
|
+
Revocation:
|
|
1410
|
+
|
|
1411
|
+
- Is explicit
|
|
1412
|
+
- Is immediate
|
|
1413
|
+
- Invalidates all representations
|
|
1414
|
+
|
|
1415
|
+
---
|
|
1416
|
+
|
|
1417
|
+
## 10. SSO Compatibility (Important)
|
|
1418
|
+
|
|
1419
|
+
SSO is simply:
|
|
1420
|
+
|
|
1421
|
+
- Multiple representations
|
|
1422
|
+
- One AuthenticationSession
|
|
1423
|
+
|
|
1424
|
+
This model supports:
|
|
1425
|
+
|
|
1426
|
+
- Web SSO
|
|
1427
|
+
- Mobile SSO
|
|
1428
|
+
- API SSO
|
|
1429
|
+
- Cross-app SSO
|
|
1430
|
+
|
|
1431
|
+
Without special logic.
|
|
1432
|
+
|
|
1433
|
+
---
|
|
1434
|
+
|
|
1435
|
+
## 11. What AuthenticationSession Does NOT Know
|
|
1436
|
+
|
|
1437
|
+
Explicitly forbidden:
|
|
1438
|
+
|
|
1439
|
+
- JWT claims
|
|
1440
|
+
- Cookies
|
|
1441
|
+
- Headers
|
|
1442
|
+
- OAuth tokens
|
|
1443
|
+
- HTTP
|
|
1444
|
+
- Storage engine
|
|
1445
|
+
|
|
1446
|
+
It only knows **meaning**, not format.
|
|
1447
|
+
|
|
1448
|
+
---
|
|
1449
|
+
|
|
1450
|
+
## 12. Ports Related to Sessions
|
|
1451
|
+
|
|
1452
|
+
```ts
|
|
1453
|
+
AuthenticationSessionRepository;
|
|
1454
|
+
SessionRevocationPublisher;
|
|
1455
|
+
SessionExpirationScheduler;
|
|
1456
|
+
SessionRepresentationFactory(infra);
|
|
1457
|
+
```
|
|
1458
|
+
|
|
1459
|
+
Domain defines contracts only.
|
|
1460
|
+
|
|
1461
|
+
---
|
|
1462
|
+
|
|
1463
|
+
## 13. Extensibility Guarantees
|
|
1464
|
+
|
|
1465
|
+
With this model:
|
|
1466
|
+
|
|
1467
|
+
- You can change token formats freely
|
|
1468
|
+
- You can support SSO without refactor
|
|
1469
|
+
- You can add step-up auth cleanly
|
|
1470
|
+
- You can audit auth decisions years later
|
|
1471
|
+
|
|
1472
|
+
---
|
|
1473
|
+
|
|
1474
|
+
## 14. Step 6 Status
|
|
1475
|
+
|
|
1476
|
+
✅ AuthenticationSession modeled ✅ Trust levels explicit ✅ Step-up safe ✅
|
|
1477
|
+
Authorization-ready ✅ Enterprise-grade
|
|
1478
|
+
|
|
1479
|
+
---
|
|
1480
|
+
|
|
1481
|
+
# 🎯 Foundation Complete
|
|
1482
|
+
|
|
1483
|
+
You now have a **complete, extensible, production-grade Auth Domain**:
|
|
1484
|
+
|
|
1485
|
+
1. Auth Method SPI
|
|
1486
|
+
2. Authentication Flow DSL
|
|
1487
|
+
3. AuthenticationAttempt lifecycle
|
|
1488
|
+
4. Policy model
|
|
1489
|
+
5. Credential lifecycle
|
|
1490
|
+
6. AuthenticationSession & Trust
|