Library Integration Enforcement

Native application integration with framework adapters, SDKs, and middleware for fine-grained authorization control

Library Integration Enforcement

Library Integration provides the most natural and flexible way to add FGA authorization to modern applications. By integrating directly with your application frameworks and runtime environments, you get fine-grained control with minimal code changes.

Integration Approaches

πŸ—οΈ Framework Adapters

Native integration with popular frameworks:

Spring Security (Java)

// Minimal Spring Security configuration
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthonomySecurityConfig {
    
    @Bean
    public AuthonomyAuthorizationManager authorizationManager() {
        return AuthonomyAuthorizationManager.builder()
            .policySet("production_v1")
            .cacheEnabled(true)
            .build();
    }
}

// Use in controllers with annotations
@RestController
public class CustomerController {
    
    @GetMapping("/customers/{id}")
    @PreAuthorize("@authonomy.check('can_view', 'customer', #id)")
    public Customer getCustomer(@PathVariable String id) {
        return customerService.findById(id);
    }
}

Express.js (Node.js)

// Express middleware integration
const authonomy = require('@authonomy/express-middleware');

app.use(authonomy.middleware({
  policySet: 'production_v1',
  userExtractor: (req) => req.user,
  resourceExtractor: (req) => ({
    type: 'api_endpoint',
    id: req.route.path
  })
}));

// Route-specific authorization
app.get('/api/customers/:id', 
  authonomy.authorize('can_view', 'customer'),
  (req, res) => {
    // Your business logic here
    res.json(customerService.findById(req.params.id));
  });

Django (Python)

# Django decorator integration  
from authonomy.django import require_permission

class CustomerViewSet(ViewSet):
    
    @require_permission('can_view', resource_type='customer')
    def retrieve(self, request, pk=None):
        customer = Customer.objects.get(pk=pk)
        return Response(CustomerSerializer(customer).data)
        
    @require_permission('can_edit', resource_type='customer') 
    def update(self, request, pk=None):
        # Update logic here
        pass

πŸŽ›οΈ Middleware Integration

Add authorization to existing middleware chains:

// Express.js middleware example
function authonomyMiddleware(options = {}) {
  const client = new AuthonomyClient(options);
  
  return async (req, res, next) => {
    try {
      const user = extractUser(req);
      const resource = extractResource(req);
      const action = extractAction(req);
      
      const decision = await client.check({
        user: user,
        action: action, 
        resource: resource,
        context: extractContext(req)
      });
      
      if (decision.allowed) {
        req.authonomy = { decision, context: decision.context };
        next();
      } else {
        res.status(403).json({ 
          error: 'Access denied',
          reason: decision.reason 
        });
      }
    } catch (error) {
      // Fail securely - deny access on authorization errors
      res.status(500).json({ error: 'Authorization service unavailable' });
    }
  };
}

πŸ”Œ SDK Integration

Direct SDK calls for custom scenarios:

// TypeScript SDK example
import { AuthonomyClient } from '@authonomy/typescript-sdk';

class OrderService {
  private authonomy = new AuthonomyClient({
    apiKey: process.env.AUTHONOMY_API_KEY,
    policySet: 'order_management_v2'
  });
  
  async createOrder(user: User, orderData: OrderData): Promise<Order> {
    // Check if user can create orders for this customer
    const canCreate = await this.authonomy.check({
      user: user.id,
      action: 'create',
      resource: {
        type: 'order',
        customer_id: orderData.customer_id
      }
    });
    
    if (!canCreate.allowed) {
      throw new ForbiddenError(canCreate.reason);
    }
    
    // Business logic continues...
    return this.orderRepository.create(orderData);
  }
}

Language & Framework Support

β˜• Java Ecosystem

  • Spring Boot: Auto-configuration and annotations
  • Jersey: JAX-RS filter integration
  • Micronaut: Native reactive support
  • Quarkus: GraalVM native image support
// Spring Boot auto-configuration
@SpringBootApplication
@EnableAuthonomy
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

🌐 JavaScript/TypeScript

  • Express.js: Middleware and route protection
  • Fastify: Plugin-based integration
  • NestJS: Decorator and guard integration
  • Next.js: API route and page protection
// NestJS guard example
@Injectable()
export class AuthonomyGuard implements CanActivate {
  constructor(private authonomy: AuthonomyService) {}
  
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const { user, resource, action } = this.extractAuthContext(request);
    
    const decision = await this.authonomy.check({ user, action, resource });
    return decision.allowed;
  }
}

🐍 Python Ecosystem

  • Django: Decorator and middleware integration
  • FastAPI: Dependency injection integration
  • Flask: Decorator and blueprint integration
  • SQLAlchemy: ORM-level authorization
# FastAPI dependency injection
from authonomy.fastapi import AuthonomyChecker

app = FastAPI()
authorize = AuthonomyChecker(policy_set="api_v1")

@app.get("/customers/{customer_id}")
async def get_customer(
    customer_id: str,
    user: User = Depends(get_current_user),
    _auth: None = Depends(authorize.require("can_view", "customer"))
):
    return await customer_service.get(customer_id)

βš™οΈ C# .NET

  • ASP.NET Core: Authorization policy integration
  • Entity Framework: Query-level authorization
  • SignalR: Real-time authorization
  • Blazor: Component-level authorization
// ASP.NET Core authorization policy
services.AddAuthorization(options =>
{
    options.AddPolicy("CanViewCustomer", policy =>
        policy.AddRequirements(new AuthonomyRequirement("can_view", "customer")));
});

// Controller usage
[Authorize(Policy = "CanViewCustomer")]
public IActionResult GetCustomer(int id)
{
    var customer = customerService.GetById(id);
    return Ok(customer);
}

Runtime Injection Patterns

🎯 Aspect-Oriented Programming (AOP)

Inject authorization without changing business logic:

// Java AOP example
@Aspect
@Component  
public class AuthonomyAuthorizationAspect {
    
    @Around("@annotation(authorize)")
    public Object checkAuthorization(ProceedingJoinPoint joinPoint, 
                                   Authorize authorize) throws Throwable {
        
        Object[] args = joinPoint.getArgs();
        String user = SecurityContext.getCurrentUser();
        String resource = extractResource(args);
        
        if (!authonomyClient.check(user, authorize.action(), resource)) {
            throw new AccessDeniedException("Insufficient permissions");
        }
        
        return joinPoint.proceed();
    }
}

πŸƒ Runtime Bytecode Modification

Inject authorization checks at runtime:

// C# runtime interception with Castle DynamicProxy
public class AuthonomyInterceptor : IInterceptor
{
    private readonly IAuthonomyClient authonomy;
    
    public void Intercept(IInvocation invocation)
    {
        var authorizeAttr = invocation.Method.GetCustomAttribute<AuthorizeAttribute>();
        if (authorizeAttr != null)
        {
            var user = GetCurrentUser();
            var resource = ExtractResource(invocation.Arguments);
            
            var allowed = authonomy.Check(user, authorizeAttr.Action, resource);
            if (!allowed)
            {
                throw new UnauthorizedAccessException();
            }
        }
        
        invocation.Proceed();
    }
}

Performance Optimization

⚑ Authorization Caching

Intelligent caching for repeated authorization checks:

// Client-side caching configuration
const authonomy = new AuthonomyClient({
  cache: {
    type: 'memory',
    ttl: 300,  // 5 minutes
    maxSize: 10000,
    
    // Cache key strategy
    keyGenerator: (user, action, resource) => 
      `${user.id}:${action}:${resource.type}:${resource.id}`,
      
    // Cache invalidation
    invalidateOn: ['user_role_change', 'policy_update']
  }
});

πŸš€ Batch Authorization

Optimize bulk operations:

# Batch authorization for list operations
async def get_customer_list(user: User) -> List[Customer]: 
    customers = await customer_repository.get_all()
    
    # Batch authorize all customers at once
    authorizations = await authonomy.batch_check([
        CheckRequest(user=user.id, action="view", resource=f"customer:{c.id}")
        for c in customers
    ])
    
    # Filter based on authorization results
    allowed_customers = [
        customer for customer, auth in zip(customers, authorizations)
        if auth.allowed
    ]
    
    return allowed_customers

πŸ“Š Performance Monitoring

Track authorization performance in production:

# Performance metrics configuration
monitoring:
  metrics:
    - name: "authorization_latency"
      type: "histogram" 
      labels: ["user_type", "resource_type", "action"]
      
    - name: "authorization_decisions"
      type: "counter"
      labels: ["decision", "policy_name"]
      
    - name: "cache_hit_rate"
      type: "gauge"
      
  alerting:
    - metric: "authorization_latency_p95"
      threshold: "> 100ms"
      
    - metric: "cache_hit_rate" 
      threshold: "< 80%"

Error Handling & Resilience

πŸ›‘οΈ Graceful Degradation

Handle authorization service outages gracefully:

// Resilience configuration
const authonomy = new AuthonomyClient({
  resilience: {
    // Fallback behavior when FGA service is unavailable
    fallback: 'deny',  // or 'allow', 'cache_only'
    
    // Circuit breaker configuration
    circuitBreaker: {
      failureThreshold: 5,
      recoveryTimeout: 30000,
      monitoringPeriod: 10000
    },
    
    // Retry configuration
    retry: {
      maxAttempts: 3,
      backoffStrategy: 'exponential',
      maxDelay: 5000
    }
  }
});

🚨 Error Scenarios

Handle common failure modes:

# Comprehensive error handling
try:
    decision = await authonomy.check(user, action, resource)
    if not decision.allowed:
        raise PermissionDenied(decision.reason)
        
except AuthonomyServiceUnavailable:
    # FGA service is down - use fallback
    if fallback_mode == 'allow':
        logger.warning("FGA unavailable, allowing access")
        return True
    else:
        logger.error("FGA unavailable, denying access") 
        raise ServiceUnavailable("Authorization service down")
        
except AuthonomyTimeoutError:
    # Request timed out - fail securely
    logger.error("Authorization timeout")
    raise PermissionDenied("Authorization check timed out")
    
except AuthonomyPolicyError as e:
    # Policy evaluation failed
    logger.error(f"Policy error: {e}")
    raise InternalServerError("Authorization policy error")

Migration Patterns

πŸ”„ Gradual Integration

Migrate existing authorization code incrementally:

// Phase 1: Add FGA alongside existing authorization
@GetMapping("/customer/{id}")  
public Customer getCustomer(@PathVariable String id) {
    // Existing authorization (keep temporarily)
    if (!legacyAuth.hasRole("ADMIN") && !legacyAuth.canViewCustomer(id)) {
        throw new AccessDeniedException("Access denied");
    }
    
    // New FGA authorization (shadow mode initially)
    boolean fgaAllowed = authonomy.check(getCurrentUser(), "view", "customer:" + id);
    if (legacyAuth.isAllowed() != fgaAllowed) {
        logger.warn("Authorization mismatch for customer {}", id);
    }
    
    return customerService.findById(id);
}

🎯 Feature Flag Migration

Use feature flags to control authorization method:

// Feature flag controlled authorization
async function checkAuthorization(user: User, action: string, resource: Resource): Promise<boolean> {
  if (await featureFlags.isEnabled('fga_enforcement')) {
    return await authonomy.check(user, action, resource);
  } else {
    return await legacyAuthService.check(user, resource);
  }
}

// Usage in application code
export async function getCustomerData(userId: string, customerId: string) {
  const canView = await checkAuthorization(
    { id: userId }, 
    'view', 
    { type: 'customer', id: customerId }
  );
  
  if (!canView) {
    throw new ForbiddenError('Cannot access customer data');
  }
  
  return customerRepository.findById(customerId);
}

Advanced Integration Patterns

🎨 Reactive Authorization

Stream real-time authorization decisions:

// Real-time authorization with WebSockets
const authStream = authonomy.createAuthorizationStream();

authStream.subscribe({
  user: currentUser.id,
  resources: ['order:*', 'customer:*'],
  
  onAuthorization: (event) => {
    if (event.type === 'permission_granted') {
      enableFeature(event.resource, event.action);
    } else if (event.type === 'permission_revoked') {
      disableFeature(event.resource, event.action);
    }
  }
});

🧩 Microservices Authorization

Consistent authorization across microservice architectures:

# Shared authorization configuration
microservices:
  customer_service:
    authonomy:
      policy_set: "customer_management_v1"
      resources: ["customer", "customer_profile"]
      
  order_service:
    authonomy:
      policy_set: "order_management_v1" 
      resources: ["order", "invoice", "shipment"]
      
  billing_service:
    authonomy:
      policy_set: "billing_management_v1"
      resources: ["payment", "subscription"]

# Cross-service authorization
cross_service_policies:
  - name: "customer_order_access"
    condition: "customer_service.can_view(customer_id) and order_service.can_view(order_id)"

πŸ”— Authorization Composition

Combine multiple authorization checks:

# Complex authorization logic
class AdvancedAuthorizationService:
    
    async def check_complex_operation(self, user, operation_context):
        checks = [
            # Base permission check
            self.authonomy.check(user, "execute", operation_context.operation_type),
            
            # Resource-specific authorization
            self.check_resource_access(user, operation_context.resources),
            
            # Time-based authorization
            self.check_time_restrictions(user, operation_context.schedule),
            
            # Delegation verification
            self.check_delegation_chain(user, operation_context.delegated_by)
        ]
        
        results = await asyncio.gather(*checks, return_exceptions=True)
        
        # All checks must pass
        return all(result.allowed for result in results if not isinstance(result, Exception))

Testing & Debugging

πŸ” Authorization Testing

Test authorization logic with various scenarios:

// JUnit test example
@Test
public void testCustomerAccessAuthorization() {
    // Setup test data
    User salesRep = createUser("alice", "sales_rep", "west_region");
    Customer customer = createCustomer("12345", "west_region");
    
    // Test authorized access
    assertTrue(authonomy.check(salesRep, "view", customer));
    
    // Test unauthorized access (different region)
    Customer eastCustomer = createCustomer("67890", "east_region"); 
    assertFalse(authonomy.check(salesRep, "view", eastCustomer));
    
    // Test admin override
    User admin = createUser("bob", "admin");
    assertTrue(authonomy.check(admin, "view", eastCustomer));
}

πŸ› Debug Mode

Enable detailed logging for troubleshooting:

// Debug configuration
const authonomy = new AuthonomyClient({
  debug: {
    enabled: process.env.NODE_ENV === 'development',
    logLevel: 'trace',
    includeContext: true,
    
    // Log all authorization decisions
    onDecision: (decision) => {
      console.log('Authorization Decision:', {
        user: decision.user,
        action: decision.action,
        resource: decision.resource,
        allowed: decision.allowed,
        reason: decision.reason,
        evaluationTime: decision.evaluationTime
      });
    }
  }
});

Production Deployment

πŸš€ Deployment Configuration

# Production deployment configuration  
production:
  authonomy:
    # Service configuration
    endpoint: "https://fga.authonomy.io"
    api_key: "${AUTHONOMY_API_KEY}"
    policy_set: "production_customer_portal_v3"
    
    # Performance settings
    timeout: "5s"
    cache_size: 50000
    cache_ttl: "10m"
    
    # Resilience settings  
    circuit_breaker:
      failure_threshold: 10
      recovery_timeout: "60s"
      
    # Monitoring
    metrics:
      enabled: true
      endpoint: "/metrics"
      
    audit:
      level: "info"
      destination: "syslog"

πŸ“Š Health Checks & Monitoring

// Application health check with authorization status
app.get('/health', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    services: {}
  };
  
  try {
    // Check FGA service connectivity
    const fgaHealth = await authonomy.healthCheck();
    health.services.authorization = {
      status: fgaHealth.healthy ? 'up' : 'down',
      latency: fgaHealth.latency,
      cacheHitRate: fgaHealth.cacheStats.hitRate
    };
    
  } catch (error) {
    health.status = 'degraded';
    health.services.authorization = {
      status: 'down',
      error: error.message
    };
  }
  
  res.json(health);
});

Best Practices

βœ… Implementation Guidelines

  • Fail securely: Default to deny when authorization service is unavailable
  • Cache wisely: Balance performance and consistency for authorization decisions
  • Monitor extensively: Track authorization decisions, performance, and errors
  • Test thoroughly: Include authorization in your integration and load testing

πŸ”’ Security Considerations

  • API key protection: Secure storage and rotation of Authonomy API keys
  • Request validation: Validate and sanitize authorization context data
  • Audit trail: Log all authorization decisions for security and compliance
  • Error handling: Don’t leak sensitive information in authorization errors

πŸ“ˆ Performance Tips

  • Batch operations: Group multiple authorization checks when possible
  • Smart caching: Cache based on user context and resource patterns
  • Async processing: Use asynchronous authorization checks where possible
  • Connection pooling: Reuse connections to the FGA service

Migration Checklist

βœ… Pre-Migration

  • Framework adapter or SDK installed and configured
  • Policy set defined and tested
  • Error handling and fallback behavior implemented
  • Monitoring and logging configured

βœ… During Migration

  • Feature flags controlling authorization method
  • Shadow mode comparison with legacy authorization
  • Performance monitoring active
  • Gradual rollout to user segments

βœ… Post-Migration

  • Legacy authorization code removed
  • Full FGA policy enforcement active
  • Performance within acceptable ranges
  • Audit logging meeting compliance requirements

Next Steps

With library integration complete, consider:


Need help with library integration? Contact our integration team for framework-specific guidance and implementation support.