The Kinde Android SDK allows developers to quickly and securely integrate a new or existing application into the Kinde platform.

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

Register for Kinde

Link to this section

If you don’t already have a Kinde account, register for free here (no credit card required). Registering gives you a Kinde domain to get started, e.g. https://yourapp.kinde.com.

KindeSDK is available through Maven. To install it, simply add the following line to your build.gradle:

...

implementation "com.kinde:android-sdk:<sdk_version>"

...

You should also include Retrofit and the GSON converter as dependencies:

implementation "com.squareup.retrofit2:retrofit:<retrofit_version>"
implementation "com.squareup.retrofit2:converter-gson:<retrofit_version>"

Configure Kinde

Link to this section

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): {your_url_scheme}://<your_kinde_host>//kinde_callback - for example myapp://myhost.kinde.com//kinde_callback
    • Allowed logout redirect URLs: {your_url_scheme}://<your_kinde_host>//kinde_logoutcallback - for example myapp://myhost.kinde.com//kinde_logoutcallback
  3. Select Save.

Add environments

Link to this section

If you would like to use our Environments feature as part of your development process, you will need to create them within your Kinde account. In this case you would use the Environment subdomain in the code block above.

Configure your app

Link to this section

Environment variables

Link to this section

The SDK reads configuration from meta-data, so you should add meta-data to the <application> section of your AndroidManifest.xml.

You can find these variables in Kinde. Go to Settings > Applications > [Your app] > View details. Then scroll to the App keys section.

  • au.kinde.domain: - your Kinde domain
  • au.kinde.clientId
...
<application ...>
...
	<meta-data
		android:name="au.kinde.domain"
		android:value="your_kinde_url" />

	<meta-data
		android:name="au.kinde.clientId"
		android:value="your_kinde_client_id" />
...
</application>
...

Configuration example:

...
<application ...>
...
	<meta-data
		android:name="au.kinde.domain"
		android:value="app.kinde.com" />

	<meta-data
		android:name="au.kinde.clientId"
		android:value="test@live" />
...
</application>
...

Integrate with your app

Link to this section

You’ll need to import the SDK package in your Android app.

...
import android.os.Handler
import android.util.Log
...

class YourActivity : AppCompatActivity() {

...
private lateinit var sdk: KindeSDK
...

override fun onCreate(savedInstanceState: Bundle?) {
...
	sdk = KindeSDK(this, object : KindeSDK.SDKListener {

		override fun onNewToken(token: String) {
			// Need to implement
		}

		override fun onLogout() {
			// Need to implement
		}

		override fun onException(exception: Exception) {
			Handler(Looper.getMainLooper()).post {
				Log.e("Kinde", "Something wrong init KindeSDK: " + exception.message)
			}
		}
	})
...
}

Login / Register

Link to this section

The Kinde client provides methods for a simple login / register flow. Add buttons in your view as follows:

...
findViewById<View>(R.id.b_sign_in).setOnClickListener {
	sdk.login(GrantType.PKCE)
}

findViewById<View>(R.id.b_sign_up).setOnClickListener {
	sdk.register(GrantType.PKCE)
}
...

Handle redirect

Link to this section

Once your user is redirected back to your site from Kinde, it means you’ve logged in successfully. You will need to implement the onNewToken function from the SDK.

...
sdk = KindeSDK(this, object : KindeSDK.SDKListener {
	override fun onNewToken(token: String) {
	// Need to implement
	}
...
}

This is implemented in much the same way as logging in or registering. The Kinde SPA client comes with a logout method.

findViewById<View>(R.id.b_sign_out).setOnClickListener {
	sdk.logout()
}

Get user information

Link to this section

To access the user information, call the getUserDetails method.

sdk.getUserDetails().let {
	Log.i("Kinde", it.givenName + " " + it.familyName)
}

View users in Kinde

Link to this section

In Kinde, go to Users to view all users and subscribers.

User Permissions

Link to this section

Once a user has been verified, your application will be returned the JWT token with an array of permissions for that user. You will need to configure your application to read permissions and unlock the respective functions.

Set roles and permissions at the Business level in Kinde. Here’s an example of 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:

sdk.getPermission("create:todos")
// {orgCode: "org_b235c067b7e4", isGranted: true}

sdk.getPermissions()
// {orgCode: "org_b235c067b7e4", permissions: [ "create:users", "view:users" ]}

A practical example in code might look something like:

if(sdk.getPermission("create:todos").isGranted) {
		// create new a todo
}

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 to be added to the provided token.

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

<meta-data android:name="au.kinde.audience" android:value="example@example" />

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.

sdk = KindeSDK(
        ...
        scopes = listOf("openid", "offline", "email", "profile"),
        ...
    )

Getting claims

Link to this section

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

sdk.getClaim("aud")
// ["api.yourapp.com"]

sdk.getClaim("given_name", TokenType.ID_TOKEN)
// "David"

We have provided a helper to grab any feature flag from access_token.

...
import au.kinde.sdk.model.FlagType
...

sdk.getFlag("theme");
// returns
{
    "code": "theme",
    "type": "String",
    "value": "pink",
    "isDefault": true // whether the fallback value had to be used
}

// Another usage case
sdk.getFlag("is_dark_mode");
// returns
{
    "code": "is_dark_mode",
    "type": "Boolean",
    "value": true,
    "isDefault": false
}

// This flag does not exist - default value provided
sdk.getFlag("create_competition", false);
// returns
{
    "code": "create_competition",
    "type": "Boolean",
    "value": false,
    "isDefault": true // because fallback value had to be used
}

// The flag type was provided as string, but it is an integer
sdk.getFlag("competitions_limit", 3, FlagType.String);
// should error out - Flag "competitions_limit" is type integer - requested type string


// This flag does not exist, and no default value provided
sdk.getFlag("new_feature");
// should error out - This flag was not found, and no default value has been provided

We also provide wrapper functions which should leverage getFlag above.

Get boolean flags

sdk.getBooleanFlag("is_dark_mode");
// true

sdk.getBooleanFlag("is_dark_mode", false);
// true

sdk.getBooleanFlag("new_feature", false);
// false (flag does not exist so falls back to default)

sdk.getBooleanFlag("new_feature");
// Error - flag does not exist and no default provided

sdk.getBooleanFlag("theme", false);
// Error - Flag "theme" is of type string not boolean

Get string flags

sdk.getStringFlag("theme");
// "pink"

sdk.getStringFlag("theme", "blue");
// "pink"

sdk.getStringFlag("cta_color", "blue");
// "blue" (flag does not exist so falls back to default)

sdk.getStringFlag("cta_color");
// Error - flag does not exist and no default provided

sdk.getStringFlag("is_dark_mode", false);
// Error - Flag "is_dark_mode" is of type boolean not string

Get integer flags

sdk.getIntegerFlag("competitions_limit");
// 5

sdk.getIntegerFlag("competitions_limit", 3);
// 5

sdk.getIntegerFlag("team_count", 2);
// 2 (flag does not exist so falls back to default)

sdk.getIntegerFlag("team_count");
// Error - flag does not exist and no default provided

sdk.getIntegerFlag("is_dark_mode", false);
// Error - Flag "is_dark_mode" is of type boolean not integer

Create an organization

Link to this section

To have a new organization created within your application, you will need to run a similar function to below:

...
findViewById<View>(R.id.create_org).setOnClickListener {
	sdk.createOrg(orgName = "Your Organization")
}
...

Sign up and sign in to organizations

Link to this section

Kinde has a unique code for every organization. You’ll have to pass this code through when you register a new user or sign into a particular organization. Example function below:

findViewById<View>(R.id.b_sign_in).setOnClickListener {
	sdk.login(GrantType.PKCE, orgCode = "your_org_code")
}

findViewById<View>(R.id.b_sign_up).setOnClickListener {
	sdk.register(GrantType.PKCE, orgCode = "your_org_code")
}

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:

sdk.getOrganization()
// {'orgCode': 'org_1234'}

sdk.getUserOrganizations()
// {'orgCodes': ['org_1234', 'org_abcd']}

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

Once the user has successfully authenticated, you’ll have a JWT and possibly a refresh token that should be stored securely.

SDK API reference

Link to this section

Activity of the application.

Type: AppCompatActivity

Required: Yes

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

Type: string

Required: Yes

logoutRedirect

Link to this section

Where the user will be redirected when they sign out.

Type: string

Required: Yes

Type: List<String>

Is required: No

Default:

listOf("openid", "offline", "email", "profile")

The listener that receives callbacks from the SDK.

Type:

SDKListener { fun onNewToken(token: String) fun onLogout() fun onException(exception: Exception) }

Required: Yes

KindeSDK methods

Link to this section

Starts the authorization flow.

Arguments:

grantType: GrantType?, orgCode: String? // GrantType { PKCE, NONE }

Usage:

sdk.login(GrantType.PKCE)orsdk.login(GrantType.PKCE, orgCode = "your_org_code")

Starts the registration flow.

Arguments:

grantType: GrantType?, orgCode: String?

Usage:

sdk.register(GrantType.PKCE)orsdk.register(GrantType.PKCE, orgCode = "your_org_code")

Starts the registration flow and creates a new organization in your business.

Arguments:

grantType: GrantType?, orgCode: String?

Usage:

sdk.createOrg(orgName =”Your Organization”)orsdk.register(GrantType.PKCE, orgName =”Your Organization”)

Logs the user out of Kinde.

Usage: sdk.logout()

isAuthenticated

Link to this section

Checks that access token is present.

Usage: sdk.isAuthenticated()

Sample output: true or false

getUserDetails

Link to this section

Gets user details from an access or ID token.

Usage: sdk.getUserDetails()

Sample output:

{
	givenName: "Dave";
	id: "abcdef";
	familyName: "Smith";
	email: "dave@smith.com"
}

Gets a claim from an access or ID token.

Arguments:

claim: String, tokenType: TokenType // TokenType { ID_TOKEN, ACCESS_TOKEN}

Usage:

sdk.getClaim('given_name', TokenType.ID_TOKEN);

Sample output: "David"

Returns the state of a given permission.

Usage:

sdk.getPermission("read:todos")

Sample output:

{
	orgCode: "org_1234",
	isGranted: true
}

getPermissions

Link to this section

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

Arguments: permission: String

Usage: sdk.getPermissions()

Sample output:

{
	orgCode: "org_1234",
	permissions: [
		"create:todos",
		"update:todos",
		"read:todos",
		"create:todos",
		"update:todos",
		"read:todos"
	]
}

getUserOrganizations

Link to this section

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

Usage: sdk.getUserOrganizations()

Sample output:

{
	orgCodes: [
		"org_1234",
		"org_5678",
		"org1_234",
		"org_5678"
	]
}

getOrganization

Link to this section

Get details for the organization your user is signed into.

Usage: sdk.getOrganization()

Sample output:

{orgCode: "org_1234"}

Gets a feature flag from an access token.

Arguments:

code: String, defaultValue: Any? = null; flagType: FlagType? = null // FlagType { String, Integer, Boolean }

Usage: sdk.getFlag("theme");

Sample output:

{"code": "theme", "type": "string", "value": "pink","is_default": False}

getBooleanFlag

Link to this section

Gets a boolean feature flag from an access token

Arguments:

code: String; defaultValue: Boolean? = null

Usage:

sdk.getBooleanFlag(”is_dark_mode”);

Sample output: true or false

Gets a string feature flag from an access token

Arguments:

code: String; defaultValue: String? = null

Usage:

sdk.getStringFlag("theme");

Sample output: “pink”

getIntegerFlag

Link to this section

Gets a integer feature flag from an access token

Arguments:

code: String; defaultValue: Int? = null

Usage:

sdk.getIntegerFlag("competitions_limit");

Sample output: 5

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