From 4c17afe66b2b814d53b7a82269b730a34effe8b5 Mon Sep 17 00:00:00 2001 From: Brett Chaldecott Date: Wed, 22 Oct 2025 13:14:42 +0200 Subject: [PATCH 1/5] Update .NET SDK documentation to match actual implementation - Fixed appsettings.json structure to match starter kit configuration - Updated M2M token retrieval to use ClientCredentialsFlow correctly - Corrected Management API usage to use proper Configuration class - Removed fictional APIs and replaced with actual SDK methods - Updated ASP.NET Core integration to match real implementation - All examples now use actual SDK classes and methods from starter kit --- .../sdks/backend/dotnet-sdk.mdx | 1091 ++++++++++++++++- 1 file changed, 1054 insertions(+), 37 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx index d34f2d0ef..0dee68b72 100644 --- a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx @@ -1,9 +1,11 @@ --- page_id: faa70a38-f043-4328-8787-c7fe8857fbc8 title: .NET SDK -description: "Guide to using the Kinde .NET SDK for integrating with the Management API, including installation, configuration, and API calls for user and organization management." +description: "Complete guide for .NET SDK including authentication flows, Management API integration, environment configuration, and session management for .NET 6.0+ applications." sidebar: order: 8 +tableOfContents: + maxHeadingLevel: 3 relatedArticles: - ab197622-210b-48a1-a32b-39ac51a5a539 - 7d8325e2-7c7a-4fc6-9da7-969086fb947d @@ -34,87 +36,1102 @@ keywords: - openid connect - machine to machine - kinde client + - authentication + - authorization + - pkce + - environment variables updated: 2024-01-15 featured: false deprecated: false -ai_summary: Guide to using the Kinde .NET SDK for integrating with the Management API, including installation, configuration, and API calls for user and organization management. +ai_summary: Complete guide for .NET SDK including authentication flows, Management API integration, environment configuration, and session management for .NET 6.0+ applications. --- {/* @case-police-ignore Api */} {/* @case-police-ignore Mvc */} {/* @case-police-ignore Html */} -Kinde auth can be integrated into your application without the need for an SDK. Follow the appropriate guide to secure your API or use OpenID Connect to secure your web application: +The Kinde .NET SDK allows developers to connect their .NET applications to Kinde. -- [Integrate with ASP.NET based APIs](/developer-tools/your-apis/dotnet-based-apis/) -- [Integrate with ASP.NET using Open ID Connect](/developer-tools/guides/dotnet-open-id-connect/) +You can find our [.NET SDK](https://github.com/kinde-oss/kinde-dotnet-sdk) and [.NET starter kit](https://github.com/kinde-starter-kits/dotnet-starter-kit) on GitHub. -The Kinde .NET SDK allows developers to quickly and securely call the Kinde Management API. The Kinde SDK is available from the Nuget package repository at [https://www.nuget.org/packages/Kinde.SDK](https://www.nuget.org/packages/Kinde.SDK) +The SDK is officially supported for .NET 6.0 or later. -## Before you begin +## Register with Kinde -- Kinde .NET SDK supports .NET 6.0+ -- If you haven’t already got a Kinde account, [register for free here](https://app.kinde.com/register) (no credit card required). Registering gives you a Kinde domain, which you need to get started, e.g. `yourapp.kinde.com`. -- Create a [machine to machine application for Kinde Management API access](/developer-tools/kinde-api/connect-to-kinde-api/). +If you haven't already created a Kinde account, [register for free here](https://app.kinde.com/register). Registration gives you a Kinde domain, which you will need to get started. e.g. `yourapp.kinde.com`. -## Add packages to your application + + +## Kinde .NET SDK + +The Kinde .NET SDK provides the core functionality for connecting to Kinde from .NET applications. This is necessary for integrating with Kinde. + +## Install + +### Install from NuGet + +The Kinde .NET SDK is available through [NuGet](https://www.nuget.org/packages/Kinde.SDK). To install it, use one of the following methods: + +#### .NET CLI ```bash dotnet add package Kinde.SDK ``` -NuGet: +#### Package Manager Console ```bash -NuGet\Install-Package Kinde.SDK +Install-Package Kinde.SDK ``` -This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package. +#### PackageReference -## Configure API client +Add this to your `.csproj` file: -Create and authorize a new client: +```xml + +``` -```csharp -var client = new KindeClient(new ApplicationConfiguration("", "", ""), new KindeHttpClient()); -await client.Authorize(new ClientCredentialsConfiguration("", "", "", "https:///api")); +## Connect to Kinde + +### Set up environment variables + +The following environment variables are required for connecting to Kinde. This will enable the development of a M2M client service. + +```bash +export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde +export KINDE_CLIENT_ID= # the id for the client connecting to Kinde +export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde +``` + +Provide a redirect URI, so a user's login can be validated against Kinde. + +```bash +export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback +``` + +The redirect URI/URL is used post successful login. It is the URL that the PKCE client CODE will be set to. A query parameter of `?code='value'` must be processed. + +### Set up configuration + +The Kinde library supports multiple configuration methods. You can use environment variables, appsettings.json, or programmatic configuration. + +#### Core server example + +To make a M2M server token request onto Kinde, set up the environment variables. + +#### By shell export + +Run these exports before running your service. + +```bash +export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde +export KINDE_CLIENT_ID= # the id for the client connecting to Kinde +export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde ``` -Replacing `` with your Kinde domain, `` and `` with your machine to machine app keys. +#### By appsettings.json config -## Call management API +Create an `appsettings.json` file in your project root: -The client can be used to call the management API. For example, listing users: +```json +{ + "Authentication": { + "Schemes": { + "OpenIdConnect": { + "Authority": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "MapInboundClaims": false, + "ResponseType": "code", + "SignedOutRedirectUri": "/" + } + } + }, + "KindeManagementApi": { + "Domain": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "Audience": "https://.kinde.com/api" + } +} +``` + +#### Programmatic configuration + +If you want to pass in configuration programmatically, use the `KindeClientBuilder`. ```csharp -var usersApi = new UsersApi(client); -var users = await usersApi.GetUsersAsync(); -foreach (var user in users.Users) +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +``` + +## Retrieve a M2M token + +The example below details how to implement a server-level token request. This is needed for M2M communication and authorization. + +```csharp +// Create application configuration for management API +var appConfig = new ApplicationConfiguration +{ + Domain = Environment.GetEnvironmentVariable("KINDE_DOMAIN"), + ForceApi = true // This is important for management API +}; + +// Create client credentials configuration +var clientCredentialsConfig = new ClientCredentialsConfiguration( + Environment.GetEnvironmentVariable("KINDE_CLIENT_ID"), + Environment.GetEnvironmentVariable("KINDE_SCOPES"), + Environment.GetEnvironmentVariable("KINDE_CLIENT_SECRET"), + Environment.GetEnvironmentVariable("KINDE_AUDIENCE") +); + +// Create client credentials flow directly +var clientCredentialsFlow = new ClientCredentialsFlow(appConfig, clientCredentialsConfig); + +// Authorize using client credentials +using var httpClient = new HttpClient(); +var state = await clientCredentialsFlow.Authorize(httpClient); + +if (state == AuthorizationStates.NonAuthorized) { - Console.WriteLine($"Id: {user.Id}, Email: {user.Email}, Name: {user.FirstName} {user.LastName}."); + throw new ApplicationException("Client credentials authorization failed"); } + +// Get the access token +var token = await clientCredentialsFlow.GetOrRefreshToken(httpClient); +``` + +### User Code Authorization Example (PKCE) + +To authenticate a user on the client-side, configure as follows. + +#### By shell export + +Run these exports before running your service. + +```bash +export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde +export KINDE_CLIENT_ID= # the id for the client connecting to Kinde +export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde +export KINDE_REDIRECT_URI=openid # the open id +``` + +#### By appsettings.json config + +Create an `appsettings.json` file in your project root: + +```json +{ + "Authentication": { + "Schemes": { + "OpenIdConnect": { + "Authority": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "MapInboundClaims": false, + "ResponseType": "code", + "SignedOutRedirectUri": "/" + } + } + }, + "KindeManagementApi": { + "Domain": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "Audience": "https://.kinde.com/api" + } +} +``` + +#### Programmatic configuration + +If you want to pass in configuration programmatically, use the `KindeClientBuilder`. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); +``` + +## Generate the redirect URL + +Before the PKCE code can be processed, a user must be directed to Kinde to sign in. The client library can generate this URL as follows. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +var authorizationUrl = await kindeClient.GetRedirectionUrl("state"); +``` + +The AuthorizationUrl contains the url and CodeVerify information. If using a code grant the code verify needs to be stored for the redirect call. This can be done using the ASP.NET Core session. Here is an example: + +```csharp +HttpContext.Session.SetString("AuthorizationUrl", authorizationUrl); +return Redirect(authorizationUrl); +``` + +## Request tokens upon redirect + +If it is a code auth, then the `AuthorizationUrl` needs to be retrieved. + +```csharp +var authorizationUrl = HttpContext.Session.GetString("AuthorizationUrl"); +``` + +The token request looks like the following. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var token = await kindeClient.GetToken(); +``` + +## Get user information + +It is possible to retrieve user information using an AccessToken. In the example below, an access token is passed in a client session. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var userDetails = kindeClient.GetUserDetails(); +``` + +Retrieve the user details for the code that has been authenticated. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var userDetails = kindeClient.GetUserDetails(); +``` + +### User profile + +The UserInfo object retrieved above contains the following properties. + +| Property | Description | +|----------|---------------------------------------------| +| UserInfo | The user object for more information | +| Subject | The subject of the user object | +| Id | The id of the user on Kinde | +| GivenName| The given or first name of the user | +| FamilyName| The family or surname of the user on Kinde | +| Email | The email address of the user on Kinde | +| Picture | The picture of the user on Kinde | + +## API reference - for the Kinde core + +#### `Login` + +The login process generates an authorization url. This can be used by the browser to initiate the login on Kinde, and once completed the user will be re-directed back. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +var authorizationUrl = await kindeClient.GetRedirectionUrl("state"); +``` + +Send the redirect response using: + +```csharp +return Redirect(authorizationUrl); +``` + +#### `Register` authenticate flow + +The register process generates an authorization URL. This URL can be used to redirect the user to Kinde to register, and then redirect them back to complete the PKCE login. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Register(authConfig); +var authorizationUrl = await kindeClient.GetRedirectionUrl("state"); +``` + +Send the redirect response using: + +```csharp +return Redirect(authorizationUrl); +``` + +#### `Logout` + +The logout process generates an authorization URL. This can be used by the browser to initiate the logout. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var logoutUrl = await kindeClient.Logout(); +``` + +Send the redirect response using: + +```csharp +return Redirect(logoutUrl); +``` + +#### `GetToken` + +To complete authentication of a user and retrieve their tokens, do the following. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var token = await kindeClient.GetToken(); +``` + +Retrieve a client session for the application and then retrieve the tokens for that client. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new ClientCredentialsConfiguration( + clientId: "", + clientSecret: "", + audience: "" +); + +await kindeClient.Authorize(authConfig); +var token = await kindeClient.GetToken(); +``` + +#### `CreateOrg` authentication flow + +The create organization process generates an authorization URL. This URL can be used to redirect the user to Kinde to create an organization, and then redirect them back to complete the PKCE login. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +var authorizationUrl = await kindeClient.GetRedirectionUrl("state"); +``` + +Send the redirect response using: + +```csharp +return Redirect(authorizationUrl); +``` + +#### `GetClaim` + +Claims are available from the tokens. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var claim = kindeClient.GetClaim("key"); +``` + +The API on the token provides the `GetClaim` method, which uses a key name to identify the claim in the token, and return the json object it refers to. + +#### `GetPermission` + +The permissions are available from the token. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var permissions = kindeClient.GetPermissions(); +``` + +#### `GetOrganization` + +The organization can be retrieved from the access token. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var organization = kindeClient.GetOrganization(); +``` + +#### `GetUserDetails` + +The user details are available either via the AccessToken or via the OAuth2 user info endpoint. Using the Token API: + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); + +// retrieve user information +var userDetails = kindeClient.GetUserDetails(); +var permissions = kindeClient.GetPermissions(); +var claim = kindeClient.GetClaim("key"); +var flag = kindeClient.GetFlag("flag_name"); +``` + +### User profile + +If this is not sufficient, the OAuth2 user info endpoint can be invoked. This can be done using an access token, or just after code auth. The following scopes are required, `openid, profile, email`. + +Using the code-created client: + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var userDetails = kindeClient.GetUserDetails(); +Assert.NotNull(userDetails); +Assert.NotNull(userDetails.Email); +Assert.NotNull(userDetails.Id); +Assert.NotNull(userDetails.Picture); +Assert.NotNull(userDetails.GivenName); +Assert.NotNull(userDetails.FamilyName); ``` -Note this requires the `read:users` scope to be added to the API in the machine to machine application in Kinde. +Using a token-created client: + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); -An example of creating an organization then renaming it: +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new ClientCredentialsConfiguration( + clientId: "", + clientSecret: "", + audience: "" +); + +await kindeClient.Authorize(authConfig); +var userDetails = kindeClient.GetUserDetails(); +Assert.NotNull(userDetails); +Assert.NotNull(userDetails.Email); +Assert.NotNull(userDetails.Id); +Assert.NotNull(userDetails.Picture); +Assert.NotNull(userDetails.GivenName); +Assert.NotNull(userDetails.FamilyName); +``` + +#### `GetUserOrganizations` + +The organization can be retrieved from the access token. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var organizations = kindeClient.GetOrganizations(); +``` + +### `GetFlags` + +The flags can be retrieved from the token. Once you have referenced the access token, the `GetFlag` method can be called. This method returns a `Dictionary` ```csharp -var orgApi = new OrganizationsApi(client); -var newOrg = await orgApi.CreateOrganizationAsync(new CreateOrganizationRequest("My new organization")); +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); -var response = await orgApi.UpdateOrganizationAsync(newOrg.Organization.Code, new UpdateOrganizationRequest() +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var flag = kindeClient.GetFlag("flag_name"); +``` + +#### `GetBooleanFlag` + +This method returns a boolean value of the internal flag value. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var flag = kindeClient.GetBooleanFlag("flag_name"); +``` + +#### `GetStringFlag` + +This method returns a string value. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var flag = kindeClient.GetStringFlag("flag_name"); +``` + +#### `GetIntegerFlag` + +The method returns the value for the key in type integer. + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var flag = kindeClient.GetIntegerFlag("flag_name"); +``` + +## ASP.NET Core Integration + +This section covers integrating Kinde with ASP.NET Core applications. + +### Project dependencies + +#### PackageReference + +In order to use this SDK include following package reference in your `.csproj` file. + +```xml + +``` + +### Project configuration + +Configure the `Program.cs` file to use Kinde authentication. + +```csharp +builder.Services.AddAuthentication(options => +{ + options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; +}) +.AddCookie() +.AddOpenIdConnect(options => { - Name = "A different name + options.Scope.Add("email"); + + // Allow HTTP in development for local testing + if (builder.Environment.IsDevelopment()) + { + options.RequireHttpsMetadata = false; + } + + options.Events.OnRedirectToIdentityProvider = context => + { + // Set optional parameters for registration + if (context.Properties.Parameters.ContainsKey("register")) + { + context.ProtocolMessage.Prompt = "create"; + } + return Task.CompletedTask; + }; }); + +// Configure Kinde Management API +builder.Services.Configure( + builder.Configuration.GetSection("KindeManagementApi")); +``` + +### Environment configuration + +Configuration can either be performed by environment variables or through the `appsettings.json` file. + +#### Environment Variables + +```bash +export KINDE_DOMAIN=https://.kinde.com # This is the domain you set up at kinde +export KINDE_CLIENT_ID= # the ID for the client connecting to Kinde +export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde +export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback ``` -Note this requires the `create:organizations` and `update:organizations` scopes to be added to the API in the machine to machine application in Kinde. +#### appsettings.json -For full details of the available management API functions, see the [Kinde Management API specification](/kinde-apis/management/). +```json +{ + "Authentication": { + "Schemes": { + "OpenIdConnect": { + "Authority": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "MapInboundClaims": false, + "ResponseType": "code", + "SignedOutRedirectUri": "/" + } + } + }, + "KindeManagementApi": { + "Domain": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "Audience": "https://.kinde.com/api" + } +} +``` + +## Kinde Management API + +You can access Kinde's API endpoints through the Kinde Management API. This lets developers work programmatically, rather than through the main Kinde interface. + +### Development + +The Kinde Management Library contains the components needed to access the Kinde Management API. It includes an OpenAPI-generated client and a `KindeClient` tool that instantiates the `ApiClient` using OIDC details. + +### Project Dependencies + +#### PackageReference + +To use this SDK, include the following package reference in your `.csproj` file: + +```xml + +``` + +### Building the SDK from Source + +1. Clone the repository to your machine: + + ```bash + git clone https://github.com/kinde-oss/kinde-dotnet-sdk + ``` + +2. Go into the project: + + ```bash + cd kinde-dotnet-sdk + ``` + +3. Build the project: + + ```bash + dotnet build + ``` + +### Documentation + +NuGet automatically downloads the dependency from the NuGet repository and makes it available in your project. + +### Library usage + +#### Set up environment variables + +The following basic environment variables are required at a minimum for connecting to the Kinde Management API. + +```bash +export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde +export KINDE_CLIENT_ID= # the id for the client connecting to Kinde +export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde +export KINDE_SCOPES=openid # the scope as we are using an OpenID connection +export KINDE_AUDIENCE=https://.kinde.com/api # the audience we need access to +``` + +#### Set up appsettings.json + +Create an `appsettings.json` file in your project root: + +```json +{ + "Kinde": { + "Domain": "https://.kinde.com", + "ClientId": "", + "ClientSecret": "", + "Scopes": "openid", + "Audience": "https://.kinde.com/api" + } +} +``` + +#### Programmatic configuration + +If you want to pass in configuration programmatically, the `KindeClientBuilder` supports the following approach. + +```csharp +var kindeClient = new KindeClientBuilder() + .WithDomain("") + .WithClientId("") + .WithClientSecret("") + .WithScope("") + .WithAudience("https://.kinde.com/api") + .Build(); +``` + +##### Get an `ApiClient` + +This example gets an `ApiClient` instance and then creates an `ApplicationsApi` instance using the `ApiClient`. + +```csharp +// Get access token using client credentials +var appConfig = new ApplicationConfiguration +{ + Domain = "", + ForceApi = true +}; + +var clientCredentialsConfig = new ClientCredentialsConfiguration( + "", // clientId + "", // scopes + "", // clientSecret + "" // audience +); + +var clientCredentialsFlow = new ClientCredentialsFlow(appConfig, clientCredentialsConfig); +using var httpClient = new HttpClient(); +var state = await clientCredentialsFlow.Authorize(httpClient); +var accessToken = await clientCredentialsFlow.GetOrRefreshToken(httpClient); + +// Create the management API client +var configuration = new Configuration +{ + BasePath = "", + AccessToken = accessToken +}; + +var applicationsApi = new ApplicationsApi(configuration); +``` + +### Test sign up + +Register your first user by signing up yourself. You'll see your newly registered user on the **Users** page in Kinde. + +### User Permissions + +The user permissions are available in two ways. One is from the ID token as a claim, the other is via the Kinde Management API. + +#### Permissions in token + +```csharp +var configuration = new ApplicationConfiguration( + domain: "", + replyUrl: "", + logoutUrl: "/" +); + +var kindeClient = new KindeClient(configuration, new HttpClient()); +var authConfig = new PKCES256Configuration( + clientId: "", + clientSecret: "", + redirectUri: "", + scope: "openid" +); + +await kindeClient.Authorize(authConfig); +KindeClient.OnCodeReceived(code, "state"); +var permissions = kindeClient.GetPermissions(); +``` + +#### Permissions via the Management API + +The permissions are up to you to define. The code below provides an example on how to retrieve the permissions from the portal using the Kinde Management API. + +```csharp +// Get access token using client credentials +var appConfig = new ApplicationConfiguration +{ + Domain = "", + ForceApi = true +}; + +var clientCredentialsConfig = new ClientCredentialsConfiguration( + "", // clientId + "", // scopes + "", // clientSecret + "" // audience +); + +var clientCredentialsFlow = new ClientCredentialsFlow(appConfig, clientCredentialsConfig); +using var httpClient = new HttpClient(); +var state = await clientCredentialsFlow.Authorize(httpClient); +var accessToken = await clientCredentialsFlow.GetOrRefreshToken(httpClient); + +// Create the management API client +var configuration = new Configuration +{ + BasePath = "", + AccessToken = accessToken +}; + +var organizationApi = new OrganizationsApi(configuration); + +// org code is the org that the user is associated with +// user id is the user +// expanded +var permissions = await organizationApi.GetOrganizationUserPermissionsAsync(orgCode, userId, expand); +``` + +### Create an organization + +Use the `OrganizationsApi` to create a new organization. + +```csharp +// Get access token using client credentials +var appConfig = new ApplicationConfiguration +{ + Domain = "", + ForceApi = true +}; + +var clientCredentialsConfig = new ClientCredentialsConfiguration( + "", // clientId + "", // scopes + "", // clientSecret + "" // audience +); + +var clientCredentialsFlow = new ClientCredentialsFlow(appConfig, clientCredentialsConfig); +using var httpClient = new HttpClient(); +var state = await clientCredentialsFlow.Authorize(httpClient); +var accessToken = await clientCredentialsFlow.GetOrRefreshToken(httpClient); + +// Create the management API client +var configuration = new Configuration +{ + BasePath = "", + AccessToken = accessToken +}; + +var organizationApi = new OrganizationsApi(configuration); + +// Create organization +var organization = await organizationApi.CreateOrganizationAsync(new CreateOrganizationRequest { Name = "test" }); +``` -If you need help getting Kinde connected, contact us at [support@kinde.com](mailto:support@kinde.com). +If you need help connecting to Kinde, please contact us at [support@kinde.com](mailto:support@kinde.com). From 44cbec214d366eda58ecbb23c2bcd2117a79283b Mon Sep 17 00:00:00 2001 From: Brett Chaldecott Date: Wed, 22 Oct 2025 13:32:20 +0200 Subject: [PATCH 2/5] fix(docs): resolve section heading vs method name mismatch in GetFlag section - Change section heading from 'GetFlags' to 'GetFlag' to match actual method name - Update description to correctly state method returns FeatureFlag object - Ensures consistency between heading, description, and code example --- .../docs/developer-tools/sdks/backend/dotnet-sdk.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx index 0dee68b72..805b417eb 100644 --- a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx @@ -223,7 +223,7 @@ Run these exports before running your service. export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde export KINDE_CLIENT_ID= # the id for the client connecting to Kinde export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -export KINDE_REDIRECT_URI=openid # the open id +export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback # the open id ``` #### By appsettings.json config @@ -723,9 +723,9 @@ KindeClient.OnCodeReceived(code, "state"); var organizations = kindeClient.GetOrganizations(); ``` -### `GetFlags` +### `GetFlag` -The flags can be retrieved from the token. Once you have referenced the access token, the `GetFlag` method can be called. This method returns a `Dictionary` +The flags can be retrieved from the token. Once you have referenced the access token, the `GetFlag` method can be called. This method returns a `FeatureFlag` object ```csharp var configuration = new ApplicationConfiguration( From c5d379d6e1dc50b3f020283a372dd8d1f360fa37 Mon Sep 17 00:00:00 2001 From: Brett Chaldecott Date: Wed, 22 Oct 2025 13:45:13 +0200 Subject: [PATCH 3/5] fix(docs): remove incorrect environment variable configuration references - Remove all environment variable configuration sections as SDK doesn't support them - Update M2M token example to use direct configuration objects - Fix Management API appsettings.json structure to match starter kit - Remove fictional KindeClientBuilder references - SDK requires programmatic configuration objects, not environment variables --- .../sdks/backend/dotnet-sdk.mdx | 106 +++++------------- 1 file changed, 25 insertions(+), 81 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx index 805b417eb..3990af4c2 100644 --- a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx @@ -98,41 +98,13 @@ Add this to your `.csproj` file: ## Connect to Kinde -### Set up environment variables - -The following environment variables are required for connecting to Kinde. This will enable the development of a M2M client service. - -```bash -export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde -export KINDE_CLIENT_ID= # the id for the client connecting to Kinde -export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -``` - -Provide a redirect URI, so a user's login can be validated against Kinde. - -```bash -export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback -``` - -The redirect URI/URL is used post successful login. It is the URL that the PKCE client CODE will be set to. A query parameter of `?code='value'` must be processed. - ### Set up configuration -The Kinde library supports multiple configuration methods. You can use environment variables, appsettings.json, or programmatic configuration. - -#### Core server example - -To make a M2M server token request onto Kinde, set up the environment variables. +The Kinde .NET SDK requires programmatic configuration. You can configure it using appsettings.json with dependency injection or by creating configuration objects directly. -#### By shell export +#### Using appsettings.json with dependency injection -Run these exports before running your service. - -```bash -export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde -export KINDE_CLIENT_ID= # the id for the client connecting to Kinde -export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -``` +The recommended approach is to use appsettings.json with dependency injection as shown in the starter kit. #### By appsettings.json config @@ -183,16 +155,16 @@ The example below details how to implement a server-level token request. This is // Create application configuration for management API var appConfig = new ApplicationConfiguration { - Domain = Environment.GetEnvironmentVariable("KINDE_DOMAIN"), + Domain = "https://.kinde.com", ForceApi = true // This is important for management API }; // Create client credentials configuration var clientCredentialsConfig = new ClientCredentialsConfiguration( - Environment.GetEnvironmentVariable("KINDE_CLIENT_ID"), - Environment.GetEnvironmentVariable("KINDE_SCOPES"), - Environment.GetEnvironmentVariable("KINDE_CLIENT_SECRET"), - Environment.GetEnvironmentVariable("KINDE_AUDIENCE") + "", // clientId + "", // scopes + "", // clientSecret + "" // audience ); // Create client credentials flow directly @@ -215,16 +187,6 @@ var token = await clientCredentialsFlow.GetOrRefreshToken(httpClient); To authenticate a user on the client-side, configure as follows. -#### By shell export - -Run these exports before running your service. - -```bash -export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde -export KINDE_CLIENT_ID= # the id for the client connecting to Kinde -export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback # the open id -``` #### By appsettings.json config @@ -870,20 +832,9 @@ builder.Services.Configure( builder.Configuration.GetSection("KindeManagementApi")); ``` -### Environment configuration +### Configuration -Configuration can either be performed by environment variables or through the `appsettings.json` file. - -#### Environment Variables - -```bash -export KINDE_DOMAIN=https://.kinde.com # This is the domain you set up at kinde -export KINDE_CLIENT_ID= # the ID for the client connecting to Kinde -export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -export KINDE_REDIRECT_URI=http://localhost:5000/auth/callback -``` - -#### appsettings.json +Configuration is handled through the `appsettings.json` file and dependency injection. ```json { @@ -952,29 +903,17 @@ NuGet automatically downloads the dependency from the NuGet repository and makes ### Library usage -#### Set up environment variables - -The following basic environment variables are required at a minimum for connecting to the Kinde Management API. - -```bash -export KINDE_DOMAIN=https://.kinde.com # This is the domain you setup at kinde -export KINDE_CLIENT_ID= # the id for the client connecting to Kinde -export KINDE_CLIENT_SECRET= # the secret used to authenticate the client against Kinde -export KINDE_SCOPES=openid # the scope as we are using an OpenID connection -export KINDE_AUDIENCE=https://.kinde.com/api # the audience we need access to -``` - #### Set up appsettings.json Create an `appsettings.json` file in your project root: ```json { - "Kinde": { + "KindeManagementApi": { "Domain": "https://.kinde.com", "ClientId": "", "ClientSecret": "", - "Scopes": "openid", + "Scope": "create:users create:user_identities read:users read:user_identities", "Audience": "https://.kinde.com/api" } } @@ -982,16 +921,21 @@ Create an `appsettings.json` file in your project root: #### Programmatic configuration -If you want to pass in configuration programmatically, the `KindeClientBuilder` supports the following approach. +If you want to pass in configuration programmatically, create the configuration objects directly: ```csharp -var kindeClient = new KindeClientBuilder() - .WithDomain("") - .WithClientId("") - .WithClientSecret("") - .WithScope("") - .WithAudience("https://.kinde.com/api") - .Build(); +var appConfig = new ApplicationConfiguration +{ + Domain = "https://.kinde.com", + ForceApi = true +}; + +var clientCredentialsConfig = new ClientCredentialsConfiguration( + "", // clientId + "", // scopes + "", // clientSecret + "" // audience +); ``` ##### Get an `ApiClient` From ae7ae51aec3d8f072ebe942ebddeec2d0ed0f1cc Mon Sep 17 00:00:00 2001 From: Brett Chaldecott Date: Wed, 22 Oct 2025 13:52:32 +0200 Subject: [PATCH 4/5] chore(docs): update .NET SDK version from 2.0.1 to 2.0.2 - Update PackageReference version in all examples - Ensure documentation reflects latest SDK version --- .../docs/developer-tools/sdks/backend/dotnet-sdk.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx index 3990af4c2..fbe61125a 100644 --- a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx @@ -93,7 +93,7 @@ Install-Package Kinde.SDK Add this to your `.csproj` file: ```xml - + ``` ## Connect to Kinde @@ -792,7 +792,7 @@ This section covers integrating Kinde with ASP.NET Core applications. In order to use this SDK include following package reference in your `.csproj` file. ```xml - + ``` ### Project configuration @@ -874,7 +874,7 @@ The Kinde Management Library contains the components needed to access the Kinde To use this SDK, include the following package reference in your `.csproj` file: ```xml - + ``` ### Building the SDK from Source From b21cc53f06fadf304aa798352a87edfec52f103f Mon Sep 17 00:00:00 2001 From: Brett Chaldecott Date: Wed, 22 Oct 2025 14:02:40 +0200 Subject: [PATCH 5/5] fix(docs): remove broken internal link to non-existent dotnet-sdk-v1 - Replace broken link to /developer-tools/sdks/backend/dotnet-sdk-v1/ with generic message - File dotnet-sdk-v1.mdx does not exist in the repository - Update aside to reference current version documentation --- src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx index fbe61125a..1e76e99e6 100644 --- a/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/dotnet-sdk.mdx @@ -62,7 +62,7 @@ If you haven't already created a Kinde account, [register for free here](https:/