A state-of-the-art, enterprise-grade, product-agnostic hexagonal security platform built on Spring Security 6 and Project Reactor (WebFlux). It replaces and absorbs the legacy
fireflyframework-security-idpbroker and the custom resource-server / authorization code that was scattered acrossfireflyframework-starter-applicationandfireflyframework-backoffice.
- Group / versioning:
org.fireflyframework, CalVer26.MM.PP(aligned withfireflyframework-parent, currently26.06.01). - Stack: Java 21+, Spring Boot 3.x, Spring Security 6.x, Project Reactor. Servlet is confined to the optional authorization server.
- Design spec:
docs/superpowers/specs/2026-06-18-fireflyframework-security-design.md. - Status: 14 modules, all GREEN, published to
github.com/fireflyframework. Every SPI port has a real adapter. Five integration tests run against live Docker containers (Postgres, OPA, Cerbos, OpenFGA, Vault). The IdP and application/backoffice de-domaining is complete. Only the cloud key/secret adapters (aws-kms,azure-keyvault) remain planned.
Firefly's "security" used to be two disconnected halves that never actually talked to each other, sitting on top of a framework that had no real authentication enforcement:
- Half 1 — the IdP broker (
fireflyframework-security-idp+ four vendor adapters). A single fat reactive port (IdpAdapter, 21 methods plus a defaultregisterUser) with 24 vendor-neutral DTOs and a 1:1 passthroughIdpControllerunder/idp. The provider was chosen byfirefly.idp.provider: keycloak (Admin Client + WebClient OIDC), aws-cognito (sync SDK v2), azure-ad (MSAL4J + Microsoft Graph), and internal-db (a real first-party auth service: R2DBC store, BCrypt(12), JJWT HS256, lockout, password policy/reset, TOTP). - Half 2 — resource-server / authz (custom code in
starter-applicationandbackoffice). A bespoke AOP scheme:@Secure+SecurityAspect→SecurityAuthorizationService, anEndpointSecurityRegistry, anAbstractSecurityConfigurationDSL, aJwtClaimsRoleExtractor, aSessionManager/SessionContext"Security Center" SPI, and anAppContextprincipal facade.
The concrete defects this platform was built to close:
- No Spring Security in the framework. No
oauth2ResourceServer, noReactiveJwtDecoder, noSecurityWebFilterChain, no method security, no JWKS. Onlyspring-security-crypto(BCrypt in internal-db) and aSecurityExceptionConvertermapping Spring Security exceptions into the kernel's RFC-7807 envelope were present. - Inbound JWT signatures were never validated. The azure-ad and keycloak adapters
"introspected" tokens by decoding them locally with no signature / issuer / audience
checks — a forged token reported
active=true. - Identity entered via a trusted
X-Party-Idheader. The framework assumed an Istio/gateway had already terminated and verified the JWT, so any off-mesh caller could spoof an identity by setting a header. - Fail-open by default.
@Securesilently skipped when no context argument was present; there was no global default-deny;security.enforcecould turn enforcement off; and the starter pulled inspring-boot-starter-securitywith no chain, silently leaking Boot's HTTP-Basic default. - The two halves did not connect. Obtaining a token from
/idpdid nothing to populate theAppContextthat the authorization aspect checked. - firefly-oss product-domain leakage.
X-Party-Id,partyId, the business-role enum (UserRoleEnum:AGENT/SUPER_AGENT/DISTRIBUTOR/ADMIN), and a Contract/Product/RoleScope "Security Center" session model — all firefly-oss product-family concepts — were baked into framework code.
The Python (fireflyframework-pyfly) and Rust (fireflyframework-rust) ports already ship the
target shape: a security tier (Verifier / BearerLayer / FilterChain / OAuth2) cleanly separated
from an idp tier, joined by one thin token-validation seam. That was the alignment target for
this Java platform, and it has now been met.
The platform is a strict hexagon. Dependencies flow inward only; the core never imports a vendor SDK, and every provider is an adapter behind an SPI.
api ──► spi ──► core ──► webflux ──► delivery ──► starters
▲ (resource-server, │
│ method-policy, │
│ oauth2-client, │
│ authorization-server) │
└──────────────── adapters ◄─────────────┘
(opa · cerbos · openfga · vault · r2dbc)
idp tier ──[ TokenValidationPort ]──► security tier
api— driving ports (inbound use-cases) and the product-agnostic domain model:SecurityPrincipal,Decision/Obligation,BearerToken,SigningKey,TrustedIssuer,SecurityAuditEvent, the@Secureannotation,AuthenticateUseCase/AuthorizeUseCase, and security exceptions (TokenValidationException,UnsupportedSecurityOperationException). No Spring web or provider dependencies.spi— driven ports (interfaces only): the outbound contracts the core depends on.core— the framework-neutral engine: default token validators, authority normalization (absorbsJwtClaimsRoleExtractor), the@Secureauthorization evaluator (fixed AND-semantics, real SpEL, default-deny), an embedded fail-closed policy decision adapter, an in-memory key/JWKS adapter, the bearer-token extractor, an introspection cache, and decorators. No provider or web-stack lock-in.webflux— reactive bindings:ServerHttpSecuritywiring, aPolicyAuthorizationManagerURL PEP, aFireflyAuthenticationToken, and a Reactor-Context-backedSecurityContextPortaccessor (ReactorSecurityContextAdapter).- delivery — the four feature modules that bind the engine to a runnable Spring stack:
resource-server,method-policy,oauth2-client,authorization-server. - starters —
fireflyframework-starter-applicationpulls the delivery modules so apps are secure by default; standalone services add the resource-server directly. - adapters — one external SDK per adapter, each depending only on
spi.
The idp tier and the security tier connect through exactly one SPI:
public interface TokenValidationPort {
Mono<SecurityPrincipal> validate(BearerToken token);
}It validates a presented bearer token — signature / issuer / audience / expiry for JWTs, RFC 7662
introspection for opaque tokens — and projects it into a SecurityPrincipal. It never returns
an unvalidated principal: any validation failure raises TokenValidationException. This mirrors
the pyfly/rust ports and keeps the two tiers decoupled; the IdP tier
(fireflyframework-security-idp + the Keycloak / Cognito / Entra / internal-db providers) knows nothing
about the security chain, and vice versa.
SecurityPrincipal is an immutable record and the framework's stack-neutral principal facade —
a projection of a signature-validated authentication:
SecurityPrincipal { subject, issuer, tenantId?, authorities: Set<String>, scopes: Set<String>,
claims: Map<String,Object>, authTime?, acr?, amr, attributes: Map<String,Object> }
It deliberately carries no party, contract, or product. Products enrich it through
PrincipalAttributeContributorPort and read their own domain off claims() / attributes(). It
is propagated end-to-end via the Reactor Context.
14 modules, all GREEN. Each was built and tested with
mvn -o test(exit 0), each carries at least one test, and the five infrastructure-backed adapters each carry a real-Docker integration test (see §7).
| Module | One line |
|---|---|
fireflyframework-security-api |
Driving ports + product-agnostic domain: SecurityPrincipal, Decision/Obligation, BearerToken, SigningKey, TrustedIssuer, SecurityAuditEvent, @Secure, Authenticate/AuthorizeUseCase, security exceptions. |
fireflyframework-security-spi |
The 13 driven ports (interfaces only) — the complete outbound contract surface the core depends on. |
fireflyframework-security-core |
The vendor-neutral engine: ConfigurableAuthorityMapper, SecureAuthorizationEvaluator, EmbeddedPolicyDecisionAdapter (+PolicyRule), InMemoryKeyManagementAdapter, CaffeineIntrospectionCache, BearerTokenExtractor, LoggingAuditEventAdapter, PrincipalFactory. |
fireflyframework-security-webflux |
Reactive bindings: FireflyAuthenticationToken, PolicyAuthorizationManager (URL PEP), ReactorSecurityContextAdapter (SecurityContextPort), PrincipalSupport. |
| Module | One line |
|---|---|
fireflyframework-security-resource-server |
Secure-by-default reactive OAuth2 resource server: ResourceServerAutoConfiguration (Nimbus verifying JWT decoder from KeyManagementPort, JwtToFireflyPrincipalConverter, default-deny chain, hardened headers) + ResourceServerProperties. |
fireflyframework-security-method-policy |
Reactive method security: MethodSecurityAutoConfiguration (@EnableReactiveMethodSecurity) + SecureMethodAuthorizationManager backing @Secure and @PreAuthorize with the core evaluator, fail-closed. |
fireflyframework-security-oauth2-client |
Reactive OAuth2/OIDC client (BFF): OAuth2ClientAutoConfiguration for authorization_code + PKCE, client_credentials, refresh, and a WebClient token-relay filter. |
fireflyframework-security-authorization-server |
Servlet-only Spring Authorization Server (AuthorizationServerConfiguration): OIDC discovery, JWKS, PKCE and grants, keys sourced from KeyManagementPort. Deployed separately from reactive resource servers. |
| Module | Implements | One line |
|---|---|---|
fireflyframework-security-adapter-opa |
PolicyDecisionPort |
OpaPolicyDecisionAdapter — Open Policy Agent (Rego) ABAC, fail-closed. |
fireflyframework-security-adapter-cerbos |
PolicyDecisionPort |
CerbosPolicyDecisionAdapter — Cerbos policy-as-code ABAC, fail-closed. |
fireflyframework-security-adapter-openfga |
RelationshipPort |
OpenFgaRelationshipAdapter — Zanzibar-style ReBAC relationship checks. |
fireflyframework-security-adapter-vault |
SecretsPort |
VaultSecretsAdapter — HashiCorp Vault secret retrieval, fail-closed at startup. |
fireflyframework-security-adapter-r2dbc |
RevocationPort |
R2dbcRevocationAdapter — relational/R2DBC token revocation list (no external cache server required). |
| Module | One line |
|---|---|
fireflyframework-security-test |
TestPrincipals factories and a configurable FakePolicyDecisionPort for asserting permit/deny paths without a live PDP. |
Plus the refactored IdP tier: fireflyframework-security-idp no longer carries UserRoleEnum or
partyId, its fat IdpAdapter is segregated into six capability ports (with NotSupported
defaults so all four provider adapters still build), and fireflyframework-security-idp-keycloak no longer
writes a partyId/userRole user attribute.
Every driven port has at least one real adapter — there are no orphan interfaces. The container icon (🐳) marks adapters proven against a live service via Testcontainers.
| SPI port | Responsibility | Delivered adapter(s) | Planned |
|---|---|---|---|
TokenValidationPort |
The idp↔security seam. Validate a bearer → SecurityPrincipal; JWT → verifying decoder + JWKS, opaque → idp introspection + cache. |
resource-server decoder (in-process RS256); idp TokenIntrospectionPort bridge |
— |
KeyManagementPort |
Active/next signing keys, kid, JWKSource, rotation-with-overlap. |
InMemoryKeyManagementAdapter (core; dev + in-proc RS256) |
aws-kms, azure-keyvault |
SecretsPort |
Fetch secrets, lease renewal, fail-closed at startup. | VaultSecretsAdapter 🐳 (Vault) |
aws-kms, azure-keyvault |
PolicyDecisionPort |
ABAC decide → PERMIT/DENY/INDETERMINATE + obligations, fail-closed. | EmbeddedPolicyDecisionAdapter (core); OpaPolicyDecisionAdapter 🐳; CerbosPolicyDecisionAdapter 🐳 |
— |
RelationshipPort |
Zanzibar-style check(subject, relation, object) ReBAC. |
OpenFgaRelationshipAdapter 🐳 (OpenFGA) |
— |
RevocationPort |
Token/session revocation checks. | R2dbcRevocationAdapter 🐳 (PostgreSQL) |
— |
AuthorityMappingPort |
Claims → authorities/scopes (dot-path config). | ConfigurableAuthorityMapper (core) |
— |
TokenIntrospectionCachePort |
Cache opaque introspection, TTL bounded by exp. |
CaffeineIntrospectionCache (core) |
— |
SecurityContextPort |
Read the current validated principal (Reactor-context backed). | ReactorSecurityContextAdapter (webflux) |
— |
AuditEventPort |
Sink for auth success/failure/denied/token/key events. | LoggingAuditEventAdapter (core) |
— |
IssuerRegistryPort |
Trusted issuers + per-issuer decoder. | resource-server issuer wiring | — |
TenantResolverPort |
Resolve tenant from the request/principal into Reactor Context. | resource-server / core | — |
PrincipalAttributeContributorPort |
Product extension seam — enrich principal attributes/claims. | product-supplied (firefly-oss re-introduces its domain here) | — |
The only items still on the planned list are the cloud key/secret backends (aws-kms,
azure-keyvault); they are provider variants of KeyManagementPort/SecretsPort that cannot be
exercised against a local container, so they are deferred behind the in-memory key source and the
Vault secrets adapter that already cover today's needs.
The whole point of the platform is to close the fail-open posture. There is no shadow mode and no audit-only mode — the defaults are hard, and an application opts out of a route, never into enforcement:
- Default-deny. The auto-configured
SecurityWebFilterChainends inanyExchange().access(policyManager); nothing is reachable unless explicitly permitted. - Validated bearer always. Every request is authenticated by an in-process verifying JWT
decoder built from
KeyManagementPort, withiss/aud/ timestamp validators wired in. - Fail-closed everywhere. PDP and introspection errors deny (never permit-on-error). A failing
or throwing
@SecureSpEL expression denies. Anullprincipal is always denied. - Gateway-trusted headers are gone.
X-Party-Idis removed from the framework chain; identity comes only from a signature-validatedAuthentication. Mesh-internal callers must present a real bearer token. - No fail-open switch. The legacy
security.enforcebypass is removed; missing prod key sources fail startup rather than degrading silently. - Boot's auto HTTP-Basic chain is explicitly replaced —
httpBasic,formLogin, andlogoutare disabled on the reactive chain, so nothing leaks. - Hardened headers on every response — HSTS (1 year, includeSubdomains), a locked-down CSP
(
default-src 'none'; frame-ancestors 'none'),X-Frame-Options: DENY, and ano-referrerReferrer-Policy. CSRF is off for pure bearer APIs. - Named, explicit opt-outs only. Routes are permitted individually via
firefly.security.*permit matchers; there is no global "allow all". requireAllRoles/requireAllPermissionsare honored (the legacy aspect silently treated them as ANY).
Every bean in the resource-server auto-configuration is @ConditionalOnMissingBean, so
applications can override any single piece without losing the secure defaults for the rest.
The framework must be usable by any product, not just firefly-oss. The initiative purged every
firefly-oss domain concept framework-wide — from the IdP DTOs, from the application starter's
context/resolver/security stack, and from the parallel copy of that model in
fireflyframework-backoffice. (fireflyframework-r2dbc was already clean; lumen-lending samples
and firefly-oss doc references are legitimate product/sample code and out of scope.)
| Removed (firefly-oss leakage) | Where it lived | Replaced with (generic) |
|---|---|---|
X-Party-Id trusted-header identity |
DefaultContextResolver, AppContext, the *ContextResolvers, AbstractApplicationController/AbstractResourceController |
identity only from a signature-validated Authentication, read via SecurityContextPort / SecurityPrincipal |
partyId (UUID) field |
idp CreateUserRequest / IntrospectionResponse; keycloak IdpAdminServiceImpl (wrote a partyId attribute) |
subject (String) from the token; optional generic attributes: Map<String,Object> passthrough |
contractId / productId / scopeKey / subScopeKey |
AppContext, SessionContext, BackofficeContext, the *SessionContextMappers |
generic, nullable tenantId + open attributes map |
UserRoleEnum (AGENT/SUPER_AGENT/DISTRIBUTOR/ADMIN) |
idp dtos/enums/UserRoleEnum.java |
plain Set<String> authorities — enum deleted |
ContractInfoDTO, ProductInfoDTO, RoleScopeInfoDTO |
starter-application spi/dto |
deleted from the framework |
SessionManager "Security Center" SPI + SessionContext |
starter-application + backoffice | generic PolicyDecisionPort + AuthorityMappingPort + SecurityContextPort; firefly-oss re-implements its Security Center in its own code |
The product extension seam. PrincipalAttributeContributorPort lets firefly-oss (or any
product) re-introduce party/contract/product in its own codebase, reading them off
SecurityPrincipal.attributes() / JWT claims. The framework ships none of those fields.
fireflyframework-backoffice is refactored onto the generic SecurityPrincipal; its
party/contract context moves out to the product.
The platform is not asserted to work — it is shown to. Beyond unit / contract tests, eight integration tests exercise real cryptography and real services; five spin up genuine Docker containers via Testcontainers.
| Integration test | Container | What it proves |
|---|---|---|
R2dbcRevocationAdapterIntegrationTest |
postgres:16-alpine |
Persistence, active-vs-expired distinction, idempotent upsert, and not-revoked default through the real RevocationPort (wired via @DynamicPropertySource). |
OpaPolicyDecisionAdapterIntegrationTest |
openpolicyagent/opa:0.70.0 |
A Rego policy is PUT to the server, then permit (allowed action / admin subject), deny (disallowed action for a non-admin), and fail-closed for an undefined decision path. |
CerbosPolicyDecisionAdapterIntegrationTest |
cerbos/cerbos:latest |
The PolicyDecisionPort resolves real Cerbos PERMIT/DENY decisions, fail-closed on error. |
OpenFgaRelationshipAdapterIntegrationTest |
openfga/openfga:latest |
Zanzibar-style check() returns true/false against a real OpenFGA store through the RelationshipPort. |
VaultSecretsAdapterIntegrationTest |
hashicorp/vault:1.15 |
The SecretsPort reads/writes secrets against a live Vault, with fail-closed behavior on a missing path. |
| Integration test | Against | What it proves |
|---|---|---|
ResourceServerIntegrationTest |
in-process RS256 crypto, random port + WebTestClient |
A permit-matched route is open; a protected route is 401 without a token, 200 with a valid RS256 JWT signed by the active KeyManagementPort key (subject echoed), 401 for an expired or unknown-key token, 403 when a PolicyRule denies despite a valid token; hardened headers asserted present. |
AuthorizationServerIntegrationTest |
servlet @SpringBootTest, random port + TestRestTemplate |
The /.well-known/openid-configuration discovery document, the published /oauth2/jwks (RSA keys), and a real client_credentials exchange at /oauth2/token returning a signed-JWT Bearer token. |
OAuth2ClientCredentialsIntegrationTest |
WireMock token endpoint | The authorized-client manager performs a real client_credentials exchange and the resolved access-token value is asserted. |
MethodSecurityIntegrationTest |
reactive security context | @Secure and @PreAuthorize both enforce fail-closed: deny when unauthenticated, allow when the required authority is present, deny when missing, and leave unannotated methods open. |
The api, core, webflux, spi, and test modules add focused unit / contract tests:
SecurityPrincipalTest, DecisionTest, BearerTokenTest, SecureAuthorizationEvaluatorTest,
ConfigurableAuthorityMapperTest, EmbeddedPolicyDecisionAdapterTest,
InMemoryKeyManagementAdapterTest, CaffeineIntrospectionCacheTest,
PolicyAuthorizationManagerTest, ReactorSecurityContextAdapterTest, SpiContractTest, and
SecurityTestFixturesTest. The de-domained application starter passes its full 180-test suite
and the de-domained backoffice passes its 13-test suite.
The platform is wired into the framework's dependency and delivery plumbing through the parent and the single BOM, and shipped to applications through the starter.
- Dependency management — parent + BOM, in lockstep. Observability and the whole security
platform are version-managed in
fireflyframework-parent'sdependencyManagementand in the singlefireflyframework-bom. Both pin everyfireflyframework-security-*module (andspring-security-oauth2-authorization-server) to${project.version}(26.06.01). Consumers import the BOM (or inherit the parent) and never spell out versions. (A standalonefireflyframework-aggregatorreactor was briefly created and pushed, then deleted — local module and GitHub repo — in favor of this parent + BOM approach.) - Delivery — through the application starter.
fireflyframework-starter-applicationnow depends directly onfireflyframework-security-resource-serverandfireflyframework-security-method-policy, so every Firefly web app is locked down out of the box.security-resource-servertransitively pullssecurity-webflux→security-core→security-spi→security-api;security-method-policypullssecurity-core+security-webflux. Adding the starter therefore brings the whole secure chain. The resource server auto-configures only for reactive web apps and can be disabled withfirefly.security.resource-server.enabled=false.
With the application starter (secure-by-default). Any application-tier service is locked down
out of the box — default-deny, verifying JWT validation, hardened headers, and @Secure reactive
method security — with zero security code. The service only declares which routes are public.
Without the starter (standalone resource-server). A service not on the application starter
adds fireflyframework-security-resource-server directly (and -method-policy for @Secure).
It receives the identical ResourceServerAutoConfiguration. Because the auto-config is conditional
on a reactive web application and gated by a single property, it composes cleanly with any service.
Bearer token
→ security-webflux SecurityWebFilterChain
→ TokenValidationPort ──(JWT)──→ ReactiveJwtDecoder + JWKS(KeyManagementPort) + iss/aud/exp validators
──(opaque)→ idp TokenIntrospectionPort + TokenIntrospectionCachePort
→ SecurityPrincipal (validated) → ReactiveSecurityContextHolder + Reactor Context (tenant, correlation)
→ URL PEP: authorizeExchange (DEFAULT-DENY) + PolicyDecisionPort/RelationshipPort (ABAC/ReBAC, fail-closed)
→ Method PEP: @PreAuthorize / @Secure (security-method-policy)
→ controller / handler
AuditEventPort emits at each decision point.
Authorization composes RBAC (authorities/scopes at the URL and method layers) with optional ABAC
(PolicyDecisionPort: embedded default, OPA, or Cerbos) and ReBAC (RelationshipPort: OpenFGA).
The default policy engine is embedded and fail-closed; production swaps in an adapter by declaring
a bean. TokenValidationPort is the single join between the idp and security tiers.
14 new public repositories under github.com/fireflyframework, all pushed to main, all
GREEN: security-{api, spi, core, webflux, resource-server, method-policy, oauth2-client, authorization-server, test} and security-adapter-{opa, cerbos, openfga, vault, r2dbc}.
The IdP tier was renamed into the security family. The five identity-broker repositories were
migrated from fireflyframework-idp[-*] to fireflyframework-security-idp[-*] — GitHub repos
renamed (old URLs redirect), Maven artifactIds changed, and the Java base package moved from
org.fireflyframework.idp to org.fireflyframework.security.idp. The single BOM manages the new
coordinates. Verified locally with mvn -DskipTests clean package (BUILD SUCCESS) on every module.
Repository (fireflyframework-…) |
PR | Status | Change |
|---|---|---|---|
security-idp (was idp) |
#13 / #14 | merged | segregate the fat IdpAdapter into capability ports + de-domain DTOs; rename to security-idp |
bom |
#23 | merged | manage the renamed security-idp[-*] coordinates |
security-idp-keycloak (was idp-keycloak) |
#14 | open | rename to security-idp-keycloak (CI pending published base) |
security-idp-aws-cognito (was idp-aws-cognito) |
#13 | open | rename to security-idp-aws-cognito (CI pending published base) |
security-idp-azure-ad (was idp-azure-ad) |
#4 | open | rename to security-idp-azure-ad (CI pending published base) |
security-idp-internal-db (was idp-internal-db) |
#13 | open | rename to security-idp-internal-db (CI pending published base) |
bom |
#22 | open | manage the 14 security modules in the single BOM |
parent |
#30 | open | observability + security in dependencyManagement |
starter-application |
#12 | open | wire security + de-domain (180 tests green) |
backoffice |
#11 | open | de-domain off the party/contract context (13 tests green) |
claude-skills |
#1 | open | security skills + agent + security-idp rename |
The four provider rename PRs are correct and build green locally; their CI cannot resolve the
renamed base artifact until fireflyframework-security-idp is published, so they remain open
pending the next release. Nothing is released to GitHub Releases or Maven Central yet.
Most applications get all of this implicitly via
fireflyframework-starter-application. The snippets below show the explicit (standalone) form.
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-security-resource-server</artifactId>
</dependency>With fireflyframework-bom imported (or the parent inherited), the version is managed for you
(26.06.01). This pulls security-webflux → security-core → security-spi → security-api
transitively and activates ResourceServerAutoConfiguration. Depending on
fireflyframework-starter-application brings this plus security-method-policy automatically.
firefly:
security:
resource-server:
issuer: https://idp.example.com/ # adds a JwtIssuerValidator
audiences: [ my-api ] # adds an audience validator
role-claim-paths: [ realm_access.roles ] # dot-path claim → authority mapping
scope-claim-paths: [ scope ]
authority-prefix: "ROLE_"
permit-matchers: [ /actuator/health, /actuator/info ] # the only routes left openWith no configuration you still get the secure defaults: an in-memory dev signing key, default-deny on every route, and the hardened header chain.
@Secure(roles = {"reader"}) // ANY of these roles
@Secure(roles = {"a","b"}, requireAllRoles = true) // ALL of these roles (honored)
@Secure(expression = "principal.hasScope('orders:write')")Everything not explicitly permitted is denied. PDP and introspection errors return 403;
missing, expired, wrong-audience, wrong-issuer, unknown-kid, and forged-signature tokens return
401.
- Provide a
PrincipalAttributeContributorPortbean to enrichSecurityPrincipal.attributes()with your product domain (party/contract/product), read off JWT claims. - Provide
PolicyRulebeans for the embedded PDP, or swap in a real engine by declaring its bean: the OPA or Cerbos adapter forPolicyDecisionPort, the OpenFGA adapter forRelationshipPort. - Add the Vault adapter for
SecretsPortor the R2DBC adapter forRevocationPort. - Override any auto-configured bean (
KeyManagementPort,AuthorityMappingPort,ReactiveJwtDecoder,SecurityWebFilterChain, …) — each is@ConditionalOnMissingBean.
- GREEN today (delivered): all 14 modules —
security-api,security-spi,security-core,security-webflux,security-resource-server,security-method-policy,security-oauth2-client,security-authorization-server,security-test, and the five adapters (-opa,-cerbos,-openfga,-vault,-r2dbc). Every SPI port has a real adapter; five integration tests run against live Docker (Postgres, OPA, Cerbos, OpenFGA, Vault). The IdP tier is segregated into capability ports and de-domained; the application (180 tests) and backoffice (13 tests) layers are de-domained onto the genericSecurityPrincipal. Version-managed in bothfireflyframework-parent'sdependencyManagementandfireflyframework-bom, delivered throughfireflyframework-starter-application(→ resource-server + method-policy) and available standalone. - PLANNED: only the cloud key/secret adapters —
fireflyframework-security-adapter-aws-kmsandfireflyframework-security-adapter-azure-keyvault(KeyManagementPort/SecretsPortprovider variants) — plus deeper per-adapter hardening of the legacy IdP providers and merging the seven open PRs.