End-to-End Dynamic Authorization Workflow
Build a complete policy-driven authorization system that can centralize most URL and method authorization rules in database-managed policy flows. From automatic resource discovery to runtime enforcement, Contexa reduces the amount of static authorization code that must be maintained in Spring Security configuration.
Why This is Revolutionary
Traditional Spring Security often forces developers to hardcode authorization rules directly in Java configuration. Every new endpoint, every role change, every permission tweak can require a code change, a rebuild, and a redeployment. Contexa moves that operational burden toward runtime-managed policies, while still allowing static matchers where they are intentionally needed.
Traditional vs. Contexa Approach
Traditional Spring Security
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/admin/**")
.hasRole("ADMIN")
.requestMatchers("/api/users/**")
.hasAuthority("READ_USERS")
.requestMatchers("/api/reports/**")
.hasAnyRole("ADMIN", "ANALYST")
.requestMatchers("/api/orders/**")
.hasAuthority("MANAGE_ORDERS")
.requestMatchers("/api/settings/**")
.hasRole("SUPER_ADMIN")
.requestMatchers("/api/audit/**")
.hasAuthority("VIEW_AUDIT_LOG")
// ... 20+ more lines
.anyRequest().authenticated()
);
Every change requires code modification, rebuild, and redeployment. No visibility into who has access to what without reading source code.
Contexa Dynamic Authorization
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**")
.permitAll()
.anyRequest()
.access(customDynamicAuthorizationManager)
);
The dynamic manager can replace most application-specific URL rules with one runtime authorization entry point. Policies are managed through the admin surface, stored in the database, and enforced at runtime without recompiling the application.
Key Advantages
| Capability | Traditional | Contexa |
|---|---|---|
| Policy changes | Code change + rebuild + redeploy | Policy Center/admin policy edit, instant effect |
| New endpoint protection | Manual requestMatchers entry |
Auto-discovered by ResourceScanner |
| Policy creation | Developer writes Java code | Policy Center quick/manual/AI authoring flows |
| Audit trail | Git history only | Policy-service events and denied URL authorization results via CentralAuditFacade |
| AI integration | Not possible | AI risk assessment, condition recommendation |
| Granularity | URL patterns + roles | URL, method, ownership, time, IP, AI conditions |
| Visibility | Read source code | Centralized dashboard for all stakeholders |
Complete Workflow Overview
The dynamic authorization system operates as a five-stage pipeline. Each stage maps to a concrete runtime component, from scanner registration through policy persistence and request-time enforcement.
ManagedResourceRepository with lifecycle statusCustomDynamicAuthorizationManager evaluates matched URL policies at runtimeThe following sections walk through four real-world scenarios demonstrating this pipeline in action.
Scenario 1 —Protecting a New API Endpoint
You have written a new REST controller and want it dynamically protected without touching your security configuration.
Create your endpoint as usual. No security annotations required.
@RestController
@RequestMapping("/api/v1/invoices")
public class InvoiceController {
@GetMapping
public List<InvoiceDto> listInvoices() {
return invoiceService.findAll();
}
@PostMapping
public InvoiceDto createInvoice(@RequestBody CreateInvoiceRequest req) {
return invoiceService.create(req);
}
@DeleteMapping("/{id}")
public void deleteInvoice(@PathVariable Long id) {
invoiceService.delete(id);
}
}
MvcResourceScanner runs automatically when the application starts. It scans all @RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, and @PatchMapping annotations across all controllers.
Three new resources are registered in the database:
| Resource ID | HTTP Method | URL Pattern | Type |
|---|---|---|---|
GET:/api/v1/invoices |
GET | /api/v1/invoices | URL |
POST:/api/v1/invoices |
POST | /api/v1/invoices | URL |
DELETE:/api/v1/invoices/{id} |
DELETE | /api/v1/invoices/{id} | URL |
No manual registration is needed. The scanner discovers everything automatically.
Open the admin console and navigate to Policy Center. The current OSS template tree uses Policy Center as the primary client surface for discovered resources, while legacy controller routes remain in code.
For each resource you can:
- Review the AI-generated friendly name and description (for example, "List Invoices", "Create Invoice", "Delete Invoice")
- Define the resource as a Permission when you want it governed by role/permission policies
- Exclude or restore the resource from authorization management based on whether it should stay public
The current OSS authoring flow is centered on Policy Center. It supports quick role-permission mapping, manual authoring, and AI-assisted draft generation.
Option A: Quick Mode
The fastest path. Select roles, assign permissions, and save a simple ALLOW policy.
- Select the resource (e.g.,
GET:/api/v1/invoices) - Choose target roles: ADMIN, ACCOUNTANT
- Assign permission:
INVOICES_READ - Effect: ALLOW
- Use the Quick mode Create Policy button, or start from the Resources surface with Create Permission & Policy.
This creates a simple role-based policy equivalent to hasAnyRole('ADMIN', 'ACCOUNTANT') —but stored in the database, not in code.
Option B: Manual / AI-Assisted Mode
For complex authorization logic with conditions, multiple targets, or AI-assisted drafting.
Policy: "Invoice Deletion - Restricted"
Target: DELETE:/api/v1/invoices/{id}
Effect: ALLOW
Roles: ADMIN
Conditions:
- Time: weekdays 09:00-18:00 only
- IP: internal network (10.0.0.0/8)
- AI: #ai.hasActionIn('ALLOW', 'CHALLENGE')
BusinessPolicyServiceImpl translates these business inputs into persisted policy targets, rules, and SpEL/XACML-compatible conditions that are evaluated at runtime.
The policy is stored in the database. CustomDynamicAuthorizationManager loads policies via PolicyRetrievalPoint (with caching) and builds a runtime matcher list.
When a request hits DELETE /api/v1/invoices/42:
- Spring Security delegates to
CustomDynamicAuthorizationManager - The manager matches the request URL to the "Invoice Deletion - Restricted" policy
- All conditions are evaluated: role check, time window, IP range, and current AI action state
- If all conditions pass,
AuthorizationDecision(true)is returned - If the URL authorization result is denied,
CentralAuditFacaderecords the denial asynchronously with request and outcome context
Result: The endpoint is dynamically protected. No code change. No redeployment. The policy can be updated at any time through Policy Center or related admin policy flows.
Scenario 2 —Protecting a Business Method
Beyond URL-level authorization, Contexa supports method-level protection using the @Protectable annotation. This enables fine-grained access control on individual service methods with ownership semantics.
@Service
public class DocumentService {
@Protectable(ownerField = "createdBy")
public Document getDocument(Long documentId) {
return documentRepository.findById(documentId)
.orElseThrow(() -> new NotFoundException("Document not found"));
}
@Protectable(ownerField = "createdBy")
public void updateDocument(Long documentId, UpdateDocumentRequest req) {
Document doc = documentRepository.findById(documentId)
.orElseThrow(() -> new NotFoundException("Document not found"));
doc.setTitle(req.getTitle());
doc.setContent(req.getContent());
documentRepository.save(doc);
}
}
The ownerField parameter tells Contexa which field on the returned entity identifies the resource owner. This enables ownership-based authorization: the owner can always access their own resources.
MethodResourceScanner scans all beans for @Protectable annotations and registers them as METHOD-type resources:
| Resource ID | Class | Method | Type |
|---|---|---|---|
DocumentService.getDocument |
DocumentService | getDocument | METHOD |
DocumentService.updateDocument |
DocumentService | updateDocument | METHOD |
In the current OSS admin experience, METHOD-type resources are surfaced through the Policy Center resource area alongside URL resources. They follow the same lifecycle —review, define as permission, connect to policy, or exclude.
Use the policy authoring flow with the selected METHOD resource context to create policies that combine ownership checks with additional conditions:
Policy: "Document Update - Owner or Admin"
Target: DocumentService.updateDocument
Effect: ALLOW
Rules:
Rule 1 (Owner Access):
Condition: #ownership.isOwner(authentication, returnObject)
Effect: ALLOW
Rule 2 (Admin Override):
Condition: hasRole('ADMIN')
Effect: ALLOW
Rule 3 (AI Risk Gate):
Condition: #ai.isBlocked()
Effect: DENY (overrides all)
This policy allows the document owner or an ADMIN to update documents, but denies the operation when the Zero Trust action resolves to BLOCK.
The policy is now enforced at the method level. When updateDocument() is called, Contexa's AOP interceptor evaluates the policy before the method executes. Ownership is resolved by comparing authentication.getName() with the entity's createdBy field.
Scenario 3 —AI-Assisted Policy Creation
Contexa can assist policy authoring by combining existing roles, permissions, condition templates, and optional custom SpEL. In OSS code, this is best understood as assisted draft generation plus approval-state handling rather than a separate threat-scoring policy language.
AI-Powered Risk Assessment
When creating a policy for a sensitive resource, the AI engine analyzes:
- Available roles and permissions —Existing access entities exposed by Policy Center.
- Target resource metadata —URL or METHOD targets and their compatible condition types.
- Saved condition templates —Reusable SpEL conditions returned by the condition catalog.
- Custom condition input —Optional direct
customConditionSpelauthored by administrators.
Condition Auto-Recommendation
Based on the analysis, the AI recommends conditions for the policy:
Resource: DELETE:/api/v1/customers/{id}
Draft summary: sensitive destructive endpoint
Recommended Conditions:
1. Role restriction: ADMIN only
2. Time restriction: Business hours (M-F 09:00-18:00)
3. IP restriction: Internal network only
4. MFA requirement: Step-up authentication required
5. AI action gate: #ai.hasActionIn('ALLOW', 'CHALLENGE')
6. Rate limit: Max 10 deletions per hour per user
Selected flow: assisted policy draft
Rationale: combine role, time, IP, and AI action checks for a high-risk target.
maximum protection with multiple condition layers.
Approval Workflow
Policies can move through approval states. The runtime loader skips PENDING and REJECTED policies; approved or not-required policies can be loaded.
CustomDynamicAuthorizationManager skips policies whose approval status is PENDING or REJECTED. Policies marked APPROVED or NOT_REQUIRED can participate in runtime evaluation.
AI Expressions in Policies
Once approved, AI-powered conditions are evaluated at runtime using SpEL expressions:
// Allow if AI determines the request is safe
#ai.isAllowed()
// Require step-up authentication if AI detects anomalies
#ai.needsChallenge()
// Action-based gating for threshold-like decisions
#ai.hasActionIn('ALLOW', 'CHALLENGE')
// Combined with traditional conditions
hasRole('ADMIN') and !#ai.isBlocked()
Scenario 4 —Migrating from Static to Dynamic
This scenario walks through converting an existing application with 20+ lines of hardcoded requestMatchers to Contexa's dynamic authorization.
Before: Static Security Configuration
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/users/**").hasRole("ADMIN")
.requestMatchers("/api/admin/settings/**").hasRole("SUPER_ADMIN")
.requestMatchers("/api/admin/audit/**").hasAuthority("VIEW_AUDIT")
.requestMatchers("/api/reports/financial/**").hasAnyRole("ADMIN", "FINANCE")
.requestMatchers("/api/reports/analytics/**").hasAnyRole("ADMIN", "ANALYST")
.requestMatchers("/api/orders/**").hasAuthority("MANAGE_ORDERS")
.requestMatchers("/api/customers/**").hasAuthority("MANAGE_CUSTOMERS")
.requestMatchers("/api/products/**").hasAuthority("MANAGE_PRODUCTS")
.requestMatchers("/api/inventory/**").hasAnyRole("ADMIN", "WAREHOUSE")
.requestMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.PUT, "/api/users/*/role").hasRole("SUPER_ADMIN")
// ... more rules
.anyRequest().authenticated()
);
return http.build();
}
Add the Contexa IAM dependency. MvcResourceScanner is auto-configured and runs on startup. All your existing endpoints are automatically discovered and registered as resources.
// With the starter on the classpath, MVC and method resource scanners
// are auto-configured and populate managed resources at startup.
Open Policy Center in the admin console. Review the discovered resources, confirm friendly names, define relevant resources as permissions, and exclude endpoints that should remain public. This gives you a complete inventory of every protected surface in your application.
For each resource (or resource group), create equivalent policies in Policy Center. Map your existing static rules to dynamic policies:
| Static Rule | Dynamic Policy |
|---|---|
.hasRole("ADMIN") |
Policy: roles=[ADMIN], effect=ALLOW |
.hasAuthority("VIEW_AUDIT") |
Policy: permissions=[VIEW_AUDIT], effect=ALLOW |
.hasAnyRole("ADMIN","FINANCE") |
Policy: roles=[ADMIN,FINANCE], effect=ALLOW |
Once migrated, you can immediately enhance these policies with conditions that were impossible with static configuration: time-based access, IP restrictions, AI risk assessment, and more.
Replace your entire static security configuration with a single dynamic line:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http,
CustomDynamicAuthorizationManager customDynamicAuthorizationManager)
throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
.requestMatchers("/api/public/**").permitAll()
.anyRequest().access(customDynamicAuthorizationManager)
);
return http.build();
}
Static matchers remain only for truly public resources (assets, public APIs). Everything else is delegated to the dynamic authorization manager.
Set the default behavior for resources that do not have an explicit policy. See the Default Policy Management section below for details.
Default Policy Management
When a request matches no configured URL policy, CustomDynamicAuthorizationManager.check(...) returns new AuthorizationDecision(true). That is the effective OSS fallback behavior.
Current Default Behavior
if (matchedDecisions.isEmpty()) {
return new AuthorizationDecision(true);
}
Moving Toward Default Deny
The OSS codebase does not expose a dedicated YAML property for unmatched URL requests. To move toward deny-by-default, create explicit catch-all DENY policies for protected URL spaces or customize the authorization manager in code.
Architecture Deep Dive
This section traces the complete lifecycle of an HTTP request through the dynamic authorization system.
#ai.* expressions read Zero Trust action state for the current request.Key Components
CustomDynamicAuthorizationManager
Implements AuthorizationManager<RequestAuthorizationContext>. On initialization, it loads all active policies from the database via PolicyRetrievalPoint and builds a list of RequestMatcherEntry objects. Each entry maps a URL pattern (with HTTP method) to an ExpressionAuthorizationManager that evaluates the policy's conditions.
PolicyRetrievalPoint (PRP)
The data access layer for policies. It loads policies from the database, caches them for performance, and supports hot-reload when Policy Center or related admin services call authorizationManager.reload() together with PRP cache clearing. The current OSS runtime does not expose this as a standalone PRP event-subscriber abstraction in the documentation layer.
PolicyExpressionConverter
Converts stored policy conditions into the normalized SpEL string consumed by Spring Security. This bridges the gap between the policy definitions managed through Policy Center/admin policy flows and the runtime expression evaluation engine.
CentralAuditFacade
CentralAuditFacade is used across IAM policy services and denied authorization handling. In the URL authorization path, denied results are recorded with the request path and matched policy context so operators can review enforcement outcomes.
Advantages Summary
A comprehensive comparison across all dimensions of authorization management.
| Dimension | Traditional Spring Security | Contexa Dynamic Authorization |
|---|---|---|
| Policy changes | Code change, rebuild, redeploy | Policy Center/admin policy edit, immediate effect |
| Deployment required | Yes, for every rule change | No —database-driven, zero downtime |
| Audit trail | Git commit history only | CentralAuditFacade-backed policy-service events and denied URL audit records |
| AI integration | Not possible | AI risk assessment, condition recommendation, policy generation |
| Granularity | URL patterns with role/authority checks | URL + method + ownership + time + IP + AI + custom conditions |
| Admin UI | None —source code only | Policy Center (resource review + quick/manual/AI creation), with detail editing through policydetails.html |
| Resource discovery | Manual inventory | Automatic via ResourceScanner on startup |
| Method-level security | @PreAuthorize with hardcoded expressions | @Protectable with dynamic, database-driven policies |
| Who manages policies | Developers only | Security admins, compliance officers, developers |
| Time to protect new endpoint | Code + review + merge + deploy (hours/days) | Auto-discovered, policy via Admin UI (minutes) |
| Approval workflow | Code review (PR-based) | Built-in DRAFT —PENDING —APPROVED workflow |
| Rollback | Git revert + redeploy | Disable policy in Policy Center/admin policy flows, instant effect |
Related Documentation
- Resource Scanner —Detailed reference for MvcResourceScanner and MethodResourceScanner
- Dynamic URL Authorization —CustomDynamicAuthorizationManager API reference
- Policy Management —Policy lifecycle, CRUD operations, and AI enrichment
- @Protectable —Method-level resource protection annotation
- XACML Integration —Policy model and evaluation engine
- Permission Evaluators —Custom expression evaluation
- Admin Console —Web-based administration console