Skip to content

Commit 5eba851

Browse files
PR prep
1 parent 5513a7f commit 5eba851

10 files changed

Lines changed: 558 additions & 117 deletions

File tree

CLAUDE.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ if (triggerResult is Result<bool, SyncError>.Error<bool, SyncError> triggerErr)
6262

6363
## Architecture Overview
6464

65-
This repository contains multiple related, but distinct suites:
65+
This repository contains four major components:
6666

6767
**DataProvider** - Source generator creating compile-time safe extension methods from SQL files
6868
- Core library in `DataProvider/DataProvider/` - base types, config records, code generation
@@ -77,11 +77,27 @@ This repository contains multiple related, but distinct suites:
7777
- CLI tool: `LqlCli.SQLite/`
7878
- Browser playground: `Lql.Browser/`
7979

80+
**Sync Framework** - Offline-first bidirectional synchronization
81+
- Core engine in `Sync/Sync/` - SyncCoordinator, ConflictResolver, BatchManager
82+
- Database implementations: `Sync.SQLite/`, `Sync.Postgres/`
83+
- HTTP layer: `Sync.Http/` - REST endpoints with SSE subscriptions
84+
- Key components: TriggerGenerator, ChangeApplier, MappingEngine
85+
- Comprehensive tests: `Sync.Tests/`, `Sync.SQLite.Tests/`, `Sync.Postgres.Tests/`
86+
87+
**Gatekeeper** - Authentication and authorization microservice
88+
- API in `Gatekeeper/Gatekeeper.Api/` - WebAuthn passkey auth, RBAC, record-level permissions
89+
- Schema in `Gatekeeper/Gatekeeper.Migration/` - Uses DataProvider migrations
90+
- Key files: `TokenService.cs`, `AuthorizationService.cs`, `Program.cs`
91+
- Tests: `Gatekeeper/Gatekeeper.Api.Tests/`
92+
8093
**Shared Libraries** in `Other/`:
8194
- `Results/` - `Result<TValue, TError>` type for functional error handling
8295
- `Selecta/` - SQL parsing and AST utilities
8396

84-
**Samples**
97+
**Samples** - Healthcare microservices demonstrating the suite
98+
- `Samples/Clinical/` - FHIR-compliant clinical API (Patient, Encounter, Condition)
99+
- `Samples/Scheduling/` - FHIR-compliant scheduling API (Practitioner, Appointment)
100+
- `Samples/Dashboard/` - React/H5 dashboard
85101
- Medical: All medical data MUST conform to the [FHIR spec](https://build.fhir.org/resourcelist.html).
86102

87103
## Project Configuration

Gatekeeper/Gatekeeper.Api/AuthorizationService.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ string now
2424
// Step 1: Check resource-level grants first (most specific)
2525
if (!string.IsNullOrEmpty(resourceType) && !string.IsNullOrEmpty(resourceId))
2626
{
27-
// Generated param order: user_id, resource_id, permission_code, resource_type, now
27+
// Generated param order: user_id, resource_type, resource_id, now, permission_code
2828
var grantResult = await conn.CheckResourceGrantAsync(
2929
userId,
30-
resourceId,
31-
permissionCode,
3230
resourceType,
33-
now
31+
resourceId,
32+
now,
33+
permissionCode
3434
)
3535
.ConfigureAwait(false);
3636

Gatekeeper/README.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# Gatekeeper
2+
3+
An independent authentication and authorization microservice implementing passkey-only authentication (WebAuthn/FIDO2) and fine-grained role-based access control with record-level permissions.
4+
5+
NOTE: There seems to be a mistake here. ABAC was not supposed to be part of this technology but was implemented anyway. We will need to remove this.
6+
7+
## Overview
8+
9+
Gatekeeper provides:
10+
11+
- **Passwordless authentication** - WebAuthn/FIDO2 passkeys only, no passwords
12+
- **Role-based access control (RBAC)** - Hierarchical roles with permission inheritance
13+
- **Record-level permissions** - Fine-grained access to specific resources
14+
- **JWT sessions** - Stateless session management with refresh tokens
15+
- **Framework-agnostic** - REST API for integration with any system
16+
17+
## Projects
18+
19+
| Project | Description |
20+
|---------|-------------|
21+
| `Gatekeeper.Api` | REST API with WebAuthn and authorization endpoints |
22+
| `Gatekeeper.Migration` | Database schema using DataProvider migrations |
23+
| `Gatekeeper.Api.Tests` | Integration tests |
24+
25+
## Getting Started
26+
27+
### Prerequisites
28+
29+
- .NET 9.0 SDK
30+
- SQLite (default) or PostgreSQL
31+
32+
### Run the API
33+
34+
```bash
35+
cd Gatekeeper/Gatekeeper.Api
36+
dotnet run
37+
```
38+
39+
The API starts on `http://localhost:5002`.
40+
41+
### Database Setup
42+
43+
The database is automatically created on first run. To reset:
44+
45+
```bash
46+
rm gatekeeper.db
47+
dotnet run
48+
```
49+
50+
## API Endpoints
51+
52+
### Authentication
53+
54+
| Endpoint | Method | Description |
55+
|----------|--------|-------------|
56+
| `/auth/register/begin` | POST | Start passkey registration |
57+
| `/auth/register/complete` | POST | Complete passkey registration |
58+
| `/auth/login/begin` | POST | Start passkey authentication |
59+
| `/auth/login/complete` | POST | Complete authentication, returns JWT |
60+
| `/auth/logout` | POST | Revoke current session |
61+
| `/auth/session` | GET | Get current session info |
62+
63+
### Authorization
64+
65+
| Endpoint | Method | Description |
66+
|----------|--------|-------------|
67+
| `/authz/check` | GET | Check if user has permission |
68+
| `/authz/permissions` | GET | List user's effective permissions |
69+
| `/authz/evaluate` | POST | Bulk permission check |
70+
71+
### Admin (requires admin role)
72+
73+
| Endpoint | Method | Description |
74+
|----------|--------|-------------|
75+
| `/admin/users` | GET/POST | User management |
76+
| `/admin/roles` | GET/POST | Role management |
77+
| `/admin/permissions` | GET/POST | Permission management |
78+
79+
## Usage Examples
80+
81+
### Register a Passkey
82+
83+
```bash
84+
# 1. Begin registration
85+
curl -X POST http://localhost:5002/auth/register/begin \
86+
-H "Content-Type: application/json" \
87+
-d '{"email": "user@example.com", "displayName": "John Doe"}'
88+
89+
# Response contains WebAuthn options for the browser
90+
# 2. Browser calls navigator.credentials.create() with options
91+
# 3. Complete registration with authenticator response
92+
curl -X POST http://localhost:5002/auth/register/complete \
93+
-H "Content-Type: application/json" \
94+
-d '{"challengeId": "...", "response": {...}}'
95+
```
96+
97+
### Authenticate
98+
99+
```bash
100+
# 1. Begin login
101+
curl -X POST http://localhost:5002/auth/login/begin \
102+
-H "Content-Type: application/json" \
103+
-d '{"email": "user@example.com"}'
104+
105+
# 2. Browser calls navigator.credentials.get() with options
106+
# 3. Complete login
107+
curl -X POST http://localhost:5002/auth/login/complete \
108+
-H "Content-Type: application/json" \
109+
-d '{"challengeId": "...", "response": {...}}'
110+
111+
# Response: {"token": "eyJ...", "expiresAt": "..."}
112+
```
113+
114+
### Check Permission
115+
116+
```bash
117+
curl "http://localhost:5002/authz/check?resource=patient&action=read&resourceId=123" \
118+
-H "Authorization: Bearer eyJ..."
119+
120+
# Response: {"allowed": true, "reason": "Role: physician"}
121+
```
122+
123+
## Database Schema
124+
125+
```
126+
gk_user ──┬── gk_credential (passkeys)
127+
├── gk_session (active sessions)
128+
├── gk_user_role ── gk_role ── gk_role_permission
129+
├── gk_user_permission (direct grants)
130+
└── gk_resource_grant (record-level access)
131+
132+
133+
gk_permission
134+
```
135+
136+
### Key Tables
137+
138+
| Table | Purpose |
139+
|-------|---------|
140+
| `gk_user` | User accounts (id, email, display_name) |
141+
| `gk_credential` | WebAuthn credentials (public_key, sign_count) |
142+
| `gk_session` | Active JWT sessions with revocation |
143+
| `gk_role` | Roles with optional parent hierarchy |
144+
| `gk_permission` | Permissions (resource_type + action) |
145+
| `gk_resource_grant` | Record-level permission grants |
146+
147+
## Permission Model
148+
149+
### RBAC
150+
151+
```
152+
admin (role)
153+
└── user:manage (permission)
154+
└── role:manage (permission)
155+
156+
physician (role)
157+
└── patient:read (permission)
158+
└── patient:write (permission)
159+
```
160+
161+
### Record-Level
162+
163+
```
164+
User "dr.smith" has "patient:read" on Patient "patient-123"
165+
```
166+
167+
## Configuration
168+
169+
Environment variables:
170+
171+
| Variable | Default | Description |
172+
|----------|---------|-------------|
173+
| `JWT_SECRET` | (generated) | Secret for JWT signing |
174+
| `JWT_ISSUER` | `Gatekeeper` | JWT issuer claim |
175+
| `JWT_AUDIENCE` | `GatekeeperClients` | JWT audience claim |
176+
| `JWT_EXPIRY_MINUTES` | `60` | Token expiration |
177+
| `DATABASE_PATH` | `gatekeeper.db` | SQLite database path |
178+
| `WEBAUTHN_RP_ID` | `localhost` | WebAuthn Relying Party ID |
179+
| `WEBAUTHN_RP_NAME` | `Gatekeeper` | WebAuthn Relying Party name |
180+
| `WEBAUTHN_ORIGIN` | `http://localhost:5002` | Expected origin |
181+
182+
## Testing
183+
184+
```bash
185+
# Run all Gatekeeper tests
186+
dotnet test --filter "FullyQualifiedName~Gatekeeper"
187+
188+
# Specific test class
189+
dotnet test --filter "FullyQualifiedName~AuthorizationTests"
190+
```
191+
192+
## Design Principles
193+
194+
Following the repository's coding rules:
195+
196+
- **No exceptions** - Returns `Result<T, GatekeeperError>` types
197+
- **No classes** - Uses records and static methods
198+
- **No interfaces** - Uses `Func<T>` for abstractions
199+
- **Integration tests** - Real database, no mocks
200+
- **DataProvider** - All SQL via generated extension methods
201+
202+
## References
203+
204+
### WebAuthn/FIDO2
205+
- [W3C WebAuthn Specification](https://www.w3.org/TR/webauthn-3/)
206+
- [fido2-net-lib](https://github.com/passwordless-lib/fido2-net-lib)
207+
- [SimpleWebAuthn](https://simplewebauthn.dev/docs/)
208+
209+
### Access Control
210+
- [NocoBase RBAC Guide](https://www.nocobase.com/en/blog/how-to-design-rbac-role-based-access-control-system)
211+
- [Permify Fine-Grained Access](https://permify.co/post/fine-grained-access-control-where-rbac-falls-short/)
212+
213+
## License
214+
215+
See repository root for license information.

0 commit comments

Comments
 (0)