rcf-lite 0.12.0 → 0.13.0
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/CHANGELOG.md +11 -0
- package/README.md +2 -0
- package/bin/view-supervisor-child.mjs +0 -0
- package/blueprints/application-api-rest/README.md +40 -0
- package/blueprints/application-api-rest/assets/middleware/auth-classes.md +45 -0
- package/blueprints/application-api-rest/assets/openapi/openapi-skeleton.yaml +322 -0
- package/blueprints/application-api-rest/assets/sample-data/sample-resources.json +53 -0
- package/blueprints/application-api-rest/assets/samples/request-response-pairs.md +204 -0
- package/blueprints/application-api-rest/blueprint.json +265 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-301-application-api-rest-error-envelope.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-303-application-api-rest-api-versioning.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-304-application-api-rest-logging.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-305-application-api-rest-pagination.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-306-application-api-rest-idempotency.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-307-application-api-rest-openapi-generation.json +25 -0
- package/blueprints/application-api-rest/contributions/adrs/adr-308-application-api-rest-rate-limiting.json +25 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-001.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-002.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-003.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-004.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-005.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-007.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-008.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-009.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-010.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-011.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-012.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-013.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-014.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-015.json +18 -0
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-016.json +18 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-301-application-api-rest-request-pipeline.json +48 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-302-application-api-rest-auth-middleware.json +41 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-303-application-api-rest-contract-surface.json +46 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-304-application-api-rest-resource-layer.json +46 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-305-application-api-rest-observability.json +40 -0
- package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +46 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2101.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2102.json +73 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2104.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2105.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2106.json +73 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2107.json +90 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +90 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2109.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2110.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2111.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2112.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2113.json +73 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2114.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2115.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2116.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2117.json +64 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2118.json +72 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2119.json +63 -0
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2120.json +73 -0
- package/blueprints/application-api-rest/docs/topics.md +46 -0
- package/blueprints/application-api-rest/guide/application-api-rest.md +41 -0
- package/blueprints/application-spa/README.md +90 -0
- package/blueprints/application-spa/assets/component-specs/actions-and-text-inputs.md +36 -0
- package/blueprints/application-spa/assets/component-specs/data-display.md +19 -0
- package/blueprints/application-spa/assets/component-specs/feedback-and-status.md +27 -0
- package/blueprints/application-spa/assets/component-specs/overlays.md +23 -0
- package/blueprints/application-spa/assets/component-specs/selection-controls.md +23 -0
- package/blueprints/application-spa/assets/sample-data/sample-entities.json +41 -0
- package/blueprints/application-spa/assets/tokens/design-tokens.json +140 -0
- package/blueprints/application-spa/assets/tokens/theme.css +169 -0
- package/blueprints/application-spa/assets/viewports.md +18 -0
- package/blueprints/application-spa/assets/wireframes/dashboard.md +48 -0
- package/blueprints/application-spa/assets/wireframes/detail.md +40 -0
- package/blueprints/application-spa/assets/wireframes/empty.md +31 -0
- package/blueprints/application-spa/assets/wireframes/error.md +46 -0
- package/blueprints/application-spa/assets/wireframes/form.md +50 -0
- package/blueprints/application-spa/assets/wireframes/list.md +45 -0
- package/blueprints/application-spa/assets/wireframes/session-expired.md +35 -0
- package/blueprints/application-spa/assets/wireframes/sign-in.md +41 -0
- package/blueprints/application-spa/assets/wireframes/sign-out.md +32 -0
- package/blueprints/application-spa/blueprint.json +387 -0
- package/blueprints/application-spa/contributions/adrs/adr-201-application-spa-routing.json +25 -0
- package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +25 -0
- package/blueprints/application-spa/contributions/adrs/adr-203-application-spa-client-state.json +25 -0
- package/blueprints/application-spa/contributions/adrs/adr-204-application-spa-error-envelope.json +25 -0
- package/blueprints/application-spa/contributions/adrs/adr-205-application-spa-auth-model.json +25 -0
- package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +13 -0
- package/blueprints/application-spa/contributions/adrs/adr-207-application-spa-motion.json +13 -0
- package/blueprints/application-spa/contributions/adrs/adr-208-application-spa-i18n.json +13 -0
- package/blueprints/application-spa/contributions/adrs/adr-209-application-spa-telemetry-naming.json +13 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-001.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-002.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-003.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-004.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-005.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-006.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-007.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-008.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-009.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-010.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-011.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-012.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-013.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-014.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-015.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-016.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-017.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-018.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-019.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-020.json +18 -0
- package/blueprints/application-spa/contributions/requirements/application-spa-req-021.json +18 -0
- package/blueprints/application-spa/contributions/tacs/tac-201-application-spa-app-shell.json +45 -0
- package/blueprints/application-spa/contributions/tacs/tac-202-application-spa-theme-system.json +32 -0
- package/blueprints/application-spa/contributions/tacs/tac-203-application-spa-component-library.json +32 -0
- package/blueprints/application-spa/contributions/tacs/tac-204-application-spa-client-data-layer.json +27 -0
- package/blueprints/application-spa/contributions/tacs/tac-205-application-spa-forms-engine.json +27 -0
- package/blueprints/application-spa/contributions/tacs/tac-206-application-spa-telemetry.json +19 -0
- package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +57 -0
- package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +56 -0
- package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +61 -0
- package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +70 -0
- package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +70 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1101.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1102.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1103.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1104.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1105.json +69 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1106.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1107.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1108.json +90 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1109.json +90 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1110.json +100 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1111.json +90 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1112.json +81 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1113.json +82 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1114.json +60 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1115.json +73 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1116.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1117.json +73 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1118.json +54 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1119.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1120.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1121.json +73 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1122.json +69 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1123.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1124.json +60 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1125.json +69 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1126.json +78 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1127.json +63 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1128.json +51 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1129.json +54 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1130.json +54 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1132.json +72 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1133.json +72 -0
- package/blueprints/application-spa/docs/topics.md +57 -0
- package/blueprints/application-spa/guide/application-spa.md +40 -0
- package/blueprints/ci-pipeline/README.md +49 -0
- package/blueprints/ci-pipeline/assets/ci-provider-examples/github-actions.yml +61 -0
- package/blueprints/ci-pipeline/assets/ci-provider-examples/notes.md +50 -0
- package/blueprints/ci-pipeline/assets/report-samples/per-gate.json +12 -0
- package/blueprints/ci-pipeline/assets/report-samples/pipeline.json +28 -0
- package/blueprints/ci-pipeline/blueprint.json +46 -0
- package/blueprints/ci-pipeline/contributions/adrs/adr-701-ci-pipeline-ci-gates.json +25 -0
- package/blueprints/ci-pipeline/contributions/adrs/adr-702-ci-pipeline-strict-coverage-gate.json +25 -0
- package/blueprints/ci-pipeline/contributions/adrs/adr-703-ci-pipeline-node-only-runner.json +25 -0
- package/blueprints/ci-pipeline/contributions/adrs/adr-704-ci-pipeline-report-shape.json +25 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-001.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-002.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-003.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-004.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-005.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-006.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-007.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-008.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-009.json +18 -0
- package/blueprints/ci-pipeline/contributions/requirements/ci-pipeline-req-010.json +18 -0
- package/blueprints/ci-pipeline/contributions/tacs/tac-701-ci-pipeline-gate-runner.json +59 -0
- package/blueprints/ci-pipeline/contributions/tacs/tac-702-ci-pipeline-gate-report.json +32 -0
- package/blueprints/ci-pipeline/contributions/tacs/tac-703-ci-pipeline-aggregate-report.json +41 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6101.json +37 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6102.json +36 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6103.json +37 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6104.json +37 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6105.json +36 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6106.json +36 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6107.json +37 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6108.json +37 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6109.json +36 -0
- package/blueprints/ci-pipeline/contributions/user-stories/ci-pipeline-us-6110.json +36 -0
- package/blueprints/ci-pipeline/docs/topics.md +49 -0
- package/blueprints/ci-pipeline/guide/ci-pipeline.md +79 -0
- package/blueprints/deploy-cloudflare-workers/README.md +63 -0
- package/blueprints/deploy-cloudflare-workers/assets/ci-workflows/build-and-upload.yml.md +109 -0
- package/blueprints/deploy-cloudflare-workers/assets/ci-workflows/promote.yml.md +120 -0
- package/blueprints/deploy-cloudflare-workers/assets/verification/served-surface-probes.md +90 -0
- package/blueprints/deploy-cloudflare-workers/assets/wrangler-samples/bootstrap-vs-steady-state.md +87 -0
- package/blueprints/deploy-cloudflare-workers/assets/wrangler-samples/preview-alias-shape.md +86 -0
- package/blueprints/deploy-cloudflare-workers/assets/wrangler-samples/wrangler-toml-shape.md +85 -0
- package/blueprints/deploy-cloudflare-workers/blueprint.json +48 -0
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1301-deploy-cloudflare-workers-deployment-target.json +30 -0
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1302-deploy-cloudflare-workers-default-vendor.json +35 -0
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1303-deploy-cloudflare-workers-preview-vs-production.json +30 -0
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1304-deploy-cloudflare-workers-rollback-is-promote.json +25 -0
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1305-deploy-cloudflare-workers-dev-mode-drift.json +25 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-001.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-002.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-003.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-004.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-005.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-006.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-007.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-008.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-009.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-010.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-011.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/requirements/deploy-cloudflare-workers-req-012.json +18 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1301-deploy-cloudflare-workers-deploy-adapter.json +54 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1302-deploy-cloudflare-workers-wrangler-manifest.json +45 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1303-deploy-cloudflare-workers-preview-url-resolver.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1304-deploy-cloudflare-workers-promote-gate.json +57 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1305-deploy-cloudflare-workers-served-surface-verifier.json +51 -0
- package/blueprints/deploy-cloudflare-workers/contributions/tacs/tac-1306-deploy-cloudflare-workers-deploy-ci-workflows.json +64 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12101.json +54 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12102.json +45 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12103.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12104.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12105.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12106.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12107.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12108.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12109.json +47 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12110.json +46 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12111.json +45 -0
- package/blueprints/deploy-cloudflare-workers/contributions/user-stories/deploy-cloudflare-workers-us-12112.json +46 -0
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +46 -0
- package/blueprints/deploy-cloudflare-workers/guide/deploy-cloudflare-workers.md +74 -0
- package/blueprints/email-smtp-resend/README.md +45 -0
- package/blueprints/email-smtp-resend/assets/from-address-rotation-pattern.md +44 -0
- package/blueprints/email-smtp-resend/assets/resend-verification-pointer.md +25 -0
- package/blueprints/email-smtp-resend/assets/stub-adapter.md +65 -0
- package/blueprints/email-smtp-resend/blueprint.json +23 -0
- package/blueprints/email-smtp-resend/contributions/adrs/adr-401-email-smtp-resend-transport-choice.json +30 -0
- package/blueprints/email-smtp-resend/contributions/adrs/adr-402-email-smtp-resend-retry-and-backoff-posture.json +30 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-001.json +18 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-002.json +18 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-003.json +18 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-004.json +18 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-005.json +18 -0
- package/blueprints/email-smtp-resend/contributions/requirements/email-smtp-resend-req-006.json +18 -0
- package/blueprints/email-smtp-resend/contributions/tacs/tac-401-email-smtp-resend-send-adapter.json +53 -0
- package/blueprints/email-smtp-resend/contributions/tacs/tac-402-email-smtp-resend-webhook-verifier.json +56 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4101.json +45 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4102.json +36 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4103.json +45 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4104.json +45 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4105.json +36 -0
- package/blueprints/email-smtp-resend/contributions/user-stories/email-smtp-resend-us-4106.json +37 -0
- package/blueprints/email-smtp-resend/docs/topics.md +44 -0
- package/blueprints/email-smtp-resend/guide/email-smtp-resend.md +71 -0
- package/blueprints/observability-essentials/README.md +53 -0
- package/blueprints/observability-essentials/assets/probe-samples/liveness-body.json +4 -0
- package/blueprints/observability-essentials/assets/probe-samples/readiness-body.json +18 -0
- package/blueprints/observability-essentials/assets/status-page-samples/status-page-clean.html +22 -0
- package/blueprints/observability-essentials/assets/status-page-samples/status-page-with-notice.html +25 -0
- package/blueprints/observability-essentials/blueprint.json +54 -0
- package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +30 -0
- package/blueprints/observability-essentials/contributions/adrs/adr-802-observability-essentials-readiness-semantics.json +30 -0
- package/blueprints/observability-essentials/contributions/adrs/adr-803-observability-essentials-status-page-contract.json +30 -0
- package/blueprints/observability-essentials/contributions/adrs/adr-804-observability-essentials-probe-secrecy.json +25 -0
- package/blueprints/observability-essentials/contributions/adrs/adr-805-observability-essentials-notification-outcome-model.json +25 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-003.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-004.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-005.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-006.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-007.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-008.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-009.json +18 -0
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-010.json +18 -0
- package/blueprints/observability-essentials/contributions/tacs/tac-801-observability-essentials-liveness-probe.json +32 -0
- package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +43 -0
- package/blueprints/observability-essentials/contributions/tacs/tac-803-observability-essentials-status-page.json +37 -0
- package/blueprints/observability-essentials/contributions/tacs/tac-804-observability-essentials-notification-outcome.json +42 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7103.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7104.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7105.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7106.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7107.json +46 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7108.json +47 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7109.json +45 -0
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7110.json +46 -0
- package/blueprints/observability-essentials/docs/topics.md +57 -0
- package/blueprints/observability-essentials/guide/observability-essentials.md +68 -0
- package/blueprints/observability-probe-endpoints/README.md +53 -0
- package/blueprints/observability-probe-endpoints/assets/docker/dockerfile-healthcheck.md +19 -0
- package/blueprints/observability-probe-endpoints/assets/kubernetes/podspec-probes-separate-port.md +54 -0
- package/blueprints/observability-probe-endpoints/assets/kubernetes/podspec-probes.md +36 -0
- package/blueprints/observability-probe-endpoints/assets/load-balancer/health-check-config.md +23 -0
- package/blueprints/observability-probe-endpoints/assets/systemd/notify-service.md +30 -0
- package/blueprints/observability-probe-endpoints/assets/uptime-monitor/monitor-config.md +22 -0
- package/blueprints/observability-probe-endpoints/blueprint.json +44 -0
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1501-observability-probe-endpoints-health-probes.json +30 -0
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1502-observability-probe-endpoints-readiness-semantics.json +30 -0
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1503-observability-probe-endpoints-kubernetes-default.json +30 -0
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1504-observability-probe-endpoints-separate-port-option.json +30 -0
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1505-observability-probe-endpoints-external-response-secrecy.json +30 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-001.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-002.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-003.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-004.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-005.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-006.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-007.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/requirements/observability-probe-endpoints-req-008.json +18 -0
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1501-observability-probe-endpoints-profile-resolver.json +39 -0
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1502-observability-probe-endpoints-handler-set.json +40 -0
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1503-observability-probe-endpoints-listener-topology.json +51 -0
- package/blueprints/observability-probe-endpoints/contributions/tacs/tac-1504-observability-probe-endpoints-non-http-adapters.json +39 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14101.json +46 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +46 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14103.json +46 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14104.json +45 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14105.json +46 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14106.json +45 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +45 -0
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14108.json +46 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +51 -0
- package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +83 -0
- package/blueprints/persistence-data-d1/README.md +50 -0
- package/blueprints/persistence-data-d1/assets/batch-usage/batch-atomicity-example.md +72 -0
- package/blueprints/persistence-data-d1/assets/facade-shape/facade-module-shape.md +115 -0
- package/blueprints/persistence-data-d1/assets/migration-shape/migration-file-shape.md +119 -0
- package/blueprints/persistence-data-d1/assets/wrangler-config/d1-binding-shape.md +93 -0
- package/blueprints/persistence-data-d1/blueprint.json +42 -0
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1401-persistence-data-d1-store-model.json +30 -0
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1402-persistence-data-d1-migration-discipline.json +30 -0
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1403-persistence-data-d1-event-secrecy.json +25 -0
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +25 -0
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1405-persistence-data-d1-recovery-model.json +30 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-001.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-002.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-003.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-004.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-005.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-006.json +18 -0
- package/blueprints/persistence-data-d1/contributions/requirements/persistence-data-d1-req-007.json +18 -0
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1401-persistence-data-d1-facade.json +51 -0
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1402-persistence-data-d1-migration-catalog.json +31 -0
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1403-persistence-data-d1-deploy-gate.json +38 -0
- package/blueprints/persistence-data-d1/contributions/tacs/tac-1404-persistence-data-d1-recovery-runner.json +39 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13101.json +45 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13102.json +45 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13103.json +46 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13104.json +45 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13105.json +45 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13106.json +46 -0
- package/blueprints/persistence-data-d1/contributions/user-stories/persistence-data-d1-us-13107.json +38 -0
- package/blueprints/persistence-data-d1/docs/topics.md +59 -0
- package/blueprints/persistence-data-d1/guide/persistence-data-d1.md +77 -0
- package/blueprints/persistence-data-sqlite/README.md +50 -0
- package/blueprints/persistence-data-sqlite/assets/backup-procedures/hot-checkpoint-note.md +22 -0
- package/blueprints/persistence-data-sqlite/assets/backup-procedures/sqlite-file-copy.md +70 -0
- package/blueprints/persistence-data-sqlite/assets/schema-samples/catalog-file-layout.md +73 -0
- package/blueprints/persistence-data-sqlite/assets/schema-samples/migration-shape.md +76 -0
- package/blueprints/persistence-data-sqlite/blueprint.json +50 -0
- package/blueprints/persistence-data-sqlite/contributions/adrs/adr-601-persistence-data-sqlite-store-model.json +30 -0
- package/blueprints/persistence-data-sqlite/contributions/adrs/adr-602-persistence-data-sqlite-migration-discipline.json +30 -0
- package/blueprints/persistence-data-sqlite/contributions/adrs/adr-603-persistence-data-sqlite-event-secrecy.json +25 -0
- package/blueprints/persistence-data-sqlite/contributions/adrs/adr-604-persistence-data-sqlite-store-boundary.json +25 -0
- package/blueprints/persistence-data-sqlite/contributions/adrs/adr-605-persistence-data-sqlite-backup-model.json +25 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-001.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-002.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-003.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-004.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-005.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-006.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-007.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-008.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-009.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-010.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/requirements/persistence-data-sqlite-req-011.json +18 -0
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-601-persistence-data-sqlite-store.json +57 -0
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-602-persistence-data-sqlite-migration-runner.json +34 -0
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-603-persistence-data-sqlite-migration-catalog.json +31 -0
- package/blueprints/persistence-data-sqlite/contributions/tacs/tac-604-persistence-data-sqlite-backup-runner.json +33 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5101.json +46 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5102.json +46 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5103.json +37 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5104.json +45 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5105.json +45 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5106.json +46 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5107.json +45 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5108.json +46 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5109.json +46 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5110.json +37 -0
- package/blueprints/persistence-data-sqlite/contributions/user-stories/persistence-data-sqlite-us-5111.json +37 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +49 -0
- package/blueprints/persistence-data-sqlite/guide/persistence-data-sqlite.md +69 -0
- package/blueprints/security-auth-clerk/README.md +50 -0
- package/blueprints/security-auth-clerk/assets/authorisation/role-claim-mapping-sample.md +99 -0
- package/blueprints/security-auth-clerk/assets/middleware/node-middleware-shape.md +86 -0
- package/blueprints/security-auth-clerk/assets/wiring/clerk-provider-react.md +48 -0
- package/blueprints/security-auth-clerk/assets/wiring/clerk-provider-vue.md +41 -0
- package/blueprints/security-auth-clerk/blueprint.json +42 -0
- package/blueprints/security-auth-clerk/contributions/adrs/adr-1001-security-auth-clerk-auth-model.json +30 -0
- package/blueprints/security-auth-clerk/contributions/adrs/adr-1002-security-auth-clerk-middleware-boundary.json +25 -0
- package/blueprints/security-auth-clerk/contributions/adrs/adr-1003-security-auth-clerk-authorisation-adapter-contract.json +25 -0
- package/blueprints/security-auth-clerk/contributions/adrs/adr-1004-security-auth-clerk-claims-mapping-discipline.json +25 -0
- package/blueprints/security-auth-clerk/contributions/adrs/adr-1005-security-auth-clerk-session-lifecycle.json +25 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-001.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-002.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-003.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-004.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-005.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-006.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-007.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-008.json +18 -0
- package/blueprints/security-auth-clerk/contributions/requirements/security-auth-clerk-req-009.json +18 -0
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1001-security-auth-clerk-middleware.json +42 -0
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1002-security-auth-clerk-authorisation-adapter.json +30 -0
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1003-security-auth-clerk-session-verifier.json +38 -0
- package/blueprints/security-auth-clerk/contributions/tacs/tac-1004-security-auth-clerk-claims-mapper.json +22 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9101.json +46 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9102.json +38 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9103.json +46 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9104.json +46 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9105.json +36 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9106.json +36 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9107.json +37 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9108.json +36 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9109.json +36 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9110.json +37 -0
- package/blueprints/security-auth-clerk/contributions/user-stories/security-auth-clerk-us-9111.json +36 -0
- package/blueprints/security-auth-clerk/docs/topics.md +56 -0
- package/blueprints/security-auth-clerk/guide/security-auth-clerk.md +71 -0
- package/blueprints/security-auth-keycloak/README.md +56 -0
- package/blueprints/security-auth-keycloak/assets/local-container/keycloak-bootstrap.md +54 -0
- package/blueprints/security-auth-keycloak/assets/middleware/verifier-wiring.md +93 -0
- package/blueprints/security-auth-keycloak/assets/mock-introspection/mock-introspection-shape.md +62 -0
- package/blueprints/security-auth-keycloak/assets/provider-router/router-shape.md +71 -0
- package/blueprints/security-auth-keycloak/assets/realm-skeleton/realm-config-shape.md +55 -0
- package/blueprints/security-auth-keycloak/blueprint.json +49 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1201-security-auth-keycloak-auth-model.json +35 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1202-security-auth-keycloak-verification-mode-choice.json +30 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1203-security-auth-keycloak-provider-routing-seam.json +30 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1204-security-auth-keycloak-session-vs-token-contract.json +25 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1205-security-auth-keycloak-jwks-rotation-cache-lifetime.json +30 -0
- package/blueprints/security-auth-keycloak/contributions/adrs/adr-1206-security-auth-keycloak-refresh-and-sign-out-posture.json +25 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-001.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-002.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-003.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-004.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-005.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-006.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-007.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-008.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-009.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-010.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-011.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/requirements/security-auth-keycloak-req-012.json +18 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1201-security-auth-keycloak-discovery-client.json +51 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1202-security-auth-keycloak-jwt-verifier.json +46 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1203-security-auth-keycloak-introspection-client.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1204-security-auth-keycloak-provider-router.json +37 -0
- package/blueprints/security-auth-keycloak/contributions/tacs/tac-1205-security-auth-keycloak-role-adapter.json +32 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11101.json +47 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11102.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11103.json +36 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11104.json +36 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11105.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11106.json +46 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11107.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11108.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11109.json +37 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11110.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11111.json +45 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11112.json +37 -0
- package/blueprints/security-auth-keycloak/contributions/user-stories/security-auth-keycloak-us-11113.json +36 -0
- package/blueprints/security-auth-keycloak/docs/topics.md +74 -0
- package/blueprints/security-auth-keycloak/guide/security-auth-keycloak.md +81 -0
- package/blueprints/security-auth-magic-link/README.md +46 -0
- package/blueprints/security-auth-magic-link/assets/email-templates/magic-link-email.md +44 -0
- package/blueprints/security-auth-magic-link/assets/email-templates/stub-adapter.md +55 -0
- package/blueprints/security-auth-magic-link/assets/principal-registry-samples/allow-list-file.md +46 -0
- package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +35 -0
- package/blueprints/security-auth-magic-link/blueprint.json +45 -0
- package/blueprints/security-auth-magic-link/contributions/adrs/adr-501-security-auth-magic-link-model.json +30 -0
- package/blueprints/security-auth-magic-link/contributions/adrs/adr-502-security-auth-magic-link-token-secrecy.json +25 -0
- package/blueprints/security-auth-magic-link/contributions/adrs/adr-503-security-auth-magic-link-anti-enumeration-budget.json +25 -0
- package/blueprints/security-auth-magic-link/contributions/adrs/adr-504-security-auth-magic-link-session-lifecycle.json +30 -0
- package/blueprints/security-auth-magic-link/contributions/adrs/adr-505-security-auth-magic-link-rate-limiting.json +25 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-001.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-002.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-003.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-004.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-005.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-006.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-007.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-008.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-009.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-010.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/requirements/security-auth-magic-link-req-011.json +18 -0
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-501-security-auth-magic-link-manager.json +45 -0
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-502-security-auth-magic-link-session-manager.json +46 -0
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-503-security-auth-magic-link-login-routes.json +76 -0
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-504-security-auth-magic-link-email-delivery-adapter.json +26 -0
- package/blueprints/security-auth-magic-link/contributions/tacs/tac-505-security-auth-magic-link-principal-registry.json +26 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3101.json +64 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3102.json +54 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3103.json +45 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3104.json +55 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3105.json +46 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3106.json +46 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3107.json +54 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3108.json +46 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3109.json +48 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3110.json +45 -0
- package/blueprints/security-auth-magic-link/contributions/user-stories/security-auth-magic-link-us-3111.json +45 -0
- package/blueprints/security-auth-magic-link/docs/topics.md +45 -0
- package/blueprints/security-auth-magic-link/guide/security-auth-magic-link.md +65 -0
- package/blueprints/security-auth-oauth2/README.md +50 -0
- package/blueprints/security-auth-oauth2/assets/mock-provider/mock-oidc-shape.md +55 -0
- package/blueprints/security-auth-oauth2/assets/provider-selector/list-shape.md +27 -0
- package/blueprints/security-auth-oauth2/assets/providers/generic-oidc-discovery.md +31 -0
- package/blueprints/security-auth-oauth2/assets/providers/github-oauth2-only.md +31 -0
- package/blueprints/security-auth-oauth2/assets/providers/google-oidc.md +31 -0
- package/blueprints/security-auth-oauth2/assets/session-bridge/opaque-handle-shape.md +59 -0
- package/blueprints/security-auth-oauth2/blueprint.json +44 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1101-security-auth-oauth2-auth-model.json +35 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1102-security-auth-oauth2-provider-abstraction-contract.json +25 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1103-security-auth-oauth2-pkce-discipline.json +25 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1104-security-auth-oauth2-session-bridge-shape.json +25 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1105-security-auth-oauth2-refresh-token-posture.json +25 -0
- package/blueprints/security-auth-oauth2/contributions/adrs/adr-1106-security-auth-oauth2-multi-provider-routing.json +25 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-001.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-002.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-003.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-004.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-005.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-006.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-007.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-008.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-009.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/requirements/security-auth-oauth2-req-010.json +18 -0
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1101-security-auth-oauth2-flow-controller.json +61 -0
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1102-security-auth-oauth2-provider-adapter.json +33 -0
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1103-security-auth-oauth2-session-bridge.json +51 -0
- package/blueprints/security-auth-oauth2/contributions/tacs/tac-1104-security-auth-oauth2-provider-selector.json +29 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10101.json +47 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10102.json +45 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10103.json +36 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10104.json +36 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10105.json +55 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10106.json +45 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10107.json +46 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10108.json +46 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10109.json +37 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10110.json +37 -0
- package/blueprints/security-auth-oauth2/contributions/user-stories/security-auth-oauth2-us-10111.json +28 -0
- package/blueprints/security-auth-oauth2/docs/topics.md +58 -0
- package/blueprints/security-auth-oauth2/guide/security-auth-oauth2.md +65 -0
- package/blueprints/security-secrets-management/README.md +48 -0
- package/blueprints/security-secrets-management/assets/cli-usage/agent-access-pattern.md +69 -0
- package/blueprints/security-secrets-management/assets/manifest-samples/environment-aware-example.md +33 -0
- package/blueprints/security-secrets-management/assets/manifest-samples/secrets-yaml-shape.md +74 -0
- package/blueprints/security-secrets-management/assets/ui-integration/three-way-choice.md +44 -0
- package/blueprints/security-secrets-management/blueprint.json +43 -0
- package/blueprints/security-secrets-management/contributions/adrs/adr-901-security-secrets-management-secrets-source.json +30 -0
- package/blueprints/security-secrets-management/contributions/adrs/adr-902-security-secrets-management-default-vendor.json +35 -0
- package/blueprints/security-secrets-management/contributions/adrs/adr-903-security-secrets-management-agent-access-discipline.json +25 -0
- package/blueprints/security-secrets-management/contributions/adrs/adr-904-security-secrets-management-dotenv-reflection.json +25 -0
- package/blueprints/security-secrets-management/contributions/adrs/adr-905-security-secrets-management-rotation-and-audit.json +30 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-001.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-002.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-003.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-004.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-005.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-006.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-007.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-008.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-009.json +18 -0
- package/blueprints/security-secrets-management/contributions/requirements/security-secrets-management-req-010.json +18 -0
- package/blueprints/security-secrets-management/contributions/tacs/tac-901-security-secrets-management-manager-client.json +52 -0
- package/blueprints/security-secrets-management/contributions/tacs/tac-902-security-secrets-management-manifest.json +34 -0
- package/blueprints/security-secrets-management/contributions/tacs/tac-903-security-secrets-management-env-reflector.json +46 -0
- package/blueprints/security-secrets-management/contributions/tacs/tac-904-security-secrets-management-rotation-gate.json +57 -0
- package/blueprints/security-secrets-management/contributions/tacs/tac-905-security-secrets-management-agent-cli.json +59 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8101.json +46 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8102.json +45 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8103.json +37 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8104.json +45 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8105.json +55 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8106.json +46 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8107.json +46 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8108.json +45 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8109.json +46 -0
- package/blueprints/security-secrets-management/contributions/user-stories/security-secrets-management-us-8110.json +45 -0
- package/blueprints/security-secrets-management/docs/topics.md +46 -0
- package/blueprints/security-secrets-management/guide/security-secrets-management.md +68 -0
- package/fixtures/canary-manifest.json +1 -101
- package/package.json +15 -9
- package/rcf/.identity/profile.md +37 -0
- package/rcf/knowledge/INDEX.md +12 -0
- package/rcf/knowledge/README.md +41 -0
- package/rcf/knowledge/docs/.gitkeep +0 -0
- package/rcf/knowledge/notes/.gitkeep +0 -0
- package/scripts/preinstall-node-check.mjs +61 -0
- package/src/blueprint/apply.js +12 -6
- package/src/blueprint/conflicts.js +8 -8
- package/src/blueprint/index.js +2 -1
- package/src/blueprint/list.js +60 -0
- package/src/blueprint/loader.js +26 -1
- package/src/blueprint/namespace.js +20 -16
- package/src/blueprint/shelf-resolver.js +173 -0
- package/src/blueprint/supersede.js +3 -2
- package/src/browser-verify/invariants.js +40 -0
- package/src/browser-verify/runner.js +2 -0
- package/src/cli/blueprint.js +53 -9
- package/src/cli/init.js +2 -0
- package/src/core/store/writer.js +64 -2
- package/src/setup/agent-setup.js +28 -10
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Security auth Clerk blueprint guide
|
|
2
|
+
|
|
3
|
+
## What it is
|
|
4
|
+
|
|
5
|
+
A Clerk-committed authentication floor for small greenfield rcf-lite projects. The blueprint contributes the WHAT of a hosted-identity pattern: how the project delegates identity to Clerk, how it verifies the resulting session cookie on the server, how it reduces the verified claims into a stable Principal shape, how the authorisation adapter maps Clerk roles and organisation memberships onto project-defined verbs, how sign-in strategy sits as a config surface rather than a hard-coded choice, how sign-out honours Clerk-side revocation within a bounded window, how rate-limiting and anti-enumeration are delegated to Clerk, how user and organisation provisioning stays read-only from the runtime's perspective, and how runtime-verify acceptance criteria acknowledge that Clerk-reachable behaviour cannot be faked.
|
|
6
|
+
|
|
7
|
+
Concretely, the blueprint ships nine requirements, eleven user stories (twenty-five acceptance criteria), four architecture components, and five architecture decision records. One ADR is `scope: global` on the `authModel` topic; the other four are scope-local operational ADRs (middleware-boundary shape, authorisation-adapter contract, claims-mapping discipline, session-lifecycle posture) that a composing blueprint does not conflict with by default.
|
|
8
|
+
|
|
9
|
+
## What it is not
|
|
10
|
+
|
|
11
|
+
Not a Clerk SDK version pin. The SDK's package version is a project-package-manifest concern; the blueprint fixes the shape of the boundary (the `verify(request)` contract, the `__session` cookie name, the reduced Principal shape) and lets the project pick which Clerk SDK major it builds against.
|
|
12
|
+
|
|
13
|
+
Not an MFA policy. Clerk owns MFA at the hosted identity surface; the blueprint delegates MFA to Clerk's configuration and does not encode an MFA strategy or enforcement rule at the project's runtime. A project with a hard MFA-for-all-admins requirement configures that on the Clerk dashboard.
|
|
14
|
+
|
|
15
|
+
Not a user or organisation mirror. Clerk is authoritative for identity state. A project that needs to mirror Clerk state into a local table for query purposes (a per-user preferences row, a per-organisation audit log) does so through a project-authored Clerk-webhook consumer; that consumer is out of scope for the blueprint's default. A project that includes one adds one project-authored TAC and one scope-local ADR alongside this blueprint's contributions.
|
|
16
|
+
|
|
17
|
+
Not a project-side rate limiter or anti-enumeration defence. Clerk applies its own throttling and enumeration defences at the identity surface; the blueprint requires that the project does not layer a second, competing rate limiter on top of the sign-in flow.
|
|
18
|
+
|
|
19
|
+
Not an OAuth2-provider-list blueprint. A project that wants direct OAuth2 against a specific set of social providers, without a hosted identity vendor, reaches for the future `security-auth-oauth2` sibling blueprint when it ships. A project that wants a self-hosted OIDC surface reaches for the future `security-auth-keycloak` sibling. Both conflict with this blueprint on `authModel` by design.
|
|
20
|
+
|
|
21
|
+
Not the sign-in UI. Clerk hosts the sign-in surface (either fully hosted at Clerk's domain or embedded through Clerk's components). The blueprint's job is to wire the surface into a project route and to verify the resulting session on the server; the pixels of the sign-in form are Clerk's.
|
|
22
|
+
|
|
23
|
+
## When to reach for it
|
|
24
|
+
|
|
25
|
+
Reach for the security-auth-clerk blueprint when:
|
|
26
|
+
|
|
27
|
+
- The project needs user accounts, sessions, sign-in UX, and account recovery, and the operator's preference is to buy that surface from a hosted vendor rather than build it.
|
|
28
|
+
- The project's operator wants a straightforward path to enterprise-shaped features (SAML, SCIM, organisation memberships, roles) without owning the identity infrastructure that supports them.
|
|
29
|
+
- The team is small enough that owning the identity surface (email deliverability, MFA rollout, breach-check integration, session persistence) is a distraction from the product.
|
|
30
|
+
- The project's compliance posture accepts a hosted identity vendor; a project subject to data-residency constraints that Clerk's regions do not satisfy is on the wrong blueprint.
|
|
31
|
+
- The project already uses (or plans to use) Clerk's dashboard for user administration and does not want a second admin surface.
|
|
32
|
+
|
|
33
|
+
## When it does not fit
|
|
34
|
+
|
|
35
|
+
Do not reach for the security-auth-clerk blueprint when:
|
|
36
|
+
|
|
37
|
+
- The project cannot depend on a hosted third-party identity surface (data-residency constraints, an air-gapped deployment, a compliance regime that requires self-hosted identity). Reach for `security-auth-keycloak` when it ships, or supersede ADR-1001 with a project-level ADR and pick a self-hosted vendor whose adapter the project authors.
|
|
38
|
+
- The project's identity surface is genuinely trivial (one operator, no organisations, no roles). A passwordless magic-link floor (`security-auth-magic-link`) is honestly a smaller machine at that scale; this blueprint's provider dependency and pricing tier are overkill.
|
|
39
|
+
- The project wants direct OAuth2 against a specific set of social providers and nothing else, with no hosted identity vendor. `security-auth-oauth2` will cover that shape when it ships; picking this blueprint plus Clerk's OAuth strategies is valid but is a bigger machine than a project that only wants "sign in with GitHub" needs.
|
|
40
|
+
- The project cannot accept the `accountBound` runtime-verify posture (runtime tests that skip when Clerk is unreachable, rather than pass on a fake). Every hosted-identity blueprint carries this posture; a project that needs offline test independence is on the wrong blueprint family.
|
|
41
|
+
|
|
42
|
+
An earlier round-1 pass shipped `security-auth-magic-link` as the generic-auth blueprint; the round-2 pass introduces the vendor-committed siblings (this blueprint for Clerk, plus the reserved `security-auth-oauth2` and `security-auth-keycloak`). The composition-precedent is `application-spa` + `application-api-rest` on the `errorEnvelope` and `authModel` topics: siblings on the same topic conflict on purpose and expect a project-level ADR resolution.
|
|
43
|
+
|
|
44
|
+
## What a good outcome looks like
|
|
45
|
+
|
|
46
|
+
A project applies the blueprint on a fresh tree, provisions a Clerk development instance, stores the publishable and secret keys in the secrets manifest under placeholder-named entries (`CLERK_PUBLISHABLE_KEY`, `CLERK_SECRET_KEY`), chooses its `signInStrategy` primary and alternates, realises the four TACs in project-authored FBSes (one framework-specific middleware shim, one authorisation-adapter with a project verb-to-role mapping, one session verifier over the Clerk SDK, one claims mapper), and lands on a deployed application where:
|
|
47
|
+
|
|
48
|
+
- The sign-in surface renders Clerk's hosted (or embedded) sign-in UI; the operator signs in and lands on the app with a `__session` cookie in their browser.
|
|
49
|
+
- Every request to a protected route arrives at the middleware, which verifies the cookie against Clerk and attaches `request.auth = { principalId, roles, organisationIds, claims }` before the handler runs.
|
|
50
|
+
- Every handler that gates on identity calls `can(request.auth, verb, subject?)` or `assert(request.auth, verb, subject?)` on the authorisation adapter; no handler reads `request.auth.roles` or `request.auth.claims` directly.
|
|
51
|
+
- Role-based UI slots on rendered pages appear or disappear per the adapter's decision; the corresponding server-side handler enforces the same verb through `assert`.
|
|
52
|
+
- The Clerk SDK is imported by two modules in the project (the middleware wiring and the session verifier). A source-tree scan confirms the boundary.
|
|
53
|
+
- The operator signs out; a subsequent request replaying the pre-sign-out cookie is refused by the middleware within the `revocationCheckIntervalMs` window declared on ADR-1005.
|
|
54
|
+
- The sign-in flow has no project-authored rate limiter; Clerk's own throttling is the observed behaviour under a burst of attempts.
|
|
55
|
+
- User and organisation management happens on the Clerk dashboard (or on a project-authored provisioning script directory that runs outside the request lifecycle); the runtime never mutates Clerk identity state.
|
|
56
|
+
- The runtime-verify test surface marks Clerk-reachable ACs as `accountBound` and, when the CI runner has Clerk reachable, they pass against the development instance; when the CI runner does not, they skip with `AUTH_CLERK_UNREACHABLE`, not pass silently.
|
|
57
|
+
|
|
58
|
+
## Operator decisions that remain open after apply
|
|
59
|
+
|
|
60
|
+
- Vendor choice (Clerk default per ADR-1001, or a superseding project-level ADR selecting Auth0, WorkOS, Cognito, or a project-authored hosted-identity adapter). Blueprint owns the boundary on both sides; project owns the vendor when it supersedes.
|
|
61
|
+
- `signInStrategy` primary and alternates (email link, email code, password, phone code, OAuth against named providers, SAML). Blueprint owns the shape; project owns the choice; Clerk dashboard owns the enablement.
|
|
62
|
+
- Verb-to-role mapping table (project vocabulary; every downstream `can` and `assert` call speaks in these verbs). Blueprint owns the adapter shape; project owns the mapping.
|
|
63
|
+
- Organisation scoping policy (whether to scope every resource by `organisationId` or leave organisation membership as a flat role decoration). Blueprint owns the adapter's optional-subject shape; project owns the choice.
|
|
64
|
+
- `revocationCheckIntervalMs` (30 seconds default per ADR-1005, or a shorter window at the cost of a per-request Clerk round trip, or a longer window up to the session's declared expiry). Blueprint owns the shape and the ceiling; project owns the number.
|
|
65
|
+
- Clerk plan tier (development, production, per-user pricing). Blueprint owns none of this; the operator picks per project needs.
|
|
66
|
+
- Provisioning-script directory location (`scripts/provisioning/` by convention on AC-9110-1, or a project-declared equivalent). Blueprint owns that provisioning is not a request handler; project owns where the scripts live.
|
|
67
|
+
- Whether to layer a project-authored Clerk-webhook consumer (for user-created, session-ended, or organisation-membership-changed events). Blueprint's default omits it; a project that adds one authors one TAC and one ADR alongside this blueprint's contributions.
|
|
68
|
+
|
|
69
|
+
## Cost-honesty paragraph
|
|
70
|
+
|
|
71
|
+
Shipping this doc set costs the project the following. Clerk is a paid vendor beyond the development tier; the operator budgets for it. The `accountBound` runtime-verify posture means the CI runner needs Clerk reachability to actually verify the runtime-verify ACs; a CI runner without outbound network for that vendor either skips those ACs (which the ship gate flags) or the operator wires a preview Clerk instance for CI to reach. The middleware boundary discipline (`request.auth` and `can`/`assert` everywhere) is a code-review load on every new handler; a project that lets the discipline slip loses the vendor-swap-safety the blueprint is buying. The `revocationCheckIntervalMs` window is a stated trade between per-request cost and sign-out prompt-ness; the operator picks a number that reflects the project's actual policy, not the blueprint's default forever. The read-only provisioning posture forces the operator to run Clerk mutations outside the request lifecycle; a project that wants a per-request user-create call is on a different pattern and should think again. The blueprint says nothing about MFA policy, about pricing, about SLA, or about vendor-lock exit; a project that needs any of those spends its own build cycles on them and this blueprint does not save it any work there.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Security auth Keycloak blueprint (v1.0.0)
|
|
2
|
+
|
|
3
|
+
The twelfth content blueprint on the rcf-build-lite blueprint mechanism, category `security`. A Keycloak-committed sibling to `security-auth-magic-link`, `security-auth-clerk`, and `security-auth-oauth2` on the `authModel` global topic. Identity is delegated to a Keycloak realm the operator runs; the project owns the discovery client, the token verifier (JWKS or introspection per realm), the role adapter, the provider-routing seam, and the optional application session on top. Targeted at rcf-lite projects that have committed to a self-hosted Keycloak realm (or are running one already) and want the Keycloak-shaped decisions the vendor-neutral `security-auth-oauth2` sibling deliberately does not fix.
|
|
4
|
+
|
|
5
|
+
## Apply
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
rcf define blueprint add <path-to>/blueprints/security-auth-keycloak
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Phase 1 resolves local path sources only; registry and git-ref resolution is a mechanism follow-up. Apply is idempotent; `rcf define blueprint list` shows the applied entry grouped under the `security` category; `rcf define blueprint remove security-auth-keycloak` cleanly removes an unreferenced application.
|
|
12
|
+
|
|
13
|
+
Composing with `security-auth-magic-link`, `security-auth-clerk`, `security-auth-oauth2`, or any other blueprint contributing `scope: global` on `authModel` (which includes `application-spa` and `application-api-rest`) raises a `globalAdrTopic` conflict at add time. The four documented resolutions apply (adopt the incoming, keep the existing, project-level supersede ADR, or `--resolve authModel=project:<ADR-id>` on the add). See `docs/topics.md` for the deliberate-conflict statement.
|
|
14
|
+
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
| Piece | Where | What |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Metadata | `blueprint.json` | Slug, version, category `security`, and the 36 contributions with scope/topic on the one global ADR |
|
|
20
|
+
| Doc set | `contributions/` | 12 REQs, 13 USs (34 ACs), 5 TACs, 6 ADRs, all schema-valid and namespaced (`security-auth-keycloak-REQ-001` prefix family; `ADR-1201-security-auth-keycloak-auth-model` suffix family) |
|
|
21
|
+
| Local-container bootstrap | `assets/local-container/keycloak-bootstrap.md` | Shape a project harness follows to stand up the vendor's official image; no compose file lifted from any real deployment |
|
|
22
|
+
| Realm-config record | `assets/realm-skeleton/realm-config-shape.md` | The plain data-record shape a project maintains per realm; placeholder secrets only |
|
|
23
|
+
| Verifier middleware wiring | `assets/middleware/verifier-wiring.md` | HTTP-framework-agnostic Node middleware chain wiring the mechanism's five factories |
|
|
24
|
+
| Provider-router seam | `assets/provider-router/router-shape.md` | The pure-function contract a project's routing decision satisfies; generic OAuth2/OIDC vocabulary; no named second issuer |
|
|
25
|
+
| Mock introspection responder | `assets/mock-introspection/mock-introspection-shape.md` | RFC 7662 shape the harness stands up for the introspection-mode verify path |
|
|
26
|
+
| Guide | `guide/security-auth-keycloak.md` | Operator-facing: when to use it, when not, promotion signals, cost honesty |
|
|
27
|
+
| Coordination vocabulary | `docs/topics.md` | The global topic string and the shared id-band registry |
|
|
28
|
+
|
|
29
|
+
The doc set is contributions (copied into the project tree by `rcf define blueprint add`); the guide, assets, and docs are package-resident references. Guide rendering into `rcf/knowledge/docs/blueprint-guides/` and asset ingestion are mechanism follow-ups; until they land, the working agent reads them from the applied blueprint's source path recorded in `manifest.blueprints[].source`.
|
|
30
|
+
|
|
31
|
+
## What it contributes, and what it deliberately does not
|
|
32
|
+
|
|
33
|
+
Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (ratified decision 5) and no code.
|
|
34
|
+
|
|
35
|
+
No FBS contributions, as a matter of principle (ratified policy 2026-08-19): FBSs are the work of the implementing agent, not the blueprint; project constraints have to be applied at the time of creation. The blueprint contributes the WHAT (the Keycloak realm as identity source, the OIDC discovery contract, the JWKS-with-rotation-cache verification path, the RFC 7662 introspection path, the provider-routing seam, the Keycloak client-roles / realm-roles claim shape, the refresh-and-sign-out posture inherited from the realm, the session-vs-token separation, the local-first stand-up shape, the fail-safe boot postures, the runtime-verify posture with accountBound cloud smokes); the implementing agent derives the HOW-tasks (FBS) in the host project.
|
|
36
|
+
|
|
37
|
+
Deliberately not contributed: the OAuth2 authorisation-code flow controller itself (a project either draws it from the sibling `security-auth-oauth2` blueprint or authors one above this blueprint's five TACs; the Keycloak-committed decisions here bind the flow controller's provider adapter to a Keycloak realm and no more); a specific HTTP framework adapter (the middleware wiring is framework-agnostic; framework adapters are a project responsibility); a specific session-record store (opaque-handle mode injects it; in-memory is the reference default; a persistence-composed project points at a table); MFA specifics (Keycloak owns MFA at the realm surface); real realm data (a placeholder `example` realm name is the shape; no lifted config); any specific second identity provider (the provider-routing seam is generic; the blueprint does not name a second issuer, per the ratified reshape ruling).
|
|
38
|
+
|
|
39
|
+
## The one global decision
|
|
40
|
+
|
|
41
|
+
ADR-1201-security-auth-keycloak-auth-model ships `scope: global` on topic `authModel`. This is the project's single decision on how identity is proven, where credentials live, and what the wire credential looks like. Composing with `security-auth-magic-link`, `security-auth-clerk`, `security-auth-oauth2`, `application-spa`, `application-api-rest`, or any future `security-auth-*` blueprint conflicts here by design and expects a project-level ADR resolution. The composition-precedent (SPA + REST on `errorEnvelope` and `authModel`) is the same pattern the auth-family blueprints follow.
|
|
42
|
+
|
|
43
|
+
See `docs/topics.md` for the exact strings, the expected resolutions, and the AC id band allocation (security-auth-keycloak owns US 11101-11899 with US 11101-11113 in use, ADR/TAC suffix block 1201-1299; the third blueprint to sit in the four-digit ADR/TAC suffix space after security-auth-clerk (1001-1099) and security-auth-oauth2 (1101-1199)).
|
|
44
|
+
|
|
45
|
+
## Quality bar
|
|
46
|
+
|
|
47
|
+
Authorisation-code + PKCE (S256) as the sole flow; JWT verification via realm JWKS with a rotation cache defended by TTL and by kid-miss single-refresh; RFC 7662 introspection as the alternate verification mode selected per realm record; provider-routing seam expressed as a project-authored pure function; role extraction from Keycloak's `client-roles` or `realm-roles` claim path per record declaration; refresh rotation honours the realm's declared model (revoke-on-reuse tightened by the realm; soft rotation permitted where the operator has declared it); sign-out invalidates the project session with realm-side end-session opt-in per record; session-vs-token separation with opaque-handle sessions (default) or stateless bearer verification (opt-in) per realm; fail-safe boot posture declared per realm (strict / deferred / standby); runtime-verify against a local Keycloak container with cloud-tenant smokes marked accountBound and skipped with a stable-coded reason when credentials are unavailable. Every bar is carried by ACs in the doc set, not by this README.
|
|
48
|
+
|
|
49
|
+
## Known mechanism-reach gaps
|
|
50
|
+
|
|
51
|
+
Three named gaps at v1.0.0. First, AC-11112-2 (the live cloud-realm smoke against a project-owned Keycloak deployment or a managed Keycloak service) is `accountBound` and depends on operator-provided cloud-realm credentials plus a redirect URI registration at the deployment's admin console; those steps sit outside the blueprint's mechanism reach. The project's ship gate reads the honest coverage: the AC is covered by a project-authored TC whose latest outcome is `skipped` with reason `KEYCLOAK_LIVE_REALM_UNREACHABLE` when credentials are absent, and `pass` when the operator has driven the smoke. The `accountBound` skip does not fail CI and does not count as coverage passed for a project auditing its cloud-realm readiness; the ship-gate operator reads the AC and drives the smoke themselves before promoting a build past staging. The local Keycloak container path (REQ-009, US-11101 through US-11104, US-11107, US-11108, US-11110, US-11111) is NOT accountBound: the vendor's official container image runs standalone under a project's harness and the mechanism verifies against it end-to-end at every runtime-verify pass. Second, every AC on every story is bound to at least one TAC that the host project must realise, and every AC's `then` clause is runtime-observable in the deployed application (redirect-inspection for the authorise URL shape, token-exchange-request inspection for the PKCE verifier presentation, response-cookie inspection for the session-cookie contract, `request.auth` shape inspection for the Principal reduction, mock-introspection response substitution for the opaque-token classes, JWKS mutation for the JWT refusal classes, session-record store inspection for refresh-token rotation, cookie-clear inspection for sign-out, `Location`-header inspection for realm-side sign-out redirect). A project that applies this blueprint and does not realise a TAC leaves an unresolved `tacIds` reference on the story that `rcf define validate` and `rcf audit coverage` refuse. Third, the flow controller itself (the state machine that mints the pending-flow record, builds the authorisation redirect, and drives the callback) is NOT contributed by this blueprint at v1.0.0: a project either composes the vendor-neutral sibling `security-auth-oauth2` (which contributes TAC-1101-security-auth-oauth2-flow-controller) and points its provider-adapter at a Keycloak realm through this blueprint's discovery client and verifier, or the project authors a project-side flow controller above this blueprint's five TACs. The two composition paths are equally valid; the blueprint documents both in the guide.
|
|
52
|
+
|
|
53
|
+
## Composition intent (deliberate)
|
|
54
|
+
|
|
55
|
+
- Applying this blueprint on top of `security-auth-magic-link`, `security-auth-clerk`, `security-auth-oauth2`, `application-spa`, or `application-api-rest` raises a `globalAdrTopic` conflict on `authModel`. That is intended: one project has one authentication model, and the surfacing is the mechanism's promise. Resolution paths are documented on `docs/topics.md`.
|
|
56
|
+
- Sibling PRs open or recently merged at this pass: `blueprint/security-auth-oauth2` (band 10101-10899 US, 1101-1199 ADR/TAC). Zero id-band overlap.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Keycloak local-container bootstrap: shape (not a compose file lift)
|
|
2
|
+
|
|
3
|
+
Shape a project stands up to satisfy REQ-009's local-first posture. The container is real Keycloak on the wire; the discovery client, the JWT verifier, and the introspection client cannot tell it apart from a cloud-hosted realm for the purpose of the state machine and the verification paths.
|
|
4
|
+
|
|
5
|
+
The blueprint does NOT ship a `docker-compose.yaml` file, a `Dockerfile`, or a container-orchestration recipe from any real deployment. The notes below name the shape a project's harness follows; the harness itself lives on the project.
|
|
6
|
+
|
|
7
|
+
## Image
|
|
8
|
+
|
|
9
|
+
The vendor's official image is `quay.io/keycloak/keycloak`. The operator pins the currently-supported stable tag at the moment they set the harness up (the vendor's release cadence moves; the pin belongs on the project's tooling, not on this blueprint). A harness that reads the pin from a project environment file is the recommended pattern.
|
|
10
|
+
|
|
11
|
+
## Startup command shape
|
|
12
|
+
|
|
13
|
+
Development-mode startup is what the harness invokes; the vendor documents it as `kc.sh start-dev`. The harness passes:
|
|
14
|
+
|
|
15
|
+
- `KC_HOSTNAME=127.0.0.1` (or a hostname the project's test suite reaches over)
|
|
16
|
+
- `KC_HTTP_ENABLED=true` (development-mode is fine over plain HTTP; production is the operator's own concern and not this asset's shape)
|
|
17
|
+
- `KC_BOOTSTRAP_ADMIN_USERNAME` and `KC_BOOTSTRAP_ADMIN_PASSWORD` read from a project environment file the harness controls (placeholders only; never committed)
|
|
18
|
+
- A published port the harness records for the `issuerBaseUrl` on the realm-config record
|
|
19
|
+
|
|
20
|
+
The container is standalone; no external database is required in development mode (Keycloak's default embedded H2 covers a scratch service).
|
|
21
|
+
|
|
22
|
+
## Realm seed (placeholder-only)
|
|
23
|
+
|
|
24
|
+
The harness applies a realm-configuration seed either through the vendor's `kc.sh import` path (mounting a realm-export file) or through the admin REST API after startup. The seed carries:
|
|
25
|
+
|
|
26
|
+
- Realm name: `example` (a generic placeholder; the operator picks a stable name for their project)
|
|
27
|
+
- One client: `example-client`
|
|
28
|
+
- `Access Type: confidential`
|
|
29
|
+
- `Client authentication: on`
|
|
30
|
+
- `Standard flow (authorisation code): on`
|
|
31
|
+
- `Direct access grants: off`
|
|
32
|
+
- `Redirect URIs: <project-callback-url>` (the project's callback route on the test process)
|
|
33
|
+
- `PKCE Code Challenge Method: S256`
|
|
34
|
+
- `Access Token Signature Algorithm: RS256` (JWKS mode) or issued opaque (introspection mode)
|
|
35
|
+
- One role assignment shape:
|
|
36
|
+
- Client roles when `roleClaimShape: 'client-roles'` (recommended default)
|
|
37
|
+
- Realm roles when `roleClaimShape: 'realm-roles'`
|
|
38
|
+
- One or two test users (placeholder usernames and passwords; never committed)
|
|
39
|
+
|
|
40
|
+
Nothing in this seed shape names a real deployment; the operator either accepts the `example` names or renames them for their own project.
|
|
41
|
+
|
|
42
|
+
## Wiring notes for the project
|
|
43
|
+
|
|
44
|
+
- The harness records `<issuerBaseUrl>` (the container's public URL) and passes it as the `issuerBaseUrl` field on the realm-config record.
|
|
45
|
+
- The realm name (`realmName` field on the record) matches the seed's realm name.
|
|
46
|
+
- The `clientId` and `clientSecret` on the record match the seeded client's fields; the secret comes from the admin surface after client creation and lives in an operator-controlled environment file, never in a committed record.
|
|
47
|
+
- A harness that tears down the container between test suites is fine and preferred; Keycloak's development-mode startup is fast enough to run per-suite when the project's suite structure warrants it.
|
|
48
|
+
- A harness that keeps a shared team-level container running is also fine; each project's harness applies its own seed on start.
|
|
49
|
+
|
|
50
|
+
## Alternate stand-up paths
|
|
51
|
+
|
|
52
|
+
- A persistent scratch service the operator runs once (a system-installed Keycloak, a team-shared container, a devcontainer) is fine; the harness records the discovered endpoints and the mechanism does not care whether the realm is per-suite or persistent.
|
|
53
|
+
- A Kubernetes namespace with Keycloak deployed via the vendor's operator (or via a chart the operator maintains) is fine; the mechanism sees a discovery endpoint and populates the record.
|
|
54
|
+
- The blueprint does not commit to any of these paths; the shape above is the contract, not the tooling.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Verifier middleware wiring: HTTP-framework-agnostic shape
|
|
2
|
+
|
|
3
|
+
A record-only shape for the middleware chain a project wires above the mechanism. Not production code; a project's own HTTP framework is what turns this into concrete request handlers.
|
|
4
|
+
|
|
5
|
+
The mechanism's public surface is three factory functions and one router:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
const discoveryClient = createDiscoveryClient({
|
|
9
|
+
realmConfig,
|
|
10
|
+
httpFetch,
|
|
11
|
+
clock,
|
|
12
|
+
auditSink,
|
|
13
|
+
retryScheduler
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const jwtVerifier = createJwtVerifier({
|
|
17
|
+
discoveryClient,
|
|
18
|
+
httpFetch,
|
|
19
|
+
clock,
|
|
20
|
+
auditSink
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const introspectionClient = createIntrospectionClient({
|
|
24
|
+
discoveryClient,
|
|
25
|
+
httpFetch,
|
|
26
|
+
clock,
|
|
27
|
+
auditSink
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const providerRouter = createProviderRouter({
|
|
31
|
+
routeFn,
|
|
32
|
+
realmConfig,
|
|
33
|
+
auditSink
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const roleAdapter = createRoleAdapter({
|
|
37
|
+
realmConfig,
|
|
38
|
+
auditSink
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Request-time chain
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
async function verifyRequest(request) {
|
|
46
|
+
const decision = providerRouter.route(request);
|
|
47
|
+
if (decision === 'notThisIssuer') {
|
|
48
|
+
return { status: 'notThisIssuer' };
|
|
49
|
+
}
|
|
50
|
+
const record = realmConfig.get(decision.realmSlug);
|
|
51
|
+
if (record === undefined) {
|
|
52
|
+
return { status: 'refused', code: 'KEYCLOAK_REALM_UNKNOWN' };
|
|
53
|
+
}
|
|
54
|
+
const health = discoveryClient.health(decision.realmSlug);
|
|
55
|
+
if (health !== 'healthy') {
|
|
56
|
+
return { status: 'refused', code: 'KEYCLOAK_REALM_UNAVAILABLE' };
|
|
57
|
+
}
|
|
58
|
+
const token = extractToken(request, record);
|
|
59
|
+
if (token === null) {
|
|
60
|
+
return { status: 'refused', code: 'KEYCLOAK_TOKEN_MISSING' };
|
|
61
|
+
}
|
|
62
|
+
const verified =
|
|
63
|
+
decision.verificationMode === 'jwks'
|
|
64
|
+
? await jwtVerifier.verify(decision.realmSlug, token)
|
|
65
|
+
: await introspectionClient.verify(decision.realmSlug, token);
|
|
66
|
+
if (verified.ok === false) {
|
|
67
|
+
return { status: 'refused', code: verified.code };
|
|
68
|
+
}
|
|
69
|
+
const principal = roleAdapter.principalFrom(decision.realmSlug, verified.claims);
|
|
70
|
+
if (principal.ok === false) {
|
|
71
|
+
return { status: 'refused', code: principal.code };
|
|
72
|
+
}
|
|
73
|
+
request.auth = principal.reduced;
|
|
74
|
+
return { status: 'verified' };
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`extractToken(request, record)` reads the bearer source per `sessionMode`: opaque-handle mode reads the session cookie and swaps it for the stored access token from the session record; stateless mode reads directly from the `bearerSource` field.
|
|
79
|
+
|
|
80
|
+
## Wiring a specific framework
|
|
81
|
+
|
|
82
|
+
The mechanism does not ship framework adapters at v1; a project on Express, Fastify, Hono, or the vendor's Workers runtime writes a one-file adapter that calls `verifyRequest` and produces the framework's response shape for the refusal classes above. Every framework adapter is a thin wrapper; the state machine is what this file names.
|
|
83
|
+
|
|
84
|
+
## Sign-in and sign-out routes
|
|
85
|
+
|
|
86
|
+
The sign-in initiation and callback routes are the flow controller's territory (a project either authors them above this blueprint's five TACs, or draws them from the sibling `security-auth-oauth2` blueprint's flow controller and adapts the state machine to the Keycloak record). The sign-out route is one line: invalidate the session handle if opaque-handle mode; clear the cookie; consult the realm record's `providerLogout` field to decide whether to return a 302 to `end_session_endpoint`.
|
|
87
|
+
|
|
88
|
+
## What this file does NOT commit
|
|
89
|
+
|
|
90
|
+
- No specific HTTP framework
|
|
91
|
+
- No specific session-record store implementation
|
|
92
|
+
- No specific httpFetch (the platform's `fetch` is the reference default; a project's harness substitutes in tests)
|
|
93
|
+
- No specific audit sink; a project points at its own event pipeline
|
package/blueprints/security-auth-keycloak/assets/mock-introspection/mock-introspection-shape.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Mock introspection responder: shape
|
|
2
|
+
|
|
3
|
+
A local stub responder a project stands up to satisfy US-11105's runtime-verify posture for `verificationMode: 'introspection'` without running a second Keycloak realm configured for opaque tokens.
|
|
4
|
+
|
|
5
|
+
The mock is real RFC 7662 on the wire: same request shape, same response shape, same content-type. The introspection client cannot tell it apart from a real Keycloak introspection endpoint for the purpose of the state machine and the response handling.
|
|
6
|
+
|
|
7
|
+
A project may implement the mock in-process (a small Node HTTP server the test harness starts and tears down), against an existing library, or as a persistent scratch service. The shape below is what the harness expects, not what a specific library commits to.
|
|
8
|
+
|
|
9
|
+
## Introspection endpoint (`POST /introspect`)
|
|
10
|
+
|
|
11
|
+
Accepts:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Content-Type: application/x-www-form-urlencoded
|
|
15
|
+
Authorization: Basic <base64(clientId:clientSecret)>
|
|
16
|
+
|
|
17
|
+
token=<opaque-token>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Returns (per RFC 7662):
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Content-Type: application/json
|
|
24
|
+
|
|
25
|
+
{
|
|
26
|
+
"active": true,
|
|
27
|
+
"sub": "<opaque-subject-id>",
|
|
28
|
+
"aud": "<clientId>",
|
|
29
|
+
"iss": "<issuer>",
|
|
30
|
+
"exp": <epoch-seconds>,
|
|
31
|
+
"scope": "openid profile email",
|
|
32
|
+
"resource_access": {
|
|
33
|
+
"<clientId>": {
|
|
34
|
+
"roles": ["admin", "editor"]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"realm_access": {
|
|
38
|
+
"roles": []
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Test-controllable knobs (per-token)
|
|
44
|
+
|
|
45
|
+
- Return `active: false` on demand (for AC-11105-2)
|
|
46
|
+
- Return HTTP 503 on demand (for AC-11105-3)
|
|
47
|
+
- Return HTTP 400 on demand (for endpoint-error edge cases)
|
|
48
|
+
- Return an `active: true` response with a claim record shaped for either `client-roles` or `realm-roles` (for US-11107)
|
|
49
|
+
- Return an `active: true` response with a malformed `roles` field (for AC-11107-3)
|
|
50
|
+
|
|
51
|
+
## Wiring notes
|
|
52
|
+
|
|
53
|
+
- The mock listens on `127.0.0.1:<random-port>` and the harness passes the port to the realm-config record's `introspection_endpoint` (either directly or through a discovery-response substitution).
|
|
54
|
+
- The mock's `clientSecret` is a placeholder the harness controls; the real realm's secret never appears here.
|
|
55
|
+
- A per-test-suite instance is fine and preferred; state does not have to persist.
|
|
56
|
+
- A project may substitute a second local Keycloak realm configured for opaque tokens if it prefers a real Keycloak surface; the mechanism cannot tell the difference and does not care.
|
|
57
|
+
|
|
58
|
+
## What this asset does NOT commit
|
|
59
|
+
|
|
60
|
+
- No library or package version. The shape is the contract; the implementation is a project responsibility.
|
|
61
|
+
- No specific `sub` value, no specific role vocabulary, no specific issuer string. The examples above are placeholders.
|
|
62
|
+
- No real `clientId` or `clientSecret`. The mock trusts whatever basic-auth pair the harness gives it, or refuses per the harness's test-driven behaviour.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Provider router: seam shape
|
|
2
|
+
|
|
3
|
+
Generic-vocabulary shape a project's own middleware invokes to answer one question: for THIS request, which realm record is authoritative (or does the routing hand off entirely)?
|
|
4
|
+
|
|
5
|
+
The blueprint stays Keycloak-committed. This asset describes the SHAPE of the routing function; it does NOT name any specific second issuer, any specific request feature, or any specific deployment topology.
|
|
6
|
+
|
|
7
|
+
## The pure function
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
type RouteDecision =
|
|
11
|
+
| { realmSlug: string, verificationMode: 'jwks' | 'introspection' }
|
|
12
|
+
| 'notThisIssuer';
|
|
13
|
+
|
|
14
|
+
type RouteFn = (request: RequestLike) => RouteDecision;
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`RequestLike` is what the project's HTTP framework exposes at the middleware boundary. The blueprint does not commit to a specific shape (Express's `req`, Fastify's `request`, Hono's `c.req`, Workers' `Request`); the routeFn adapts to whatever the project's framework provides.
|
|
18
|
+
|
|
19
|
+
## Single-realm deployment
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
const routeFn = () => ({ realmSlug: 'r1', verificationMode: 'jwks' });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The reference wiring includes this constant-realmSlug default for the common single-realm case. The overhead is one function call per request and one config-record lookup; the payoff is that the same seam exists in every deployment shape, so upgrading from single-realm to multi-realm is a routeFn swap, not a code rewrite.
|
|
26
|
+
|
|
27
|
+
## Multi-realm deployment (two Keycloak realms)
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
const routeFn = (request) => {
|
|
31
|
+
const marker = readMarker(request); // project-specific: header, path prefix, claim, or other
|
|
32
|
+
if (marker === undefined) {
|
|
33
|
+
return { realmSlug: 'r1', verificationMode: 'jwks' }; // project's declared default
|
|
34
|
+
}
|
|
35
|
+
return { realmSlug: marker, verificationMode: 'jwks' };
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The MARKER is the project's own concern. The blueprint refuses to name it: a project might use a header, a request-path prefix, a preflight claim, a tenant slug from a subdomain, or something else entirely. The routeFn inspects the request and picks; the mechanism honours the pick.
|
|
40
|
+
|
|
41
|
+
## Deployment where routing hands off
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
const routeFn = (request) => {
|
|
45
|
+
if (isThisMechanismsResponsibility(request)) {
|
|
46
|
+
return { realmSlug: 'r1', verificationMode: 'jwks' };
|
|
47
|
+
}
|
|
48
|
+
return 'notThisIssuer';
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
A project whose middleware chain also verifies tokens from another OAuth2/OIDC issuer above this blueprint's mechanism reach returns the sentinel `notThisIssuer` when the request is not for this mechanism to verify. The caller (the project's own middleware) is responsible for what happens next; the mechanism does not know and does not care.
|
|
53
|
+
|
|
54
|
+
The blueprint does NOT contribute an ADR that fixes what a project puts in `isThisMechanismsResponsibility`. That is the project-level decision the ratified reshape ruling reserves for the project. The seam is the mechanism's contribution; the routing policy is the project's.
|
|
55
|
+
|
|
56
|
+
## Why the sentinel exists
|
|
57
|
+
|
|
58
|
+
Without it, the mechanism would have to guess: either refuse the request (which would break a deployment where a token from another issuer is expected on that path) or trust it (which would break the security posture). The sentinel makes the hand-off explicit and paper-trailed; the routeFn is where a reviewer looks to see which requests this mechanism owns.
|
|
59
|
+
|
|
60
|
+
## What the routeFn must NOT do
|
|
61
|
+
|
|
62
|
+
- Perform any HTTP request. The routeFn is pure; network I/O belongs on the verifiers, not the router.
|
|
63
|
+
- Read or mutate the session-record store. That is the session-bridge's territory.
|
|
64
|
+
- Name a specific second issuer inside the shipped mechanism. A project that has one names it on a project-level ADR whose scope is the project, not the blueprint.
|
|
65
|
+
|
|
66
|
+
## What the routeFn MAY do
|
|
67
|
+
|
|
68
|
+
- Read request fields (headers, path, method, cookies, query parameters).
|
|
69
|
+
- Consult a project-authored in-process lookup (a tenant registry the project maintains, a rules table the operator loaded at boot).
|
|
70
|
+
- Return a stable realmSlug per request feature that maps to a realm record.
|
|
71
|
+
- Return the sentinel when the project's middleware chain owns the decision above this mechanism.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Realm-config record: shape
|
|
2
|
+
|
|
3
|
+
The plain data record a project maintains per configured realm. TAC-1201 validates the shape at boot; TAC-1202, TAC-1203, and TAC-1205 read from it on the hot path.
|
|
4
|
+
|
|
5
|
+
All fields below are declared with placeholder or example values; a project populates them from a realm the operator runs. The `clientSecret` is server-only and NEVER committed - the record reads it from `security-secrets-management` (when composed) or from the process environment at boot.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
{
|
|
9
|
+
realmSlug: 'r1',
|
|
10
|
+
issuerBaseUrl: 'http://127.0.0.1:8080',
|
|
11
|
+
realmName: 'example',
|
|
12
|
+
clientId: 'example-client',
|
|
13
|
+
clientSecret: '<PLACEHOLDER_CLIENT_SECRET>',
|
|
14
|
+
verificationMode: 'jwks',
|
|
15
|
+
roleClaimShape: 'client-roles',
|
|
16
|
+
scopes: ['openid', 'profile', 'email'],
|
|
17
|
+
redirectUri: '<PLACEHOLDER_PROJECT_CALLBACK_URL>',
|
|
18
|
+
providerLogout: 'none',
|
|
19
|
+
sessionMode: 'opaque-handle',
|
|
20
|
+
bearerSource: null,
|
|
21
|
+
jwksCacheTtlSeconds: 900,
|
|
22
|
+
introspectionCacheTtlSeconds: 0,
|
|
23
|
+
bootPosture: 'strict',
|
|
24
|
+
deferredRetryCapSeconds: 300,
|
|
25
|
+
discoveryRefreshSeconds: 3600,
|
|
26
|
+
enabled: true
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Field notes
|
|
31
|
+
|
|
32
|
+
- `realmSlug` is a project-local stable slug; it appears in `principalId` derivations and in every audit event. Short and lowercase; do not use the operator's realm name here (that is `realmName`).
|
|
33
|
+
- `issuerBaseUrl` is the URL prefix Keycloak reports as the realm's issuer, up to but not including `/realms/<realm>`. The discovery client appends `/realms/<realmName>/.well-known/openid-configuration`.
|
|
34
|
+
- `verificationMode` is `'jwks'` (default) or `'introspection'`. See ADR-1202.
|
|
35
|
+
- `roleClaimShape` is `'client-roles'` (reads `resource_access.<clientId>.roles`) or `'realm-roles'` (reads `realm_access.roles`). See REQ-006 and TAC-1205.
|
|
36
|
+
- `providerLogout` is `'none'` (default; sign-out clears the project session only) or `'redirect'` (sign-out returns a 302 to the realm's `end_session_endpoint`). A record with `'redirect'` on a realm whose discovery lacks `end_session_endpoint` refuses boot. See REQ-010 and ADR-1206.
|
|
37
|
+
- `sessionMode` is `'opaque-handle'` (the default; server-side session record + opaque cookie) or `'stateless'` (per-request bearer verification, no session record). See ADR-1204.
|
|
38
|
+
- `bearerSource` is required when `sessionMode='stateless'`: `'authorization-header'` or `'cookie:<name>'`.
|
|
39
|
+
- `jwksCacheTtlSeconds` is 900 by default; the record may raise (up to 86400) or lower (down to 60). See ADR-1205.
|
|
40
|
+
- `introspectionCacheTtlSeconds` is 0 by default (no cache); the record may raise for high-issuance realms. See TAC-1203.
|
|
41
|
+
- `bootPosture` is `'strict'` (default), `'deferred'`, or `'standby'`. See REQ-011 and TAC-1201.
|
|
42
|
+
- `discoveryRefreshSeconds` is the background refresh cadence (default 3600); a failure at refresh logs a warning and does not flip a healthy realm to unhealthy.
|
|
43
|
+
- `enabled: false` marks the record as configured but not routed to; the provider-router skips disabled records.
|
|
44
|
+
|
|
45
|
+
## Multiple realms
|
|
46
|
+
|
|
47
|
+
A project may declare N realm records. Each carries its own `realmSlug` and its own set of the fields above. The provider-router (TAC-1204) uses a project-authored `routeFn` to decide which realmSlug a request routes to. A project with only one realm passes a constant `routeFn`; the reference wiring ships that constant.
|
|
48
|
+
|
|
49
|
+
## Rejection classes at boot
|
|
50
|
+
|
|
51
|
+
- Missing required field: `KEYCLOAK_RECORD_INCOMPLETE` naming the field.
|
|
52
|
+
- `verificationMode='introspection'` on a discovery without `introspection_endpoint`: `KEYCLOAK_DISCOVERY_MISSING_ENDPOINT`.
|
|
53
|
+
- `providerLogout='redirect'` on a discovery without `end_session_endpoint`: `KEYCLOAK_LOGOUT_NOT_DECLARED`.
|
|
54
|
+
- `sessionMode='stateless'` without `bearerSource`: `KEYCLOAK_BEARER_SOURCE_MISSING`.
|
|
55
|
+
- `jwksCacheTtlSeconds` outside `[60, 86400]`: `KEYCLOAK_JWKS_TTL_OUT_OF_RANGE`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "security-auth-keycloak",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "security",
|
|
5
|
+
"contributions": [
|
|
6
|
+
{ "id": "security-auth-keycloak-REQ-001", "kind": "req", "path": "requirements/security-auth-keycloak-req-001.json" },
|
|
7
|
+
{ "id": "security-auth-keycloak-REQ-002", "kind": "req", "path": "requirements/security-auth-keycloak-req-002.json" },
|
|
8
|
+
{ "id": "security-auth-keycloak-REQ-003", "kind": "req", "path": "requirements/security-auth-keycloak-req-003.json" },
|
|
9
|
+
{ "id": "security-auth-keycloak-REQ-004", "kind": "req", "path": "requirements/security-auth-keycloak-req-004.json" },
|
|
10
|
+
{ "id": "security-auth-keycloak-REQ-005", "kind": "req", "path": "requirements/security-auth-keycloak-req-005.json" },
|
|
11
|
+
{ "id": "security-auth-keycloak-REQ-006", "kind": "req", "path": "requirements/security-auth-keycloak-req-006.json" },
|
|
12
|
+
{ "id": "security-auth-keycloak-REQ-007", "kind": "req", "path": "requirements/security-auth-keycloak-req-007.json" },
|
|
13
|
+
{ "id": "security-auth-keycloak-REQ-008", "kind": "req", "path": "requirements/security-auth-keycloak-req-008.json" },
|
|
14
|
+
{ "id": "security-auth-keycloak-REQ-009", "kind": "req", "path": "requirements/security-auth-keycloak-req-009.json" },
|
|
15
|
+
{ "id": "security-auth-keycloak-REQ-010", "kind": "req", "path": "requirements/security-auth-keycloak-req-010.json" },
|
|
16
|
+
{ "id": "security-auth-keycloak-REQ-011", "kind": "req", "path": "requirements/security-auth-keycloak-req-011.json" },
|
|
17
|
+
{ "id": "security-auth-keycloak-REQ-012", "kind": "req", "path": "requirements/security-auth-keycloak-req-012.json" },
|
|
18
|
+
{ "id": "security-auth-keycloak-US-11101", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11101.json" },
|
|
19
|
+
{ "id": "security-auth-keycloak-US-11102", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11102.json" },
|
|
20
|
+
{ "id": "security-auth-keycloak-US-11103", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11103.json" },
|
|
21
|
+
{ "id": "security-auth-keycloak-US-11104", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11104.json" },
|
|
22
|
+
{ "id": "security-auth-keycloak-US-11105", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11105.json" },
|
|
23
|
+
{ "id": "security-auth-keycloak-US-11106", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11106.json" },
|
|
24
|
+
{ "id": "security-auth-keycloak-US-11107", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11107.json" },
|
|
25
|
+
{ "id": "security-auth-keycloak-US-11108", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11108.json" },
|
|
26
|
+
{ "id": "security-auth-keycloak-US-11109", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11109.json" },
|
|
27
|
+
{ "id": "security-auth-keycloak-US-11110", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11110.json" },
|
|
28
|
+
{ "id": "security-auth-keycloak-US-11111", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11111.json" },
|
|
29
|
+
{ "id": "security-auth-keycloak-US-11112", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11112.json" },
|
|
30
|
+
{ "id": "security-auth-keycloak-US-11113", "kind": "us", "path": "user-stories/security-auth-keycloak-us-11113.json" },
|
|
31
|
+
{ "id": "TAC-1201-security-auth-keycloak-discovery-client", "kind": "tac", "path": "tacs/tac-1201-security-auth-keycloak-discovery-client.json" },
|
|
32
|
+
{ "id": "TAC-1202-security-auth-keycloak-jwt-verifier", "kind": "tac", "path": "tacs/tac-1202-security-auth-keycloak-jwt-verifier.json" },
|
|
33
|
+
{ "id": "TAC-1203-security-auth-keycloak-introspection-client", "kind": "tac", "path": "tacs/tac-1203-security-auth-keycloak-introspection-client.json" },
|
|
34
|
+
{ "id": "TAC-1204-security-auth-keycloak-provider-router", "kind": "tac", "path": "tacs/tac-1204-security-auth-keycloak-provider-router.json" },
|
|
35
|
+
{ "id": "TAC-1205-security-auth-keycloak-role-adapter", "kind": "tac", "path": "tacs/tac-1205-security-auth-keycloak-role-adapter.json" },
|
|
36
|
+
{
|
|
37
|
+
"id": "ADR-1201-security-auth-keycloak-auth-model",
|
|
38
|
+
"kind": "adr",
|
|
39
|
+
"path": "adrs/adr-1201-security-auth-keycloak-auth-model.json",
|
|
40
|
+
"scope": "global",
|
|
41
|
+
"topic": "authModel"
|
|
42
|
+
},
|
|
43
|
+
{ "id": "ADR-1202-security-auth-keycloak-verification-mode-choice", "kind": "adr", "path": "adrs/adr-1202-security-auth-keycloak-verification-mode-choice.json" },
|
|
44
|
+
{ "id": "ADR-1203-security-auth-keycloak-provider-routing-seam", "kind": "adr", "path": "adrs/adr-1203-security-auth-keycloak-provider-routing-seam.json" },
|
|
45
|
+
{ "id": "ADR-1204-security-auth-keycloak-session-vs-token-contract", "kind": "adr", "path": "adrs/adr-1204-security-auth-keycloak-session-vs-token-contract.json" },
|
|
46
|
+
{ "id": "ADR-1205-security-auth-keycloak-jwks-rotation-cache-lifetime", "kind": "adr", "path": "adrs/adr-1205-security-auth-keycloak-jwks-rotation-cache-lifetime.json" },
|
|
47
|
+
{ "id": "ADR-1206-security-auth-keycloak-refresh-and-sign-out-posture", "kind": "adr", "path": "adrs/adr-1206-security-auth-keycloak-refresh-and-sign-out-posture.json" }
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-1201-security-auth-keycloak-auth-model",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "A Keycloak realm is the project's identity source; federation is OIDC authorisation-code + PKCE with per-realm verification mode",
|
|
8
|
+
"context": "A project has one authentication model; the client tier, the server tier, and every operator surface must reason against it. The security-auth-keycloak blueprint contributes a vendor-committed shape of that model: identity, sign-in surface, credential storage, MFA, and account recovery live at a Keycloak realm the operator runs; the project owns the discovery client, the token verifier (JWKS or introspection depending on the realm's client configuration), the role adapter, the provider-router seam, and the optional application session on top. Every other auth-family blueprint (security-auth-magic-link, security-auth-clerk, security-auth-oauth2) contributes its own decision on this topic; blueprint composition surfaces the pairing at add time for the operator to reconcile into one project-level model. That surfacing is intended.",
|
|
9
|
+
"decision": "The project's authentication model is delegated identity to a Keycloak realm the operator runs, federated through OAuth2 authorisation-code with PKCE (RFC 7636, S256), with the realm's OIDC endpoints resolved through discovery (REQ-002). Every access token the project receives from the realm is verified either through JWKS (default, REQ-003) or through the RFC 7662 introspection endpoint (opt-in per realm, REQ-004); the verification mode is a per-realm-record field. Roles are read from Keycloak's client-roles or realm-roles claim path per the realm's configuration (REQ-006); the project's own handlers see only the reduced Principal. The application session posture on top of the verified token stream is either an opaque-handle session cookie (the default, mirroring the sibling blueprints' opaque-handle contract) or stateless bearer verification per request; the operator picks one per realm record (REQ-008). Refresh follows the realm's rotation model (REQ-007). Sign-out invalidates the project session; realm-side sign-out is a project option (REQ-010). Fail-safe boot follows a declared posture (REQ-011). Runtime-verify binds against a local Keycloak container; live cloud-tenant smokes are accountBound (REQ-012). The blueprint contributes a provider-routing seam (REQ-005) that a project's own middleware may use to route requests to one of several issuers; the seam is described in generic OAuth2/OIDC vocabulary and does not itself commit the blueprint to any specific second issuer.",
|
|
10
|
+
"consequences": "The project owns the discovery client, the token verifier, the role adapter, the session-bridge (opaque-handle mode) or the bearer verifier (stateless mode), the provider-router seam, and the optional local-container harness for runtime-verify; the realm owns the sign-in surface, the credential storage, MFA, account recovery, refresh-token issuance policy, role assignments, and the whole admin console. A realm swap is a discovery-record refresh plus (if the client configuration changed) a re-choice of `verificationMode`; the project's code path does not change. Composing with another auth-family blueprint conflicts on this topic by design; the expected resolution is one project-level ADR that fixes the identity surface and the credential shape for the whole project. The local-container runtime-verify posture makes CI honest without demanding cloud-realm credentials; a project that has a cloud realm wires it on top and the accountBound smokes light up. Every path that produces or consumes a session record (opaque-handle mode) or that reads a bearer token (stateless mode) flows through one narrow set of modules the ship gate compels.",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Vendor-neutral OAuth2 authorisation-code + PKCE (security-auth-oauth2)",
|
|
14
|
+
"summary": "The sibling blueprint's model: keep the flow (authorisation-code + PKCE) but do not commit to a vendor; let the project drop in any conforming IdP through a fixed provider-abstraction record.",
|
|
15
|
+
"reasonNotChosen": "Right choice for projects that are not committed to a single vendor. This blueprint is for projects that have committed to Keycloak: they want the Keycloak-shaped decisions (JWKS vs introspection, client-roles vs realm-roles, local-container stand-up, RP-initiated logout through the realm's end_session_endpoint) fixed at the mechanism layer so the project code path can name a Keycloak realm rather than an abstract provider record."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Hosted identity vendor with vendor-committed shape (security-auth-clerk)",
|
|
19
|
+
"summary": "The Clerk sibling: Clerk hosts the sign-in surface, the credential storage, MFA, account recovery; the project runs a middleware boundary against Clerk's session-verification API.",
|
|
20
|
+
"reasonNotChosen": "Valid for projects that want a hosted-identity fast lane. This blueprint targets the operator who wants self-hosted control over the realm and the admin surface, or who has an existing Keycloak deployment they cannot displace. The Clerk lane trades vendor commitment for less operator work; the Keycloak lane trades operator work for full self-hosted control."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Passwordless magic-link with server-issued opaque cookie sessions (security-auth-magic-link)",
|
|
24
|
+
"summary": "The magic-link sibling's model: mint a single-use token on POST /login, deliver by email, verify on GET /login/verify, issue an opaque-handle session cookie.",
|
|
25
|
+
"reasonNotChosen": "Valid for projects with no third-party identity dependency and the willingness to own the whole authentication surface in-house. This blueprint delegates that surface entirely to the realm; the trade against magic-link is running a Keycloak realm rather than an in-process principal registry."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "Hand-wire the Keycloak flow inside the project without a mechanism-level record",
|
|
29
|
+
"summary": "Keep the Keycloak URLs, client id, secret, and JWKS knowledge inline in project code; no discovery, no per-realm record, no injected verifier.",
|
|
30
|
+
"reasonNotChosen": "Cheap on day one and expensive on day thirty: the realm URL layout changes, the client configuration changes to opaque tokens, the operator introduces a second realm, or the deployment moves to a different hostname. Every one of those is a code edit rather than a record refresh; the injected verifier + discovery record shape pays back the abstraction cost by the second such change."
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"createdAt": "2026-08-31T00:00:00Z",
|
|
34
|
+
"updatedAt": "2026-08-31T00:00:00Z"
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-1202-security-auth-keycloak-verification-mode-choice",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Verification mode is a per-realm-record choice between JWKS (default) and RFC 7662 introspection",
|
|
8
|
+
"context": "Keycloak clients issue either JWT access tokens (verifiable off-line against the realm's JWKS) or opaque access tokens (verifiable only through the RFC 7662 introspection endpoint). The choice is made at the Keycloak client configuration layer (Access Token Signature vs Bearer-only clients using opaque handles) and each has legitimate operational reasons. A blueprint that fixes one mode fights half the deployments. A blueprint that lets a project mix modes at random inside one realm record blurs the mechanism.",
|
|
9
|
+
"decision": "The realm record carries a `verificationMode` field with two legal values: `jwks` (the default) and `introspection`. The verifier reads the field once per verification and dispatches to the JWT verifier (TAC-1202) or the introspection client (TAC-1203) accordingly. A single realm record carries a single mode; a project whose realm has both kinds of clients declares one realm record per client and routes through the provider-router seam (REQ-005). The default is JWKS because JWKS is cheap on the hot path and matches the more common Keycloak client configuration; introspection is opt-in per record.",
|
|
10
|
+
"consequences": "The verifier stays single-branched inside one realm record. The role adapter (TAC-1205) reads roles from the verified claims in both modes (the introspection response body is claim-shaped identically to the id_token payload for role-carrying paths). The operator's mode choice is legible on the record and does not require a code path change to swap; a realm reconfigured from JWT to opaque tokens is a `verificationMode` field flip on the record plus a discovery re-fetch (introspection_endpoint appears on discovery in both modes but its use only matters in introspection mode). Runtime-verify covers both modes; the JWKS path binds against a real local Keycloak container and the introspection path binds against a local stub responder (or a second local realm configured for opaque tokens, per project preference).",
|
|
11
|
+
"alternativesConsidered": [
|
|
12
|
+
{
|
|
13
|
+
"name": "JWKS only (fix the mode at the mechanism layer)",
|
|
14
|
+
"summary": "Refuse to support introspection at all; every client must be configured to issue JWTs.",
|
|
15
|
+
"reasonNotChosen": "Excludes deployments that legitimately prefer opaque tokens (some regulated environments require server-side revocation reflection with no JWT-in-flight window). Fixing a mode at the mechanism boundary is exactly the vendor-lock this blueprint is designed to accept for Keycloak specifically, not for token shape."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Introspection only (fix the mode at the mechanism layer)",
|
|
19
|
+
"summary": "Every access token is verified through the introspection endpoint on every request.",
|
|
20
|
+
"reasonNotChosen": "Trades a documented performance property for one policy uniformity. Introspection is one HTTP round-trip per verification against the realm; the hot-path cost is unacceptable on any deployment where the JWKS-cached path would satisfy the operator's revocation posture."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Auto-detect the mode from the token shape at first receipt",
|
|
24
|
+
"summary": "Peek at the token; if it parses as a JWT with valid header, run JWKS; otherwise run introspection.",
|
|
25
|
+
"reasonNotChosen": "The mode is not the token's decision to make; it is the realm operator's. Auto-detect makes the mechanism reason about the operator's realm configuration in code rather than on the record, and a realm reconfigured mid-deployment would flip modes without a paper trail. Naming the choice on the record makes it observable and reviewable."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"createdAt": "2026-08-31T00:00:00Z",
|
|
29
|
+
"updatedAt": "2026-08-31T00:00:00Z"
|
|
30
|
+
}
|