This guide is intended for maintainers of the Descope .NET SDK. For SDK usage documentation, see the main README.md.
- Getting Started
- Makefile Usage
- Kiota Code Generation
- Extension Methods
- Middleware Overview
- Testing
- Releasing Versions
- .NET SDK 6.0, 8.0, 9.0, and 10.0 (for running all tests)
- Kiota CLI tool (automatically installed by
make check-kiota) - Access to the
GODESCOPEenvironment variable pointing to the Descope root Go folder
The most common workflow for maintainers:
# Regenerate Kiota files and build the SDK
make
# Run quick tests (net8.0 framework only)
make test-quickThe project uses a Makefile to automate common tasks. Here are the available targets:
makeormake build(default): Regenerates all Kiota client files and rebuilds the C# projectmake test: Runs unit tests across all target frameworks (net6.0, net8.0, net9.0, net10.0)make test-quick: Runs unit tests for net8.0 only (faster for development)make generate: Regenerates all Kiota client files without building
make generate-mgmt: Regenerates Management API Kiota client files onlymake generate-auth: Regenerates Auth API Kiota client files onlymake check-kiota: Checks if Kiota is installed, installs if missing
make cover: Runs tests with coverage report (requires ReportGenerator)make clean: Cleans build artifactsmake post-process-obsolete: Applies[Obsolete]annotations fromObsolete.csv(called duringmake generate)make help: Shows all available targets with descriptions
The SDK uses Microsoft Kiota to auto-generate API client code from OpenAPI specifications.
Generated code is placed in:
- Management API:
Descope/Generated/Mgmt/ - Auth API:
Descope/Generated/Auth/
Not all endpoints from the OpenAPI specs are included in the SDK. Endpoints are excluded in the Makefile using the --exclude-path option for Kiota.
After Kiota generation, the post-process-obsolete target applies [Obsolete] attributes to methods that have better alternatives (see Extension Methods below).
To provide a better developer experience, the SDK includes extension methods that wrap Kiota-generated methods with cleaner, more intuitive APIs.
Kiota-generated methods often require complex configuration objects or have implicit requirements (like JWT tokens) that aren't clear from the method signature. Extension methods make these requirements explicit and provide sensible defaults.
Located at Descope/Sdk/Auth/AuthExtensions.cs, this class provides extensions for authentication operations that require JWT tokens.
Key patterns:
WithJwtmethods: Operations requiring a refresh JWT (updates, logout, etc.)WithKeymethods: Operations requiring an access key (key exchange)- Query parameter helpers: Simplifying SSO authorize flows
Example:
// Instead of manually configuring request with JWT:
await client.Auth.V1.Magiclink.Update.Email.PostAsync(request, config => {
config.Headers.Add("Authorization", $"Bearer {refreshJwt}");
});
// Use the extension method:
await client.Auth.V1.Magiclink.Update.Email.PostWithJwtAsync(request, refreshJwt);Located at Descope/Sdk/Mgmt/MgmtExtensions.cs, this class provides extensions for management operations with clearer parameter naming.
Key patterns:
WithIdmethods: Loading entities by IDWithTenantIdmethods: Tenant-scoped operationsWithIdentifiermethods: Flexible user identifier lookups (userID or loginID)WithSettingsResponsemethods: Update operations using response objects
Example:
// Instead of:
await client.Mgmt.V1.Tenant.GetAsync(config => {
config.QueryParameters.Id = tenantId;
});
// Use:
await client.Mgmt.V1.Tenant.GetWithIdAsync(tenantId);When an extension method provides a better API than the Kiota-generated method, we mark the generated method as obsolete to guide developers toward the better approach.
This CSV file (located at project root) defines which methods should be marked with [Obsolete] attributes:
RelativeFilePath,Method,Replacement
Descope/Generated/Mgmt/V1/Mgmt/User/UserRequestBuilder.cs,GetAsync,GetWithIdentifierAsync
Descope/Generated/Auth/V1/Auth/Magiclink/Update/Email/EmailRequestBuilder.cs,PostAsync,PostWithJwtAsyncColumns:
RelativeFilePath: Path to the generated file (relative to project root)Method: The Kiota-generated method name to mark obsoleteReplacement: The extension method that should be used instead
Important: The post-process-obsolete target runs automatically as part of make generate, so you don't need to manually apply these annotations.
- Explicit parameters: Make implicit requirements (like JWTs) explicit in the method signature
- Validation: Validate parameters and throw
DescopeExceptionwith clear messages - Documentation: Include XML comments with usage examples
- Consistency: Follow existing naming patterns (
WithJwt,WithId, etc.) - Update Obsolete.csv: ALWAYS add an entry when wrapping a generated method
The SDK uses custom HTTP middleware handlers to address OpenAPI inconsistencies and routing requirements.
Purpose: Corrects OpenAPI spec inconsistencies for endpoints using the protobuf response_body option.
Problem: Some endpoints return "flat" fields at the root level instead of nested under a specific field name, which doesn't match the generated client's expectations.
Location: Descope/Sdk/Internal/Middleware/FixRootResponseBodyHandler.cs
Purpose: Routes specific FGA (Fine-Grained Authorization) operations to an alternate cache URL when configured.
Problem: FGA cache operations need to hit a different endpoint than the main API for performance reasons.
Location: Descope/Sdk/Internal/Middleware/FgaCacheUrlHandler.cs
Affected endpoints (POST only):
/v1/mgmt/fga/schema- SaveSchema/v1/mgmt/fga/relations- CreateRelations/v1/mgmt/fga/relations/delete- DeleteRelations/v1/mgmt/fga/check- Check
Configuration:
var client = new DescopeClient(new DescopeClientOptions
{
ProjectId = "your-project-id",
FgaCacheUrl = "https://fga-cache.descope.com" // Optional
});If you need to add new middleware:
- Create a class inheriting from
DelegatingHandlerinDescope/Sdk/Internal/Middleware/ - Override
SendAsyncto implement your logic - Register it in both
DescopeClientFactory.csandDescopeServiceCollectionExtensions.cs: - Document it in this README
Tests are located in Descope.Test/:
- UnitTests/: Fast, isolated tests using mocks
- IntegrationTests/: Tests against real Descope APIs (require configuration)
- Helpers/: Test utilities and mocks
# All frameworks (net6.0, net8.0, net9.0, net10.0)
make test
# Quick run (net8.0 only) - recommended during development
make test-quick
# With coverage report
make coverIntegration tests require a valid Descope project. To run locally, create and populate the git-ignored Descope.Test/appsettingsTest.json file like in the example below.
{
"AppSettings": {
"ProjectId": "P**************a",
"ManagementKey": "K********************************",
"BaseURL": "http://localhost:8000",
"Unsafe": "true"
}
}Important: In the CI environment, integration tests use environment variables instead of appsettingsTest.json.
Important: Integration tests are rate-limited. See Descope.Test/IntegrationTests/RATE_LIMITING.md for details.
The SDK maintains two separate version lines with different release processes:
The current Kiota-generated SDK uses automated release management via release-please.
How it works:
- Release-please automatically maintains a release PR that tracks all changes merged into
main - The PR is continuously updated with new changes and follows Conventional Commits to determine version bumps
- Changelog entries are automatically generated from commit messages
To release a new version:
- Review the open release-please PR to verify the changes and version bump
- Merge the release-please PR into
main - Release-please will automatically:
- Create a GitHub release
- Publish the package to NuGet
- Update the version number
Important: Make sure your commit messages follow conventional commit format (e.g., feat:, fix:, chore:) for proper changelog generation and version bumping.
The legacy manually-generated SDK is maintained on the main-v0 branch for critical bug fixes and vulnerability updates only.
When to use:
- Security vulnerabilities affecting
0.x.xusers - Critical bug fixes that can't wait for users to migrate to
1.x.x
Release process:
-
Create and merge PR to
main-v0:- The
main-v0branch is protected and tracks the0.x.xSDK version - Create your fix/update branch from
main-v0 - Open a PR targeting
main-v0(NOTmain) - Get it reviewed and merged
- The
-
Manually create a release:
- Go to the GitHub Releases page
- Click "Draft a new release"
- Important: Select
main-v0as the target branch (NOTmain) - Set the tag version with
0.prefix (e.g.,0.8.1,0.8.2) - Fill in release notes describing the fixes
- Publish the release
Important Notes:
- Release-please does NOT track the
main-v0branch - releases must be created manually - Always ensure the version number starts with
0.to distinguish it from the1.x.xline - NuGet package publication is handled automatically by GitHub Actions on release creation
To verify which Descope .NET SDK versions are available on NuGet after a release completes, run:
dotnet package search DescopeThis will list the published package versions so you can confirm that the expected version is live.