Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Dec 9, 2025

feat(csharp): Add Inferred Authentication Support

Summary

This PR implements support for the inferred authentication scheme in the C# SDK generator. Inferred authentication is a pattern where authentication credentials are automatically obtained by calling a token endpoint (e.g., OAuth client credentials flow) before making authenticated API requests. The generator now:

  • Generates an InferredAuthTokenProvider class that handles token acquisition and caching
  • Automatically configures the root client to use inferred auth when specified in the API definition
  • Implements token expiry tracking and automatic refresh with a configurable buffer
  • Supports multiple authenticated headers from the token response
  • Updates mock server tests to include inferred auth endpoint mocking

Key Changes

Generator Implementation

New Generator Component (InferredAuthTokenProviderGenerator.ts):

  • Generates InferredAuthTokenProvider class in the Core namespace
  • Extracts credential parameters from the token endpoint (headers and body properties)
  • Implements GetAuthHeadersAsync() method with caching and expiry support
  • Builds response property accessors for flexible token response structures
  • Handles value prefixes (e.g., "Bearer ") for authentication headers

Root Client Integration (RootClientGenerator.ts):

  • Instantiates InferredAuthTokenProvider with required credentials
  • Configures client headers using lazy evaluation (Func<string>) to avoid blocking constructor calls
  • Adds constructor parameters for inferred auth credentials
  • Generates example values in snippets/documentation

Context Updates (SdkGeneratorContext.ts):

  • Added getInferredAuth() helper method to detect inferred auth schemes

Generator Entry Point (SdkGeneratorCli.ts):

  • Conditionally generates InferredAuthTokenProvider when inferred auth is detected

Generated Code Updates

Seed Test Fixtures (4 fixtures updated):

  • inferred-auth-explicit - Explicit auth with client credentials
  • inferred-auth-implicit-no-expiry - No expiry tracking
  • inferred-auth-implicit - Implicit auth with expiry
  • websocket-inferred-auth - WebSocket-specific inferred auth

Each fixture now includes:

  • Generated InferredAuthTokenProvider class (example)
  • Updated client initialization with credential parameters
  • Mock server test support for token endpoints

Mock Server Test Integration

Base Mock Server Test Generator (BaseMockServerTestGenerator.ts):

  • Added MockInferredAuthEndpoint method to mock token responses
  • Configures WireMock to return appropriate auth tokens for tests
  • Ensures tests can run without real authentication services

Technical Implementation Details

Token Caching Strategy

The generated provider implements efficient token management:

private IDictionary<string, string>? _cachedHeaders;
private DateTime? _expiresAt;

public async Task<IDictionary<string, string>> GetAuthHeadersAsync()
{
    if (_cachedHeaders == null || DateTime.UtcNow >= _expiresAt)
    {
        // Refresh token
    }
    return _cachedHeaders;
}

Lazy Header Evaluation

Headers use Func<string> to avoid blocking the client constructor:

clientOptions.Headers["Authorization"] = new Func<string>(() =>
    inferredAuthProvider.GetAuthHeadersAsync().Result["Authorization"]
);

Credential Parameter Collection

The generator intelligently extracts required credentials:

  • Skips literal values (hardcoded in requests)
  • Skips optional parameters for simplicity
  • Collects both header and body parameters
  • Uses PascalCase property names for request initialization

Testing

All seed test fixtures have been regenerated and validated:

  • inferred-auth-explicit - Tests explicit client credentials flow
  • inferred-auth-implicit - Tests implicit auth with token expiry
  • inferred-auth-implicit-no-expiry - Tests auth without expiry tracking
  • websocket-inferred-auth - Tests WebSocket-specific auth scenarios

Mock server tests ensure the generated code works correctly without external dependencies.

Files Changed

Generator Source (5 files)

  • generators/csharp/codegen/src/context/generation-info.ts - Added InferredAuthTokenProvider type reference
  • generators/csharp/sdk/src/SdkGeneratorCli.ts - Added generator instantiation
  • generators/csharp/sdk/src/SdkGeneratorContext.ts - Added helper method
  • generators/csharp/sdk/src/inferred-auth/InferredAuthTokenProviderGenerator.ts - New generator (337 lines)
  • generators/csharp/sdk/src/root-client/RootClientGenerator.ts - Client integration (+264 lines)

Test Infrastructure (1 file)

  • generators/csharp/sdk/src/test/mock-server/BaseMockServerTestGenerator.ts - Mock server support

Generated Seed Outputs (17 files)

  • 4 InferredAuthTokenProvider implementations
  • 4 updated client classes
  • 4 updated mock server tests
  • 4 updated READMEs
  • 1 updated snippet.json file

Version Configuration (1 file)

  • generators/csharp/sdk/versions.yml - Updated version metadata

Breaking Changes

None. This is an additive feature that only affects SDKs using the inferred authentication scheme.

Next Steps

  • Monitor generated SDK usage in production
  • Consider adding support for optional credential parameters
  • Evaluate async/await improvements to avoid .Result blocking in header suppliers

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Use PascalCase property names (XApiKey, ClientId, ClientSecret) instead of
private field names (_xApiKey, _clientId, _clientSecret) when initializing
the token request object in InferredAuthTokenProvider.

Co-Authored-By: Niels Swimberghe <[email protected]>
Swimburger and others added 6 commits December 10, 2025 18:18
- Updated the SeedInferredAuthExplicitClient, SeedInferredAuthImplicitNoExpiryClient, and SeedWebsocketAuthClient constructors to accept an optional scope parameter.
- Modified example snippets and test cases to reflect the new constructor signature, ensuring consistent usage of "X-Api-Key", "client_id", "client_secret", and "scope".
- Adjusted README files and code snippets to demonstrate the updated client initialization.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants