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

You can also view the .NET docs and .NET starter kit in GitHub.

Before you begin

Link to this section
  • Kinde .NET SDK supports .NET 6.0+
  • If you haven’t already got a Kinde account, register for free here (no credit card required). Registering gives you a Kinde domain, which you need to get started, e.g. yourapp.kinde.com.

Add packages to your application

Link to this section

Use Dotnet CLI or NuGet CLI to add packages in your project.

Dotnet CLI:

dotnet add package Kinde.SDK

NuGet:

NuGet\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.

Set callback URLs

Link to this section
  1. In Kinde, go to Settings > Applications > [Your app] > View details.
  2. Add your callback URLs in the relevant fields. For example:
    • Allowed callback URLs (also known as redirect URIs) - for example: https://localhost:6789/home/callback
    • Allowed logout redirect URLs - for example: https://localhost:6789
  3. Select Save.

Add environments

Link to this section

Kinde comes with a production environment, but you can set up other environments if you want to. Note that each environment needs to be set up independently, so you need to use the Environment subdomain in the code block above for those new environments.

Configure your app

Link to this section

Environment variables

Link to this section

Put these variables in your .env file:

  • KINDE_SITE_URL - where your app is running
  • KINDE_ISSUER_URL - your Kinde domain
  • KINDE_POST_CALLBACK_URL - After the user authenticates we will callback to this address. Make sure this URL is under your Allowed callback URLs (also known as redirect URIs).
  • KINDE_POST_LOGOUT_REDIRECT_URL - where you want users to be redirected to after logging out. Make sure this URL is under your allowed logout redirect URLs.
  • KINDE_CLIENT_ID - you can find this on the Application details page
  • KINDE_CLIENT_SECRET - you can find this on the Application details page

SDK also supports configuration from the appsetings.json file. If you want, you can write your own implementation of IAuthorizationConfigurationProvider and IIdentityProviderConfigurationProvider.

{
...
"KindeSettings": {
    "Domain": <KINDE_ISSUER_URL>,
    "CallbackUrl": <KINDE_POST_CALLBACK_URL>
},
"ApplicationConfiguration": {
    "Domain": <KINDE_ISSUER_URL>,
    "ReplyUrl": <KINDE_POST_CALLBACK_URL>,
    "LogoutUrl": <KINDE_POST_LOGOUT_REDIRECT_URL>
},
"DefaultAuthorizationConfiguration": {
    "ConfigurationType": "Kinde.Api.Models.Configuration.<THE_LOGIN_METHOD_YOU_PREFER>",
    "Configuration": {
        "State": null,
        "ClientId": <KINDE_CLIENT_ID>,
        "Scope": "openid offline profile",
        "GrantType": "code id_token token",
        "ClientSecret": <KINDE_CLIENT_SECRET>
    }
},
...
}

Replace everything in < angle brackets > with your own values. Here’s an example:

{
...
"KindeSettings": {
    "Domain": "https://your_kinde_domain.kinde.com",
    "CallbackUrl": "https://localhost:7165/home/callback"
},
"ApplicationConfiguration": {
    "Domain": "https://your_kinde_domain.kinde.com",
    "ReplyUrl": "https://localhost:7165/home/callback",
    "LogoutUrl":  "https://localhost:7165/home"
},
"DefaultAuthorizationConfiguration": {
    "ConfigurationType": "Kinde.Api.Models.Configuration.PKCES256Configuration",
    "Configuration": {
        "State": null,
        "ClientId": your_kinde_client_id,
        "Scope": "openid offline profile",
        "GrantType": "code id_token token",
        "ClientSecret": your_kinde_client_secret
    }
},
...
}

In your startup file (usually called Startup.cs or Program.cs), register configuration providers using .NET DI:

builder.Services.AddTransient<IAuthorizationConfigurationProvider, DefaultAuthorizationConfigurationProvider>();
builder.Services.AddTransient<IApplicationConfigurationProvider, DefaultApplicationConfigurationProvider>();
builder.Services.AddSession();
...
var app = builder.Build();
app.UseSession();

Note: The above configuration providers are referenced in the Kinde.Api.Models.Configuration and the Microsoft.AspNetCore.Session assembly. Those assemblies must be added to your project.

PKC256 Configuration example:

This is the most complicated configuration. The configuration for the Authentication code is the same. For Client credentials, State is not applicable, but you don’t need to remove it.

All available 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 only difference is if the authorization flow requires user redirection. In which case, for Client Credentials configuration Authorize() call is enough for authorization. For others (PKCE and Authorization code) you should handle redirection to Kinde (as IdP) and handle callback to end authorization.

Integrate with your app

Link to this section

You’ll need to declare your configurations provider in your controller.

...
using Kinde.Api;
using Kinde.Api.Client;
using Kinde.Api.Models.Configuration;
using Microsoft.AspNetCore.Mvc;
...

public class YourController : Controller
{
...
		private readonly IAuthorizationConfigurationProvider _authConfigurationProvider;
		private readonly IApplicationConfigurationProvider _appConfigurationProvider;
...

		public YourController (..., IAuthorizationConfigurationProvider authConfigurationProvider, IApplicationConfigurationProvider appConfigurationProvider)
		{
		...
				_authConfigurationProvider = authConfigurationProvider;
				_appConfigurationProvider = appConfigurationProvider;
		...
		}
}

Log in and registration

Link to this section

The Kinde client provides methods for easy sign in and register flows.

For example, if add buttons in your HTML as follows:

<div class="navigation">
    @Html.ActionLink("Sign in","Login", "YourController") @Html.ActionLink("Sign up","Signup", "
    YourController")
</div>

Then define new actions in YourController:

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 == Kinde.Api.Enums.AuthorizationStates.UserActionsNeeded)
	{
		// redirect user to login page
		return Redirect(await client.GetRedirectionUrl(correlationId));
	}
		return RedirectToAction("Index");
}

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());

	if (client.AuthorizationState == Kinde.Api.Enums.AuthorizationStates.UserActionsNeeded)
	{
		return Redirect(await client.GetRedirectionUrl(correlationId));
	}

	return RedirectToAction("Index");
}

When defining the above methods in your controller class, ensure that Kinde assembly is included by adding using Kinde;

Manage redirects

Link to this section

When the user is redirected back to your site from Kinde, this code executes:

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");
}

Logging out is a two step process: local cache cleanup and token revocation on the Kinde side.

When the client.Logout() method is called, it redirects the user to a redirect URL for token revocation.

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);
}

Get user information

Link to this section

You need to have already authenticated before you call the API, otherwise errors can happen. To access the user information, use the GetUserDetails method:

public async Task<IActionResult> Index()
{
	if (HttpContext.Session.GetString("KindeCorrelationId") != null)
	{
		var client = KindeClientFactory.Instance.Get(HttpContext.Session.GetString("KindeCorrelationId"));

		if(client.AuthorizationState == Kinde.Api.Enums.AuthorizationStates.Authorized)
		{
			ViewBag.Authorized = true;
			var model = await client.GetUserDetails();
			return View("Index", model);
		}
	}
	return View("Index");
}

View users in Kinde

Link to this section

Go to the Users page in Kinde to see who has registered.

User permissions

Link to this section

After a user signs in and they are verified, the token return includes permissions for that user. User permissions are set in Kinde, but you must also configure your application to unlock these functions.

Example permissions:

String[] permissions = {
	"create:todos",
	"update:todos",
	"read:todos",
	"delete:todos",
	"create:tasks",
	"update:tasks",
	"read:tasks",
	"delete:tasks",
}

We provide helper functions to more easily access permissions:

client.GetPermission("create:todos");
// { OrganizationId: "org_1234", Granted: True, Id: "create:todos"}

client.GetPermissions();
// { OrganizationId: "org_1234", Permissions: {"create:todos", "update:todos", "read:todos"}}

A practical example in code might look something like:

if (client.GetPermission("create:todos").Granted) {
    // Need to implement
}

An audience is the intended recipient of an access token - for example the API for your application. The audience argument can be passed to the Kinde client to request an audience be added to the provided token.

The audience of a token is the intended recipient of the token.

{
	...
	Audience: "api.yourapp.com"
	...
}

For details on how to connect, see Register an API

Overriding scope

Link to this section

By default the KindeSDK requests the following scopes:

  • profile
  • email
  • offline
  • openid

You can override this by passing scope into the KindeSDK.

{
	...
	Scope: "openid offline profile email"
	...
}

Getting claims

Link to this section

We have provided a helper to grab any claim from your id or access tokens:

client.GetClaim("given_name");
// "David"

Create an organization

Link to this section

To have a new organization created within your application, you will need to run declare IsCreateOrganization in your configuration:

{
	...
	IsCreateOrganization: "true"
	...
}

Sign and sign in to organizations

Link to this section

Kinde has a unique code for every organization. You’ll have to pass the OrganizationId when you want to register a new user or sign into a particular organization.

{
	...
	OrganizationId: "org_1234"
	...
}

Following authentication, Kinde provides a json web token (jwt) to your application. Along with the standard information we also include the org_code and the permissions for that organization (this is important as a user can belong to multiple organizations and have different permissions for each).

Example of a returned token:

{
    "aud": [],
    "exp": 1658475930,
    "iat": 1658472329,
    "iss": "https://your_subdomain.kinde.com",
    "jti": "123457890",
    "org_code": "org_1234",
    "permissions": ["read:todos", "create:todos"],
    "scp": ["openid", "profile", "email", "offline"],
    "sub": "kp:123457890"
}

The id_token will also contain an array of organizations that a user belongs to - this is useful if you wanted to build out an organization switcher for example.

{
	...
	"org_codes": ["org_1234", "org_4567"]
	...
}

There are two helper functions you can use to extract information:

client.GetOrganization();
// "org_1234"

client.GetOrganizations();
// ["org_1234", "org_abcd"]

For more information about how organizations work in Kinde, see Kinde organizations for developers.

SDK API reference

Link to this section

Either your Kinde instance url or your custom domain. e.g https://yourapp.kinde.com

Type: string

Required: Yes

The URL that the user will be returned to after authentication.

Type: string

Required: Yes

The URL that the user will be returned to after they sign out.

Type: string

Required: Yes

The audience claim for the JWT.

Type: string

Required: No

The unique ID of your application as it appears in Kinde.

Type: string

Required: Yes

The unique secret identifier for your application as it appears in Kinde.

Type: string

Required: Yes

The scopes to be requested from Kinde.

Type: string

Required: Yes

The grant type to define is the flow that will be used.

Type: string

Required: Yes

IsCreateOrganization

Link to this section

Use this field when you want to create a new organization within your application

Type: boolean

Required: No

OrganizationId

Link to this section

Use this field when you want to register a new user or sign into a particular organization.

Type: string

Required: No

KindeSDK methods

Link to this section

Constructs a redirect URL and sends the user to Kinde to sign in.

Arguments:

configuration: IAuthorizationConfiguration

Usage:

kinde.Authorize();

Constructs a redirect URL and sends the user to Kinde to sign up.

Arguments:

configuration: IAuthorizationConfiguration

Usage:

kinde.Register();

Logs the user out of Kinde.

Usage:

kinde.Logout();

Trying to get a new token using refresh_token.

Usage:

kinde.Renew();

Gets a claim from an access or ID token.

Arguments:

claim: string

Usage:

kinde.GetClaim("given_name");

Sample output:

"David"

Returns the state of a given permission.

Arguments:

key: string

Usage:

kinde.GetPermission(”read:todos”);

Sample output:

{
	OrganizationId: "org_1234",
	Granted: True,
	Id: "create:todos"
}

GetPermissions

Link to this section

Returns all permissions for the current user for the organization they are signed into.

Usage:

kinde.GetPermissions();

Sample output:

{
	OrganizationId: "org_1234",
	Permissions: {"create:todos", "update:todos", "read:todos" }
}

GetOrganization

Link to this section

Get details for the organization your user is signed into.

Usage:

kinde.GetOrganization();

Sample output:

"org_1234"

GetOrganizations

Link to this section

Gets an array of all organizations the user has access to.

Usage:

kinde.GetOrganizations();

Sample output:

["org_1234", "org_abcd"]

IsAuthenticated

Link to this section

To check if a user is authenticated or not.

Usage:

kinde.IsAuthenticated;

Sample output:

True or False

Returns the raw Access token from URL after logged from Kinde.

Usage:

kinde.Token;

Sample output:

{
    "AccessToken": "some_value",
    "ExpiresIn": 1234,
    "Scope": "some_value",
    "TokenType": "some_value",
    "IdToken": "some_value",
    "RefreshToken": "some_value"
}

Returns the profile for the current user.

Usage:

kinde.User;

Sample output:

{
    "GivenName": "Dave",
    "Id": "abcdef",
    "FamilyName": "Smith",
    "Email": "dave@smith.com"
}

If you need help getting Kinde connected, contact us at support@kinde.com.


Talk to us

If you can’t find what you’re looking for in our help center — email our team

Contact support