Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_017ic4b4VQVEJWetTT1dYzyJ
42 lines
2.0 KiB
Plaintext
42 lines
2.0 KiB
Plaintext
# JWT -> filter -> TenantContext -> @TenantId, real HTTP against the discriminator application
|
|
|
|
== the filter: who gets in
|
|
-- no Authorization header
|
|
GET /invoices -> HTTP 401 {"error":"missing bearer token"}
|
|
-- garbage token
|
|
GET /invoices -> HTTP 401 {"error":"invalid token"}
|
|
-- token signed with a different secret
|
|
GET /invoices -> HTTP 401 {"error":"invalid token"}
|
|
-- expired token (exp = 10 minutes ago)
|
|
GET /invoices -> HTTP 401 {"error":"invalid token"}
|
|
-- valid signature, no tenant_id claim
|
|
GET /invoices -> HTTP 403 {"error":"token carries no valid tenant"}
|
|
-- valid signature, tenant_id = "x; drop schema public cascade"
|
|
GET /invoices -> HTTP 403 {"error":"token carries no valid tenant"}
|
|
-- valid signature, tenant_id = "public" (reserved name)
|
|
GET /invoices -> HTTP 403 {"error":"token carries no valid tenant"}
|
|
|
|
== two tenants, same URL, different data
|
|
-- acme creates INV-1
|
|
POST /invoices -> HTTP 201 {"id":1,"number":"INV-1","amount":100.00,"tenant":"acme"}
|
|
-- acme creates INV-2
|
|
POST /invoices -> HTTP 201 {"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}
|
|
-- globex creates INV-9
|
|
POST /invoices -> HTTP 201 {"id":3,"number":"INV-9","amount":999.00,"tenant":"globex"}
|
|
-- acme lists
|
|
GET /invoices -> HTTP 200 [{"id":1,"number":"INV-1","amount":100.00,"tenant":"acme"},{"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}]
|
|
-- globex lists
|
|
GET /invoices -> HTTP 200 [{"id":3,"number":"INV-9","amount":999.00,"tenant":"globex"}]
|
|
|
|
== cross-tenant read by id
|
|
-- globex asks for acme's INV-2 by id (2)
|
|
GET /invoices/2 -> HTTP 404
|
|
-- acme asks for the same id
|
|
GET /invoices/2 -> HTTP 200 {"id":2,"number":"INV-2","amount":250.00,"tenant":"acme"}
|
|
|
|
== a well-formed tenant nobody has onboarded
|
|
-- token for tenant "ghostco": GET /invoices
|
|
GET /invoices -> HTTP 200 []
|
|
-- token for tenant "ghostco": POST /invoices
|
|
POST /invoices -> HTTP 201 {"id":4,"number":"INV-G","amount":1.00,"tenant":"ghostco"}
|