Advanced Topics

This page covers advanced scenarios and integrations for IntelliToggle in Dart server environments and test harnesses. If you are new to IntelliToggle, start with SDK Usage.

1. Local Development

During development you may want to test feature flags without connecting to the IntelliToggle cloud service. The InMemoryProvider is the fastest way to do that.

import 'package:openfeature_provider_intellitoggle/openfeature_provider_intellitoggle.dart';

void main() async {
  final provider = InMemoryProvider();
  provider.setFlag('feature-enabled', true);
  provider.setFlag('api-version', 'v2');
  provider.setFlag('rate-limits', {
    'requests_per_minute': 1000,
    'burst_size': 50,
  });

  await OpenFeatureAPI().setProvider(provider);

  final client = IntelliToggleClient(
    FeatureClient(
      metadata: ClientMetadata(name: 'test'),
      hookManager: HookManager(),
    ),
  );

  final enabled = await client.getBooleanValue('feature-enabled', false);
  print('Feature enabled: $enabled');

  provider.setFlag('feature-enabled', false);
}

2. Remote Evaluation

The provider supports two remote-evaluation-oriented workflows:

  • A local HTTP evaluation server for development and smoke tests

  • OFREP-compatible client mode for calling a remote evaluation endpoint

2.1. Local HTTP Evaluation Server

Start the local evaluation server:

dart run bin/orep_server.dart

Environment variables:

OREP_PROVIDER_MODE=inmemory
OREP_HOST=0.0.0.0
OREP_PORT=8080
OREP_AUTH_TOKEN=secure-token-123

Use OREP_PROVIDER_MODE=intellitoggle and also set INTELLITOGGLE_CLIENT_ID, INTELLITOGGLE_CLIENT_SECRET, and INTELLITOGGLE_TENANT_ID if you want the local server to evaluate against your IntelliToggle workspace instead of seeded in-memory flags.

Test a local evaluation:

curl -X POST http://localhost:8080/v1/flags/my-flag/evaluate \
  -H "Authorization: Bearer secure-token-123" \
  -H "Content-Type: application/json" \
  -d '{
    "defaultValue": false,
    "type": "boolean",
    "context": {
      "targetingKey": "user-123",
      "role": "admin"
    }
  }'

For gRPC-based OFREP testing, the provider repo also includes:

dart run bin/ofrep_grpc_server.dart

2.2. OFREP Client Mode

The provider can call an OFREP-compatible endpoint directly.

final provider = IntelliToggleProvider(
  clientId: 'client_id',
  clientSecret: 'client_secret',
  tenantId: 'tenant_id',
  options: IntelliToggleOptions(
    useOfrep: true,
    ofrepBaseUri: Uri.parse('https://ofrep.example.com'),
    ofrepAuthToken: 'your_bearer_token',
    cacheTtl: const Duration(minutes: 1),
    maxRetries: 3,
    timeout: const Duration(seconds: 5),
  ),
);

await OpenFeatureAPI().setProvider(provider);

Environment variables:

OFREP_ENABLED=true
OFREP_BASE_URL=https://ofrep.example.com
OFREP_AUTH_TOKEN=your_bearer_token
OFREP_TIMEOUT_MS=5000
OFREP_MAX_RETRIES=3
OFREP_CACHE_TTL_MS=60000

3. API Integration

3.1. OAuth2 Token Exchange

Obtain an access token for direct API calls:

Future<String> getAccessToken() async {
  final response = await http.post(
    Uri.parse('https://api.intellitoggle.com/api/v1/oauth/token'),
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: 'grant_type=client_credentials'
        '&client_id=$clientId'
        '&client_secret=$clientSecret'
        '&scope=flags:read flags:evaluate',
  );

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    return data['access_token'];
  }
  throw Exception('OAuth2 failed: ${response.body}');
}

3.2. Direct API Calls

Future<Map<String, dynamic>> evaluateFlag({
  required String flagKey,
  required String projectId,
  required Map<String, dynamic> context,
}) async {
  final token = await getAccessToken();

  final response = await http.post(
    Uri.parse('$baseUrl/api/v1/flags/projects/$projectId/flags/$flagKey/evaluate'),
    headers: {
      'Authorization': 'Bearer $token',
      'X-Tenant-ID': tenantId,
      'Content-Type': 'application/json',
    },
    body: jsonEncode(context),
  );

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  }
  throw Exception('Evaluation failed: ${response.body}');
}

4. Error Handling

4.1. Exception Types

try {
  final result = await client.getBooleanValue('my-flag', false);
} on FlagNotFoundException {
  // Flag does not exist
} on AuthenticationException {
  // Invalid credentials
} on ApiException catch (e) {
  print('API error: ${e.code}');
} catch (e) {
  // General error
}

4.2. Retry Configuration

final options = IntelliToggleOptions(
  maxRetries: 3,
  retryDelay: Duration(seconds: 1),
  timeout: Duration(seconds: 10),
);

5. Hook System

Hooks let you intercept flag evaluations globally or per client.

5.1. Console Logging Hook

final hook = ConsoleLoggingHook();

OpenFeatureAPI().addHooks([hook]);

final hookManager = HookManager();
hookManager.addHook(hook);

5.2. Custom Analytics Hook

class AnalyticsHook extends BaseHook {
  AnalyticsHook()
    : super(metadata: HookMetadata(name: 'AnalyticsHook'));

  @override
  Future<void> after(HookContext context) async {
    analytics.track('flag_evaluated', {
      'flag_key': context.flagKey,
      'result': context.result,
    });
  }
}

6. Flutter Integration

For Flutter apps, use a service layer that exchanges OAuth2 credentials for tokens and then evaluates flags through your backend or a controlled API client.

dependencies:
  flutter_dotenv: ^5.2.1
  provider: ^6.1.5
class IntelliToggleService extends ChangeNotifier {
  Future<String> getAccessToken() async {
    // OAuth2 implementation
  }

  Future<Map<String, dynamic>> evaluateFlag({
    required String projectId,
    required String flagKey,
    required Map<String, dynamic> context,
  }) async {
    // Direct API calls
  }
}

See the sample app for a full example.

7. Context Types

7.1. Single Context

{
  "targetingKey": "user-123",
  "kind": "user",
  "role": "admin",
  "plan": "enterprise"
}

7.2. Multi-Context

{
  "kind": "multi",
  "user": {
    "targetingKey": "user-123",
    "role": "admin"
  },
  "organization": {
    "targetingKey": "org-456",
    "plan": "enterprise"
  }
}

7.3. Reserved Attributes

  • targetingKey - Required identifier for targeting

  • kind - Context type such as user, organization, device, or multi

  • anonymous - Anonymous context flag

  • privateAttributes - Attributes to exclude from logs

8. Remote Evaluation Endpoints

8.1. Local HTTP Evaluation Server

  • POST /v1/flags/{flagKey}/evaluate - Evaluate a flag

  • GET /v1/provider/metadata - Provider metadata

  • POST /v1/provider/seed - Seed test flags for local development

  • POST /v1/provider/reset - Clear seeded flags

  • POST /v1/provider/shutdown - Shut down the local server

8.2. Authentication

All local HTTP evaluation endpoints require a Bearer token:

curl -H "Authorization: Bearer changeme-token" ...

9. Security

9.1. TLS Requirements

Production deployments require HTTPS endpoints. HTTP is only allowed for localhost.

9.2. Token Management

  • Client secrets are never logged or exposed

  • Tokens have configurable TTL, with a default of 60 minutes

  • Automatic token refresh starts before expiry

9.3. Tenant Isolation

All requests include the X-Tenant-ID header for multi-tenancy:

headers: {
  'Authorization': 'Bearer $token',
  'X-Tenant-ID': tenantId,
}