Kinde.SDK 1.2.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Kinde.SDK --version 1.2.0                
NuGet\Install-Package Kinde.SDK -Version 1.2.0                
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 Include="Kinde.SDK" Version="1.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Kinde.SDK --version 1.2.0                
#r "nuget: Kinde.SDK, 1.2.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Kinde.SDK as a Cake Addin
#addin nuget:?package=Kinde.SDK&version=1.2.0

// Install Kinde.SDK as a Cake Tool
#tool nuget:?package=Kinde.SDK&version=1.2.0                

Overview

The Kinde .NET SDK allows developers to quickly and securely integrate a new or an existing .NET application to the Kinde platform. The Kinde SDK is available from the Nuget package repository at https://www.nuget.org/packages/Kinde.SDK

It contains 3 pre-built OAuth2 grants:

  • Client credentials
  • Authorization code
  • Authorization code with PKCE

Build

Visual Studio automatically recreates the API access client using the Kinde Management API specs on build.

Getting Started

Kinde configuration

Before working with the SDK, it is necessary to create an api and create an application using the Kinde admin panel.

Configuration
Please don't use the constructor without the <code>IIdentityProviderConfiguration</code> parameter, otherwise the constructor will throw exceptions.

Environment settings are located in <code>IIdentityProviderConfiguration</code>. These are common settings for any user in the application's scope. The Identity provider configuration contains the following parameters:

  • Domain: The Kinde domain you have registered with
  • ReplyUrl: When using Authorisation code or PKCE grants, the callback URL as setup in Kinde. This value can be null for client credentials grant.
  • LogoutUrl: Url for redirection after logout.

Additional requirements (based on flow):

  • ClientID: Required for all grants
  • ClientSecret: Required for the Authorisation Code and the client credentials grant
  • Scope: Required for all grants
  • State: Optional. If it's set to null, it will be autogenerated. <b> Note, that this parameter should not be a constant. It should be random for each call.</b>
  • Code verifier generic parameter: Required. Use inbuilt SHA256CodeVerifier, or create another one if needed.

The SDK supports configuring from values defined in the appsetings.json file. Also, you can write your own implementation of IAuthorizationConfigurationProvider and IIdentityProviderConfigurationProvider.

Configuration example:

  "ApplicationConfiguration": {
    "Domain": "https://testauth.kinde.com",
    "ReplyUrl": "https://localhost:7165/home/callback",
    "LogoutUrl":  "https://localhost:7165/home"
  },
  "DefaultAuthorizationConfiguration": {
    "ConfigurationType": "Kinde.Api.Models.Configuration.PKCES256Configuration",
    "Configuration": {
      "State": null,
      "ClientId": "12354359asf123rasfaf",
      "Scope": "openid offline profile",
      "GrantType": "code id_token token",
      "ClientSecret": "<my secret>"
    }
  },

You should register your configuration providers using .NET DI:

builder.Services.AddTransient<IAuthorizationConfigurationProvider, DefaultAuthorizationConfigurationProvider>();
builder.Services.AddTransient<IApplicationConfigurationProvider, DefaultApplicationConfigurationProvider>();

The available grant types are:

  1. Kinde.Api.Models.Configuration.PKCES256Configuration
  2. Kinde.Api.Models.Configuration.AuthorizationCodeConfiguration
  3. Kinde.Api.Models.Configuration.ClientCredentialsConfiguration

Besides configuration, all code approaches are quite similar. The main difference is whether the chosen grant requires redirection/callback.

For the client credentials grant, the Authorize() call is enough for authorization.

For the other 2 grants (PKCE and Authorization Code), you should handle redirection to Kinde (as IdP) and handle callback in your application.

Integration in your application

The main class used for integration is the KindeClientFactory class. It provides thread safe instances of a Kinde client. It is not mandatory to use it, you can create your own solution for your web app to control access.

Authentication
1. Login with no redirection, using the Client Credentials grant

In trusted environments, such as a backend app, the client credentials grant can be used.

Example: <br>

var client = new KindeClient(
    new ApplicationConfiguration("https://testauth.kinde.com", "https://test.domain.com/callback", "https://test.domain.com/logout"),
    new KindeHttpClient());
await client.Authorize(new ClientCredentialsConfiguration("clientId_here", "openid offline any_other_scope", "client secret here", "https://testauth.kinde.com/api"));

// Api call
var orgApi = new OrganizationsApi(client);
var orgs = await orgApi.GetOrganizationsAsync();

After the authorization is complete, you can use the client to call any management API methods.

2. Login with redirection, using PKCE256 flow or Authorization code

For front-end applications, or applications running in an untrusted environment, such as web applications, the Kinde client should be associated with a user session. To keep them in sync, use the <code>KindeClientFactory</code> class. It has a thread safe dictionary to save client instances. It is highly recommended to use KindeCorrelationId or something similar as a key for the instance.

Example:<br>

    public async Task<IActionResult> Login()
    {
        // We need some artificial id to correlate user session to client instance
        // NOTE: Session.Id will be always random, we need to add something to session to make it persistent. 
        var correlationId = HttpContext.Session?.GetString("KindeCorrelationId");
        if (string.IsNullOrEmpty(correlationId))
        {
            correlationId = Guid.NewGuid().ToString();
            HttpContext.Session?.SetString("KindeCorrelationId", correlationId);
        }

        // Get client's instance...
        var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());

        // ...and authorize it
        await client.Authorize(_authConfigurationProvider.Get());

        // if auth flow is not ClientCredentials flow, we need to redirect user to another page
        if (client.AuthorizationState == Api.Enums.AuthorizationStates.UserActionsNeeded)
        {
            // redirect user to login page
            return Redirect(await client.GetRedirectionUrl(correlationId));
        }

        return RedirectToAction("Index");
    }

This code won't authenticate the user completely. We should wait for data on callback endpoint and execute this: <br>

    public IActionResult Callback(string code, string state)
    {
    	KindeClient.OnCodeReceived(code, state);
	    var correlationId = HttpContext.Session?.GetString("KindeCorrelationId");
    	var client = KindeClientFactory.Instance.Get(correlationId); // already authorized instance

	    if(client.AuthorizationState == Kinde.Api.Enums.AuthorizationStates.Authorized) {
		    var organizationId = client.GetOrganization(); // use the client to retrieve details about the user
	    }
	    return RedirectToAction("Index");
    }

Register user

User registration is same as authorization. With one small difference:

    public async Task<IActionResult> SignUp()
    {
        var correlationId = HttpContext.Session?.GetString("KindeCorrelationId");
        if (string.IsNullOrEmpty(correlationId))
        {
            correlationId = Guid.NewGuid().ToString();
            HttpContext.Session.SetString("KindeCorrelationId", correlationId);
        }

        var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
        await client.Register(_authConfigurationProvider.Get()) //<--- Register, if needed
        if (client.AuthorizationState == Api.Enums.AuthorizationStates.UserActionsNeeded)
        {
            return Redirect(await client.GetRedirectionUrl(correlationId));
        }

        return RedirectToAction("Index");
    }
Logout

Logout has two steps: local cache cleanup and token revocation on Kinde side. Call the client.Logout() method. This method returns the redirect url setup for logout. The user should be redirected to it.

Logout example:

    public async Task<IActionResult> Logout()
    {
        var correlationId = HttpContext.Session?.GetString("KindeCorrelationId");
        
        var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
        var url = await client.Logout();
        
        return Redirect(url);
    }
Access token

There is a method GetToken to return the access token with auto-refresh mechanism.

    var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
    var accessToken = client.GetToken(); //returns raw access token
Token renewal

Token will renew automatically in the background. If you want to do it manually, you can call the Renew method. Example:

    public async Task<IActionResult> Renew()
    {
        var correlationId = HttpContext.Session?.GetString("KindeCorrelationId");

        var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
        await client.Renew();

        return RedirectToAction("Index");
    }
Getting user information

There is a method GetUserDetails to get user profile.

    var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
    var claim = client.GetUserDetails(); //returns user profile
Getting token details

Note, that some of claims and properties will be unavailable if scope profile wasn't used while authorizing. In this case null will be returned.

    var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
    var claim = client.GetClaim("sub", "id_token"); //get claim
    var organizations = client.GetOrganizations(); ; //get available organizations
    var organization = client.GetOrganization();  //get single organization
    var permissions = client.GetPermissions(); //get all permissions
    var permission = client.GetPermission("something"); //get permission
Feature Flags - Helper methods

Feature flags are found in the feature_flags claim of the access token.

    var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
    var featureFlag = client.GetFlag("feature_flag_code");
    var stringFlag = client.GetStringFlag("theme");
    var booleanFlag = client.GetBooleanFlag("is_dark_mode");
    var intFlag = client.GetIntegerFlag("competitions_limit");

Additional Usage

Calling APIs

    // Don't forget to add "using Kinde;", all data objects models located in this namespace 
    var client = KindeClientFactory.Instance.GetOrCreate(correlationId, _appConfigurationProvider.Get());
    var userApi = new UsersApi(client);
    var users = await userApi.GetUsersAsync(sort: "name_asc", pageSize: 20, userId: null, nextToken: "next", cancellationToken: CancellationToken.None);
    foreach (User user in users.Users)
    {
        Console.WriteLine($"{user.FirstName} {user.LastName} is awesome!");
    }

The Full API Documentation can be found here.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.9 182 11/6/2024
1.2.8 95 10/31/2024
1.2.7 1,450 8/19/2024
1.2.6 16,035 4/10/2024
1.2.5 5,184 12/8/2023
1.2.4 125 12/7/2023
1.2.3 726 10/23/2023
1.2.2 131 10/17/2023
1.2.0 5,150 6/28/2023
1.1.0 191 4/14/2023
0.0.1 244 11/15/2022

Minor update