contexa-iam

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

Java
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.

VS

Contexa Dynamic Authorization

Java
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.

ResourceScanner
Auto-discovers all endpoints and @Protectable methods at startup
registers
ManagedResource Registry
Discovered resources are synchronized into ManagedResourceRepository with lifecycle status
curates
Policy Center
Current OSS authoring UI for resource review, quick/manual creation, AI-assisted drafts, and policy list management
persists
DB Policy Storage
Policies, conditions, targets stored in database
loads
Dynamic Authorization Manager
CustomDynamicAuthorizationManager evaluates matched URL policies at runtime

The 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.

1
Write a Controller with @RequestMapping

Create your endpoint as usual. No security annotations required.

Java
@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);
    }
}
2
ResourceScanner Auto-Detects on Startup

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.

3
Policy Center —Review, Name, and Define

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
4
Create a Policy —Quick, Manual, or AI-Assisted

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.

  1. Select the resource (e.g., GET:/api/v1/invoices)
  2. Choose target roles: ADMIN, ACCOUNTANT
  3. Assign permission: INVOICES_READ
  4. Effect: ALLOW
  5. 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 Definition (Conceptual)
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.

5
Runtime Enforcement —Automatic and Immediate

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:

  1. Spring Security delegates to CustomDynamicAuthorizationManager
  2. The manager matches the request URL to the "Invoice Deletion - Restricted" policy
  3. All conditions are evaluated: role check, time window, IP range, and current AI action state
  4. If all conditions pass, AuthorizationDecision(true) is returned
  5. If the URL authorization result is denied, CentralAuditFacade records 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.

1
Annotate with @Protectable
Java
@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.

2
MethodResourceScanner Detects on Startup

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
3
Policy Center Lists METHOD Resources

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.

4
Policy Center with Ownership + AI Conditions

Use the policy authoring flow with the selected METHOD resource context to create policies that combine ownership checks with additional conditions:

Policy Definition (Conceptual)
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.

5
Dynamic Method-Level Authorization Active

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 customConditionSpel authored by administrators.

Condition Auto-Recommendation

Based on the analysis, the AI recommends conditions for the policy:

AI-Generated Recommendations
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.

AI Draft / Assisted Draft
source = AI_GENERATED or AI_EVOLVED
submit
Pending Approval
approvalStatus = PENDING
approve
Active Policy
approvalStatus = APPROVED or NOT_REQUIRED

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:

Java (SpEL)
// 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

Java
@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();
}
1
Enable ResourceScanner (Auto-Configured)

Add the Contexa IAM dependency. MvcResourceScanner is auto-configured and runs on startup. All your existing endpoints are automatically discovered and registered as resources.

YAML
// With the starter on the classpath, MVC and method resource scanners
// are auto-configured and populate managed resources at startup.
2
Review Discovered Resources in Policy Center

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.

3
Define Permissions and Create Policies

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.

4
Replace Static Configuration

Replace your entire static security configuration with a single dynamic line:

Java
@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.

5
Configure Default Policy

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

Java
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.

HTTP Request
Incoming request from client
filter chain
PlatformSecurityConfig
Static matchers for public resources (assets, public APIs). Passes all other requests through.
.anyRequest().access()
CustomDynamicAuthorizationManager
Core engine. Matches request to policies, orchestrates evaluation.
find policies
PolicyRetrievalPoint (PRP)
Loads policies from database with caching layer. Supports hot-reload.
evaluate conditions
Expression Evaluation (SpEL + AI)
PolicyExpressionConverter extracts the stored rule expression and ExpressionAuthorizationManagerResolver evaluates it. #ai.* expressions read Zero Trust action state for the current request.
decision
AuthorizationDecision
ALLOW or DENY with detailed reasoning context.
async
CentralAuditFacade
Asynchronous recording of policy-service events and denied URL authorization results with request, outcome, and risk context when available.

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