Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/support-auth/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Plain readonly data objects — no interface, no dispatcher dependency. Caller d
| `TokenRevokedException` | extends `AuthenticationException` |
| `UnauthorizedException` | extends `RuntimeException`, NOT `AuthenticationException` |

## CONTRACTS (`jardissupport/contract`)
## CONTRACTS (`jardissupport/contracts`)
| Interface | Methods |
|-----------|---------|
| `TokenStoreInterface` | `store`, `find`, `revoke`, `revokeAllForSubject`, `deleteExpired` — **consumer must implement** |
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Authentication, session management, password hashing, and RBAC — no HTTP layer

- **Strict Orchestrator Pattern:** Four Orchestrators in `src/` root compose themselves from Closures (`src/Handler/{Category}/`) via `->__invoke(...)` binding in the constructor. Orchestrators have **zero business logic** — only delegation.
- **Events are plain readonly data objects** under `src/Data/Event/` (`AuthenticationSucceeded/Failed`, `SessionCreated/Refreshed/Invalidated`, `AllSessionsInvalidated`) — no interface, no Dispatcher. `SessionManager::create()/refresh()` return `SessionResult` with events; `invalidate()/invalidateAll()` return the event directly. The caller dispatches itself.
- **`TokenStoreInterface` must be implemented by the consumer** (from `jardissupport/contract`). No default store in the package — the test fake `InMemoryTokenStore` lives in `tests/Support/`, not in `src/`. `PasswordHasher::argon2id(memoryCost, timeCost, threads)` or `::bcrypt(cost)` as Factory Named Constructors.
- **`TokenStoreInterface` must be implemented by the consumer** (from `jardissupport/contracts`). No default store in the package — the test fake `InMemoryTokenStore` lives in `tests/Support/`, not in `src/`. `PasswordHasher::argon2id(memoryCost, timeCost, threads)` or `::bcrypt(cost)` as Factory Named Constructors.
- **`Guard` against immutable `Policy` via `PolicyBuilder`:** `role()->allow()->deny()->includes()->build()`. Rule semantics: **deny overrides allow**, role inheritance via `includes('editor')`. `check()` returns bool, `authorize()` throws `UnauthorizedException` (extends `RuntimeException`, **not** `AuthenticationException`).
- **Multi-role support:** `$session->getMetadata()['role']` may be `string` or `string[]` — `CheckPermission` iterates the list, **first match wins**. Permission format `"resource:action"` via `Permission::from()` with wildcard support.
- **Public error messages stay generic** (`"Invalid credentials"`), details are only in the events. `AuthenticationResult` implements `AuthResultInterface` — usable as both rich result and contract type. Exception hierarchy: `AuthenticationException` (base) → `InvalidCredential`/`TokenExpired`/`TokenRevoked`; `UnauthorizedException` separate.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ tests/Integration/

## Contracts

Defined in `jardissupport/contract` — implement these in your infrastructure:
Defined in `jardissupport/contracts` — implement these in your infrastructure:

| Interface | Purpose |
|-----------|---------|
Expand Down
Loading