Set up Kinde Management API access
SDKs and APIs
Before you can get an access token and call the Kinde Management API, follow the steps to create and authorize a machine-to-machine (M2M) application, with scopes.
There are two main methods for getting an access token for the Kinde Management API.
For full details, see generate a test access token for the Kinde Management API.
To ask Kinde for an access token for calling the management API, perform a POST request to the https://<your_subdomain>.kinde.com/oauth2/token
endpoint, using the credentials of the M2M application you created in the prerequisite step.
The payload should look as follows:
curl --request POST \ --url 'https://<your_subdomain>.kinde.com/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data grant_type=client_credentials \ --data 'client_id=<your_m2m_client_id>' \ --data 'client_secret=<your_m2m_client_secret>' \ --data 'audience=https://<your_subdomain>.kinde.com/api'
var client = new RestClient("https://<your_subdomain>.kinde.com/oauth2/token");var request = new RestRequest(Method.POST);request.AddHeader("content-type", "application/x-www-form-urlencoded");request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi", ParameterType.RequestBody);IRestResponse response = client.Execute(request);
package main
import ( "fmt" "strings" "net/http" "io/ioutil")
func main() {
url := "https://<your_subdomain>.kinde.com/oauth2/token"
payload := strings.NewReader("grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}
HttpResponse<String> response = Unirest.post("https://<your_subdomain>.kinde.com/oauth2/token") .header("content-type", "application/x-www-form-urlencoded") .body("grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi") .asString();
async function getToken() { try { const response = await fetch(`https://<your_subdomain>.kinde.com/oauth2/token`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ audience: "https://<your_subdomain>.kinde.com/api", grant_type: "client_credentials", client_id: "<your_m2m_client_id>", client_secret: "<your_m2m_client_secret>" }) });
if (!response.ok) { throw new Error(`Response status: ${response.status}`); }
const json = await response.json(); console.log(json); } catch (error) { console.error(error.message); }}
getToken();
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };
NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"grant_type=client_credentials" dataUsingEncoding:NSUTF8StringEncoding]];[postData appendData:[@"&client_id=<your_m2m_client_id>" dataUsingEncoding:NSUTF8StringEncoding]];[postData appendData:[@"&client_secret=<your_m2m_client_secret>" dataUsingEncoding:NSUTF8StringEncoding]];[postData appendData:[@"&audience=https://<your_subdomain>.kinde.com/api" dataUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://<your_subdomain>.kinde.com/oauth2/token"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];[request setHTTPMethod:@"POST"];[request setAllHTTPHeaderFields:headers];[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sharedSession];NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { NSLog(@"%@", error); } else { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; NSLog(@"%@", httpResponse); } }];[dataTask resume];
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://<your_subdomain>.kinde.com/oauth2/token", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi", CURLOPT_HTTPHEADER => [ "content-type: application/x-www-form-urlencoded" ],]);
$response = curl_exec($curl);$err = curl_error($curl);
curl_close($curl);
if ($err) { echo "cURL Error #:" . $err;} else { echo $response;}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "https://<your_subdomain>.kinde.com/oauth2/token", payload, headers)
res = conn.getresponse()data = res.read()
print(data.decode("utf-8"))
require 'uri'require 'net/http'require 'openssl'
url = URI("https://<your_subdomain>.kinde.com/oauth2/token")
http = Net::HTTP.new(url.host, url.port)http.use_ssl = truehttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)request["content-type"] = 'application/x-www-form-urlencoded'request.body = "grant_type=client_credentials&client_id=<your_m2m_client_id>&client_secret=<your_m2m_client_secret>&audience=https%3A%2F%2F<your_subdomain>.kinde.com%2Fapi"
response = http.request(request)puts response.read_body
import Foundation
let headers = ["content-type": "application/x-www-form-urlencoded"]
let postData = NSMutableData(data: "grant_type=client_credentials".data(using: String.Encoding.utf8)!)postData.append("&client_id=<your_m2m_client_id>".data(using: String.Encoding.utf8)!)postData.append("&client_secret=<your_m2m_client_secret>".data(using: String.Encoding.utf8)!)postData.append("&audience=https://<your_subdomain>.kinde.com/api".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "https://<your_subdomain>.kinde.com/oauth2/token")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)request.httpMethod = "POST"request.allHTTPHeaderFields = headersrequest.httpBody = postData as Data
let session = URLSession.sharedlet dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) }})
dataTask.resume()
Make sure to replace <your_subdomain>
, <your_m2m_client_id>
and <your_m2m_client_secret>
with your own details.
The response will contain a signed JWT containing claims including the scopes the token is allowed to access and the expiry time. Here is an example token:
{ "aud": [ "https://example.kinde.com/api" ], "azp": "bd69bb9fe5db44a38b6b2dacd1f4b451", "exp": 1729812040, "gty": [ "client_credentials" ], "iat": 1729725640, "iss": "https://example.kinde.com", "jti": "6f091ebe-44ba-4afc-bd2f-05fcccafc89e", "scope": "read:users update:users"}
To use this token, include it in the Authorization header of your request. For example to get all users you would call:
curl --request GET \ --url 'https://<your_subdomain>.kinde.com/api/v1/users' \ --header 'authorization: Bearer <m2m_access_token>' \ --header 'content-type: application/json'
var client = new RestClient("https://<your_subdomain>.kinde.com/api/v1/users");var request = new RestRequest(Method.GET);request.AddHeader("content-type", "application/json");request.AddHeader("authorization", "Bearer <m2m_access_token>");IRestResponse response = client.Execute(request);
package main
import ( "fmt" "net/http" "io/ioutil")
func main() {
url := "https://<your_subdomain>.kinde.com/api/v1/users"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json") req.Header.Add("authorization", "Bearer <m2m_access_token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res) fmt.Println(string(body))
}
HttpResponse<String> response = Unirest.get("https://<your_subdomain>.kinde.com/api/v1/users") .header("content-type", "application/json") .header("authorization", "Bearer <m2m_access_token>") .asString();
async function getUsers() { try { const response = await fetch(`https://<your_subdomain>.kinde.com/api/v1/users`, { method: "GET", headers: { "content-type": "application/json", authorization: "Bearer <m2m_access_token>" } });
if (!response.ok) { throw new Error(`Response status: ${response.status}`); }
const json = await response.json(); console.log(json); } catch (error) { console.error(error.message); }}
getUsers();
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"content-type": @"application/json", @"authorization": @"Bearer <m2m_access_token>" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://<your_subdomain>.kinde.com/api/v1/users"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];[request setHTTPMethod:@"GET"];[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { NSLog(@"%@", error); } else { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; NSLog(@"%@", httpResponse); } }];[dataTask resume];
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://<your_subdomain>.kinde.com/api/v1/users", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => [ "authorization: Bearer <m2m_access_token>", "content-type: application/json" ],]);
$response = curl_exec($curl);$err = curl_error($curl);
curl_close($curl);
if ($err) { echo "cURL Error #:" . $err;} else { echo $response;}
import http.client
conn = http.client.HTTPSConnection("")
headers = { 'content-type': "application/json", 'authorization': "Bearer <m2m_access_token>" }
conn.request("GET", "https://<your_subdomain>.kinde.com/api/v1/users", headers=headers)
res = conn.getresponse()data = res.read()
print(data.decode("utf-8"))
require 'uri'require 'net/http'require 'openssl'
url = URI("https://<your_subdomain>.kinde.com/api/v1/users")
http = Net::HTTP.new(url.host, url.port)http.use_ssl = truehttp.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)request["content-type"] = 'application/json'request["authorization"] = 'Bearer <m2m_access_token>'
response = http.request(request)puts response.read_body
import Foundation
let headers = [ "content-type": "application/json", "authorization": "Bearer <m2m_access_token>"]
let request = NSMutableURLRequest(url: NSURL(string: "https://<your_subdomain>.kinde.com/api/v1/users")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)request.httpMethod = "GET"request.allHTTPHeaderFields = headers
let session = URLSession.sharedlet dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) }})
dataTask.resume()
Make sure to replace <your_subdomain>
with your Kinde subdomain and <m2m_access_token>
with the token received in the previous step.
As an alternative to making HTTP calls, you can also use the Kinde Management API JS SDK.
You can use it to automatically obtain tokens for, and interact with the Kinde management API.
We recommend you do this in a non-production environment first.
If you decide to use Postman, we recommend that you set up a Postman environment. Here’s some troubleshooting solutions in case you need them.
Save
or the variables will not persist.{{business_domain}}/oauth2/token
. Note that even if you use a custom domain, the access token URL should still use your https://<your_subdomain>.kinde.com
domain.{{business_domain}}/api
. To do this:
audience
key and enter the above URL in the Value field. Ensure it is being sent in the body
of the requestapplication/json
.You can test your API access in Postman by sending a GET
request to any Kinde API endpoint. See the Kinde Management API library for options.
Here’s an example using the Get users
endpoint.
GET
request./users
endpoint, e.g. https://<your_subdomain>.kinde.com/api/v1/users
.