Kendr.org

Pick the auth flow that matches your client.

Kendr supports several auth modes because the clients are different: browser pages, installed apps, server-side integrations, Kendr Desktop, and the CLI do not all authenticate the same way. This page covers the exact routes, request bodies, and token shapes accepted by https://kendr.org.

Cookies X-Kendr-Session API keys OAuth PKCE and device code

Auth matrix

Mode Header or state Best for
Browser session kendr_session cookie Portal and browser-driven flows after /api/auth/login or /api/auth/register.
App session X-Kendr-Session Installed apps that authenticate directly with Kendr and immediately call customer endpoints.
API key Authorization: Bearer kndr_live_... or X-API-Key Server-to-server usage, background jobs, and long-lived backend integrations.
OAuth bearer Authorization: Bearer kndr_oat_... Kendr Desktop, CLI, or other native clients using PKCE or device code with the app scope.

Browser session auth

The browser endpoints create and refresh the kendr_session cookie. They are useful for portals, browser automation, and any flow that wants cookie-backed auth rather than manually managing X-Kendr-Session.

Register and store the cookie

curl https://kendr.org/api/auth/register \
  -X POST \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "user@example.com",
    "password": "supersecret123",
    "full_name": "Example User"
  }'

Log in and refresh the cookie

curl https://kendr.org/api/auth/login \
  -X POST \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "user@example.com",
    "password": "supersecret123"
  }'

Inspect browser session state

curl https://kendr.org/api/auth/session \
  -b cookies.txt

Log out

curl https://kendr.org/api/auth/logout \
  -X POST \
  -b cookies.txt \
  -c cookies.txt
Payload rules

email must be a valid address and password must be at least 8 characters on registration.

App session auth

The app auth routes return a session token directly in the JSON response. That token is sent on later calls as X-Kendr-Session.

Switch languages

Use the tabs to view the same login flow in Curl, JavaScript, Python, .NET, Java, or Go. The response shape stays the same across every client.

Authenticate and receive the session token

Post credentials and read session.token from the JSON response

curl https://kendr.org/api/app/auth/login \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "supersecret123"
  }'

Successful response

{
  "ok": true,
  "authenticated": true,
  "user": {
    "id": 12,
    "email": "user@example.com",
    "full_name": "Example User",
    "credit_balance": 250
  },
  "session": {
    "token": "SESSION_TOKEN",
    "header_name": "X-Kendr-Session",
    "expires_at": "2026-04-24T12:00:00Z"
  }
}

Inspect the app session

curl https://kendr.org/api/app/auth/session \
  -H "X-Kendr-Session: $KENDR_SESSION"

Log out the app session

curl https://kendr.org/api/app/auth/logout \
  -X POST \
  -H "X-Kendr-Session: $KENDR_SESSION"

OAuth PKCE for desktop apps

Kendr’s first-party OAuth clients are seeded as kendr-desktop and kendr-cli. Native clients can use PKCE with GET /oauth/authorize and POST /oauth/token.

Parameter Needed for
response_type=code Required on /oauth/authorize.
client_id Use kendr-desktop or another allowed client.
redirect_uri Must match an allowed client redirect URI, including Kendr loopback or custom URI handlers.
code_challenge and code_challenge_method=S256 Required for PKCE.
scope Optional. Defaults to the client’s default scopes. Include offline_access when you need a refresh token.
https://kendr.org/oauth/authorize?response_type=code&client_id=kendr-desktop&redirect_uri=kendr%3A%2F%2Foauth%2Fcallback&scope=profile%20email%20app%20offline_access&code_challenge=YOUR_S256_CHALLENGE&code_challenge_method=S256&state=opaque-state
curl https://kendr.org/oauth/token \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-desktop" \
  -d "grant_type=authorization_code" \
  -d "code=$OAUTH_CODE" \
  -d "redirect_uri=kendr://oauth/callback" \
  -d "code_verifier=$CODE_VERIFIER"

OAuth device code for the CLI

Device code is the cleanest CLI flow because the terminal never asks the user for their password. The CLI starts the flow, the user approves it in the browser, and the client then exchanges the device code for an access token.

Start the flow

curl https://kendr.org/oauth/device/code \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-cli" \
  -d "scope=profile email app offline_access"

Response fields

{
  "device_code": "kndr_odc_...",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://kendr.org/oauth/device",
  "verification_uri_complete": "https://kendr.org/oauth/device?user_code=ABCD-EFGH",
  "expires_in": 900,
  "interval": 5,
  "scope": "profile email app offline_access"
}
curl https://kendr.org/oauth/token \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=kendr-cli" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "device_code=$DEVICE_CODE"
Polling behavior

Poll no faster than the returned interval. Kendr returns OAuth protocol errors such as authorization_pending, slow_down, or access_denied as appropriate.

OAuth metadata and user info

Discovery metadata

curl https://kendr.org/.well-known/oauth-authorization-server

User info

curl https://kendr.org/oauth/userinfo \
  -H "Authorization: Bearer $KENDR_OAUTH_ACCESS_TOKEN"
Scope behavior

profile exposes name and preferred username, email exposes the email address, and app allows customer endpoints such as dashboard, API keys, purchases, and query execution.

App telemetry endpoints

Kendr also exposes app-side endpoints for installations, activity, error reports, feedback, and active notifications. These endpoints accept JSON and can carry extra metadata beyond their primary fields.

Path Key fields Response
POST /api/app/installations installation_id, platform, app_version, channel, source status, install_id, total_installs, recorded_at
POST /api/app/activity installation_id, platform, app_version, source status, activity_date, identity_type, total_active, recorded_at
POST /api/app/errors Required message; optional install, version, platform, error name, error code, details, stack trace, severity, email status, error_id, created_at
POST /api/app/feedback Required message; optional install, version, platform, category, rating, email status, feedback_id, created_at
GET /api/app/notifications No body count and notifications
curl https://kendr.org/api/app/feedback \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "installation_id": "desktop-prod-001",
    "platform": "windows",
    "app_version": "0.4.0",
    "category": "feature_request",
    "rating": 5,
    "message": "Please add saved query presets."
  }'

SDK helpers

JavaScript helpers

import {
  KendrClient,
  loginWithPassword,
  registerWithPassword
} from './sdk/javascript/index.js';

const auth = await loginWithPassword({
  email: 'user@example.com',
  password: 'supersecret123',
  baseUrl: 'https://kendr.org'
});

const client = new KendrClient({
  sessionToken: auth.session.token,
  baseUrl: 'https://kendr.org'
});

const dashboard = await client.getDashboard();

Python helpers

from kendr import KendrClient, login_with_password

auth = login_with_password(
    email='user@example.com',
    password='supersecret123',
    base_url='https://kendr.org',
)

client = KendrClient(
    session_token=auth['session']['token'],
    base_url='https://kendr.org',
)

dashboard = client.get_dashboard()