The Kinde Ruby SDK gem allows developers to integrate Kinde API into any ruby-based applications, Rails or non-Rails.

The gem contains all the related oauth2 authorization, and 3 pre-built OAuth flows: client credentialsauthorization code and authorization code with PKCE code verifier.

Register for Kinde

Link to this section

If you haven’t already got a Kinde account, register for free here (no credit card required).

You also need a Kinde domain to get started, e.g.

Add this line into your Gemfile and run a bundler or install manually through a gem command.

gem 'kinde_sdk'

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, http://localhost:8000/callback
    • Allowed logout redirect URLs - for example, http://localhost:8000
  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

The following variables need to be replaced in the code snippets below.

  • KINDE_HOST - your Kinde domain - e.g.
  • KINDE_REDIRECT_URL - your callback url, make sure this URL is under your allowed callback redirect URLs. - e.g. http://localhost:8000/callback
  • 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. - e.g. http://localhost:8000
  • KINDE_CLIENT_ID - you can find this on the Application details page - e.g. your_kinde_client_id
  • KINDE_CLIENT_SECRET - you can find this on the Application details page - e.g. your_kinde_client_secret

Integrate with your app

Link to this section

You can easily configure via the gem. For example, in a typical Rails-app it can be configured through the initializer file:

KindeSdk.configure do |c|
 c.domain = domain
 c.client_id = client_id
 c.client_secret = client_secret
 c.callback_url = callback_url
 c.logout_url = logout_url
 # c.scope = 'openid offline email profile' # default value
 # c.pkce_enabled = true                    # default value
 # c.authorize_url = '/oauth2/auth'         # default value
 # c.token_url = '/oauth2/token'            # default value
 # c.debugging = false                      # default value
 # c.business_name = nil                    # default value
 c.logger = Rails.logger

The snippet above contains all the possible configuration values. Here is detailed explanation of them:

  • Domain refers to your organization - for example,
  • Client id and Client secret can be found in Kinde. Go to Settings > Applications > [yourapplication] > Details.
  • Callback url (or redirect URI) refers to the callback processing action. The URL must be defined in the Allowed callback URLs section of your application.
  • Logout url will open when the user signs out. The URL must be defined in the Allowed callback URLs section of your application.
  • Scope is an Oauth special parameter which is used to limit some rights.
  • PKCE enabled is a flag that can turn off PKCE auth flow. By default it is activated to improve security.
  • Authorize url and Token url are paths to Oauth2 methods in kinde.
  • Debugging set to True for long request logs. Can be useful while developing your application.
  • Business name is a parameter which is used in requests building. By default it is extracted from your Kinde domain endpoint. For example, if your domain is, then business name will be set toyour-biz. You don’t need to change it.
  • Logger set to whichever kind of loggers you are using. By default it is set to Rails.logger if gem is used in rails application or if it is not a rails app.

These variables can be handled with any system you want: .env files, settings.yml or any type of config files. For example, .env file (you can name variables by yourself):


can be used as:

KindeSdk.configure do |c|
 c.domain = ENV['KINDE_DOMAIN']
 c.client_id = ENV['KINDE_CLIENT_ID']
 # ....

Sign in and registration

Link to this section

The Kinde client provides methods for easy login / registration. For this, you need to acquire auth url by calling:

# =>
 url: "https://<domain>/oauth2/auth?client_id=<client_id>&code_challenge=<generated code>&code_challenge_method=S256&redirect_uri=<redirect_uri>&response_type=code&scope=openid+offline+email+profile&state=<random string>",
 code_verifier: "<challenge verifier>"

By default, gem uses the PKCE verification flow. This means that the code challenge param will be added to your auth url, and the method returns verification string for the code. This can also be used in token requests. You can disable PKCE by setting pkce_enabled to false in your configuration. In this case, KindeSdk.auth_url will only return a url:

# => {url: ......}

If you are about to use PCKE, our recommendation to save code verifier output somewhere near your later tokens output.

Put the link in your web-application page or use it under the hood as a redirect. After visiting the link users are redirected to Kinde’s sign in/sign up form. And after authorizing in Kinde, they are redirected to the callback url.

Manage redirects

Link to this section

The next step is to extract code from the callback redirect. Your callback endpoint should contain logic to call the exchange method. Callback is triggered in the body with the code. Use the whole params object or to extract code from params["code"].

Next, exchange access and refresh tokens. You will receive code as the parameter in the callback endpoint, and code_verifier (if PKCE enabled) as per the previous step.

KindeSdk.fetch_tokens(code, code_verifier)
# =>
 "scope"=>"openid offline email profile",

Save the whole hash in your session, redis or any other storage, and use it to build your client.

# In case of preventing cookie overflow, you need to limit what exactly your are saving.# Here is the required minimum of params. But in general you are able save it wherever you want to.# For example, in database, without any limiting.
session[:kinde_auth] = KindeSdk.fetch_tokens(code).slice(:access_token, :refresh_token, :expires_at)
# ...
client = KindeSdk.client(session[:kinde_auth]["access_token"])# => #<KindeSdk::Client:0x00007faf31e5ecb8>

For logout you need to get the logout URL and redirect to it:

redirect_to KindeSdk.logout_url, allow_other_host: true

If you configured logout redirect_url correctly, you will receive a logout callback. Use it to perform clean-ups, clear your session or storage (delete your token) and redirect to wherever you want to.

Get user information

Link to this section

You need to have already authenticated before you call the API, otherwise an error will occur.

Use the Kinde\KindeSDK\Api\OAuthApi class, then call the getUser method.

# => {id: ..., preferred_email: ..., provided_id: ..., last_name: ..., first_name: ...}

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.

"permissions" => [

We provide helper functions to more easily access permissions:

client = KindeSdk.client(session[:kinde_auth]["access_token"])
client.get_permission("create:todos")# => {org_code: "org_1234", is_granted: true}
client.permission_granted?("create:todos")# => true
client.permission_granted?("create:orders")# => false

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 #auth_url method to request an audience be added to the provided token:

KindeSdk.auth_url(audience: "<>")

For details on how to connect, see Register an API.

Overriding scope

Link to this section

By default KindeSdk requests the following scopes:

  • profile
  • email
  • offline
  • openid

You can change scopes by configuring then when you install or by direct param passing into auth_url method:

KindeSdk.auth_url(scope: "openid offline")

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:

client = KindeSdk.client(session[:kinde_auth]["access_token"])
client.get_claim("aud")#=> ['']
client.get_claim("scp")#=> ["openid", "offline"]

Create an organization

Link to this section

To have a new organization created within your application, you will need to run something like:

client.organizations.create_organization(create_organization_request: {name: "new_org"})
# or `client.organizations.create_organization` without name

Sign up and sign in to organizations

Link to this section

Kinde has a unique code for every organization. If you want a user to sign into a particular organization, call the #auth_url method with org_code param passing:

KindeSdk.auth_url(org_code: "org_1234", start_page: "registration")# to enforce new user creation form
KindeSdk.auth_url(org_code: "org_1234")# to login by default

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" => "",
    "jti" => "123457890",
    "org_code" => "org_1234",
    "permissions" => ["read:todos", "create:todos"],
    "scp" => [
    "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:

client.get_claim("org_codes")# => ["org_1234", "org_5462"]

Getting user info

Link to this section
# => {id: ..., preferred_email: ..., provided_id: ..., last_name: ..., first_name: ...}

Kinde management API

Link to this section

The sections below relate to the Kinde Management API. You need to add a machine to machine application and get an access token to connect:

result = KindeSdk.client_credentials_access(
# as an example of usage redis to save access token:
$redis.set("kinde_m2m_token", result["access_token"], ex: result["expires_in"].to_i)

Organizations handling

Link to this section
client = KindeSdk.client($redis.get("kinde_m2m_token"))
# get organizations list:
# => {"code": "OK", "message": "Success", "next_token": "qweqweqwe", "organizations": [{"code": "org_casda123c", "name": "Default Organization", "is_default": true}]}
# create new organization:
client.organizations.create_organization(create_organization_request: {name: "new_org"})
# this variant for more strict input params validation:
# client.organizations.create_organization(create_organization_request: new_org_name))

Create new user

Link to this section

Add organization users

Link to this section
client.organizations.add_organization_users(code: "org_1111", users: ["kp:12311...."])

Token expiration and refreshing

Link to this section

For proper refreshing you’ll need to use access_tokenrefresh_token and probably expires_in if you want to know if your access token still active. Use these two methods to work with refreshing:

KindeSdk.token_expired?(session[:kinde_auth])# => false
KindeSdk.refresh_token(session[:kinde_auth])# => {"access_token" => "qwe...", "refresh_token" => "fqw...", .....}

KindeSdk#refresh_token returns a new token hash, so it needs to be updated in your storage.

SDK API reference

Link to this section
PropertyTypeIs requiredDefaultDescription
hoststringYesEither your Kinde instance url or your custom domain. e.g
redirectUristringYesThe url that the user will be returned to after authentication
clientIdstringYesThe id of your application - get this from the Kinde admin area
clientSecretstringYesThe id secret of your application - get this from the Kinde admin area
logoutRedirectUristringYesWhere your user will be redirected upon logout
scopestringNoopenid profile email offlineThe scopes to be requested from Kinde
additionalParametersarrayNo[]Additional parameters that will be passed in the authorization request
additionalParameters - audiencestringNoThe audience claim for the JWT

KindeSDK methods

Link to this section
PropertyDescriptionArgumentsUsageSample output
loginConstructs redirect url and sends user to Kinde to sign inorg_code?: string$kinde->login();
registerConstructs redirect url and sends user to Kinde to sign uporg_code?: string$kinde->register();
logoutLogs the user out of Kinde$kinde->logout();
getTokenReturns the raw access token from URL after logged from Kinde$kinde->getToken();eyJhbGciOiJIUzI1...
createOrgConstructs redirect url and sends user to Kinde to sign up and create a new org for your businessorg_name?: string$kinde->createOrg(); or $kinde->createOrg(['org_name' => 'your organization name'});redirect
getClaimGets a claim from an access or id tokenclaim: string, tokenKey?: string$kinde->getClaim('given_name', 'id_token');David
getPermissionReturns the state of a given permissionkey: string$kinde->getPermission('read:todos');['orgCode' => 'org_1234', 'isGranted' => true]
getPermissionsReturns all permissions for the current user for the organization they are logged into$kinde->getPermissions();['orgCode' => 'org_1234', permissions => ['create:todos', 'update:todos', 'read:todos']]
getOrganizationGet details for the organization your user is logged into$kinde->getOrganization();['orgCode' => 'org_1234']
getUserDetailsReturns the profile for the current user$kinde->getUserDetails();['given_name' => 'Dave', 'id' => 'abcdef', 'family_name' => 'Smith', 'email' => '']
getUserOrganizationsGets an array of all organizations the user has access to

If you need help connecting to Kinde, please contact us at

Talk to us

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

Contact us