Skip to Content
AuthenticationToken Auth

Token Auth

Use token auth when your app should send Authorization: Bearer <token> on every request instead of raw user/password credentials.

KalamDB supports two token sources:

  • KalamDB-issued access and refresh tokens returned by local login or OIDC exchange endpoints
  • direct external OIDC ID tokens from the configured trusted issuer

Internal Token Flow

The built-in login flow is:

  1. Send user and password to POST /v1/api/auth/login.
  2. Receive access_token and refresh_token.
  3. Send the access token on API and WebSocket requests.
  4. Refresh it through POST /v1/api/auth/refresh when needed.

Login

BASH
curl -X POST http://127.0.0.1:2900/v1/api/auth/login \  -H 'Content-Type: application/json' \  -d '{"user":"admin","password":"AdminPass123!"}'

Typical response fields:

  • access_token
  • refresh_token
  • expires_at or token-expiry metadata
  • authenticated user profile fields

Use the access token

BASH
TOKEN="<access_token>" curl -X POST http://127.0.0.1:2900/v1/api/sql \  -H "Authorization: Bearer $TOKEN" \  -H 'Content-Type: application/json' \  -d '{"sql":"SELECT CURRENT_USER();"}'

Refresh Tokens

BASH
REFRESH="<refresh_token>" curl -X POST http://127.0.0.1:2900/v1/api/auth/refresh \  -H "Authorization: Bearer $REFRESH"

Use the returned access token for subsequent requests.

Checking Auth State

There are two practical checks:

Check the current authenticated user

BASH
curl http://127.0.0.1:2900/v1/api/auth/me \  -H "Authorization: Bearer $TOKEN"

This confirms whether the token is accepted and shows the current user record.

Check from SQL

BASH
curl -X POST http://127.0.0.1:2900/v1/api/sql \  -H "Authorization: Bearer $TOKEN" \  -H 'Content-Type: application/json' \  -d '{"sql":"SELECT CURRENT_USER();"}'

This is the fastest way to confirm the runtime identity that SQL sees.

OIDC Browser And Device Exchange Flows

The Admin UI and CLI normally exchange provider login results for KalamDB-issued tokens.

Endpoints:

  • POST /v1/api/auth/oidc/exchange-code for browser Authorization Code + PKCE
  • POST /v1/api/auth/oidc/exchange-token for direct device login when the CLI obtains a provider ID token
  • POST /v1/api/auth/oidc/device/start and POST /v1/api/auth/oidc/device/poll for brokered device flow

CLI entry points:

BASH
# Browser PKCE loginkalam login --instance local --url http://127.0.0.1:2900 --oidc # Direct device loginkalam login --instance local --url http://127.0.0.1:2900 --oidc --no-browser # Brokered device loginkalam login --instance local --url http://127.0.0.1:2900 --oidc --no-browser --brokered

All three flows return or save KalamDB access and refresh tokens. They do not persist provider credentials.

Direct External Bearer Tokens

If you already have a valid token from the configured trusted OIDC issuer, you can also skip the exchange endpoints and send that provider token directly as a bearer token.

KalamDB will:

  1. read alg and iss
  2. reject untrusted issuers
  3. perform OIDC discovery for the issuer
  4. fetch and cache the issuer JWKS
  5. validate the token signature and claims
  6. resolve or create the matching local user

OIDC setup details live in:

SDK Pattern

For long-lived apps, return a fresh token from the SDK auth provider callback instead of hard-coding a token once.

TypeScript

TS
import { Auth, createClient, type AuthProvider } from '@kalamdb/client'; const authProvider: AuthProvider = async () => {  const token = await myApp.getOrRefreshJwt();  return Auth.jwt(token);}; const client = createClient({  url: 'https://db.example.com',  authProvider,});

Dart

DART
final client = await KalamClient.connect(  url: 'https://db.example.com',  authProvider: () async {    final token = await myApp.getOrRefreshJwt();    return Auth.jwt(token);  },);

Configuration Notes

Internal token auth still depends on a strong shared secret:

TOML
[auth]jwt_secret = "replace-with-strong-random-secret-32-plus-chars"cookie_secure = true

OIDC also depends on the configured single provider block:

TOML
[auth.oidc]enabled = trueissuer = "https://idp.example.com/realms/kalamdb"client_id = "kalamdb"scopes = ["openid", "email", "profile"]

Use KALAMDB_JWT_SECRET and the KALAMDB_AUTH_OIDC_* env vars in production instead of committing secrets to server.toml.

Last updated on