Skip to content

Authentication

Kiket supports multiple authentication flows tailored to users, service accounts, extensions, and tooling such as the CLI or MCP server.

Workspace API Tokens (CLI & MCP)

Workspace API tokens are organization-scoped bearer tokens used by the CLI, MCP server, and other first-party tools. Only organization admins can issue them.

Create a token from the UI

  1. Navigate to Settings → API Tokens.
  2. Provide a descriptive name (e.g., “CLI – laptop”).
  3. Select scopes (issues, projects, workflows, analytics, admin) or leave blank for full workspace access.
  4. Optionally set an expiration. Tokens are shown exactly once—copy them into your secret manager immediately.

Manage tokens via API

GET    /api/v1/workspace_api_tokens        # list tokens you can manage
POST   /api/v1/workspace_api_tokens        # create a token (returns `token` once)
DELETE /api/v1/workspace_api_tokens/:id    # revoke a token

Example request:

curl -X POST https://kiket.dev/api/v1/workspace_api_tokens \
  -H "Authorization: Bearer <session_or_token>" \
  -H "Content-Type: application/json" \
  -d '{
        "workspace_api_token": {
          "name": "CLI – laptop",
          "scopes": ["issues:read", "projects"],
          "expires_at": "2025-01-31T23:59:00Z"
        }
      }'

Successful response:

{
  "id": 42,
  "name": "CLI – laptop",
  "scopes": ["issues:read", "projects"],
  "token": "wksp_7d5c9c1a0e8c4f58...", // shown once
  "token_prefix": "wksp_7d5c9c1a",
  "last_used_at": null,
  "owner": { "id": 7, "name": "Avery" }
}

Use the returned token in every API call:

Authorization: Bearer wksp_7d5c9c1a0e8c4f58...

Token scopes

Common scopes mirror CLI/MCP capabilities:

  • issues:read, issues:write
  • projects (includes read/write)
  • comments
  • workflows
  • analytics
  • admin

Scopes follow least privilege—only grant what automation requires.

OAuth 2.0 Client Credentials

  • Use for server-to-server integrations that you host.
  • Register an OAuth application under Organization → Integrations.
  • Token endpoint: https://kiket.dev/oauth/token.
  • Provide client_id, client_secret, and grant_type=client_credentials. Returned tokens carry the scopes you requested.

Extension API Keys

  • Issued automatically during extension installation.
  • Keys are project-scoped and inherit permissions declared in the manifest.
  • Rotate keys from Settings → Extensions or via the /api/v1/extensions/:id/secrets endpoints.

Revocation & Audit

  • Revoke workspace API tokens or OAuth credentials at any time. Revoked tokens stop working immediately.
  • The Settings → API Tokens table shows last used timestamps so you can prune unused credentials.
  • Suspicious usage generates security alerts via email/Slack if configured.

Always keep tokens secret and rotate them regularly to maintain security hygiene.

Headless Auth API

For standalone products built on Kiket's API. Users authenticate via JSON endpoints — no Kiket UI involved. Product JWT tokens work on all authenticated API endpoints (issues, projects, comments, users, etc.) — not just the auth and billing endpoints.

Headers

All headless auth requests should include:

  • X-Product-Slug — your product identifier (e.g., spravce-gdpr)
  • Accept-Language — optional, sets response locale (cs, de, en)

Register

curl -X POST https://kiket.dev/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -H "X-Product-Slug: spravce-gdpr" \
  -d '{
    "email": "jan@acme.cz",
    "password": "SecurePass123!",
    "password_confirmation": "SecurePass123!",
    "name": "Jan Novak",
    "organization_name": "Acme s.r.o."
  }'

Returns access_token, refresh_token, and user/organization/subscription details.

If the email already exists, the password is verified and the user is added to a new organization for your product (same user identity, separate data).

Login

curl -X POST https://kiket.dev/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -H "X-Product-Slug: spravce-gdpr" \
  -d '{ "email": "jan@acme.cz", "password": "SecurePass123!" }'

If the user manages multiple organizations on the same product, the response includes select_organization: true with an organizations array. Call /api/v1/auth/login/select_org with the chosen organization_id.

Refresh

curl -X POST https://kiket.dev/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{ "refresh_token": "eyJ..." }'

Access tokens expire in 1 hour. Refresh tokens expire in 30 days. Refresh validates that the product subscription is still active.

Password Reset

# Request reset email (white-labeled with your product branding)
curl -X POST https://kiket.dev/api/v1/auth/forgot_password \
  -H "Content-Type: application/json" \
  -d '{ "email": "jan@acme.cz" }'

# Set new password
curl -X PUT https://kiket.dev/api/v1/auth/reset_password \
  -H "Content-Type: application/json" \
  -d '{ "token": "...", "password": "NewPass456!", "password_confirmation": "NewPass456!" }'

Profile

# Get current user
curl https://kiket.dev/api/v1/auth/me \
  -H "Authorization: Bearer eyJ..."

# Update profile
curl -X PUT https://kiket.dev/api/v1/auth/me \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Jan Novak Jr." }'

JWT Token Format

Tokens use ES256 (ECDSA P-256) signing. Claims:

Claim Description
sub User ID
org Organization ID
product Product slug (e.g., spravce-gdpr)
scopes API scopes from product feature flags
type access or refresh
iss kiket.dev
exp Expiration timestamp
jti Unique token ID

Real-Time Notifications (WebSocket)

Product frontends can connect to Kiket's ActionCable WebSocket to receive real-time notifications (SLA warnings, workflow transitions, new comments, assignments).

Connect with the JWT access token as a query parameter:

const ws = new WebSocket(
  `wss://kiket.dev/cable?token=${accessToken}`
);

// Subscribe to notifications channel
ws.send(JSON.stringify({
  command: "subscribe",
  identifier: JSON.stringify({ channel: "NotificationsChannel" })
}));

// Receive notifications
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === "ping") return;

  const msg = JSON.parse(data.message || "{}");
  if (msg.action === "new_notification") {
    // msg.notification.title, msg.notification.message, msg.notification.url
    // msg.unread_count
  }
};

The notification payload includes:

{
  "action": "new_notification",
  "unread_count": 3,
  "notification": {
    "id": 42,
    "title": "SLA Warning",
    "message": "DSAR for Jan Novak approaching 30-day deadline",
    "url": "/issues/456",
    "type": "sla_warning",
    "created_at": "2 minutes ago"
  }
}

Localization

Pass ?locale=cs or set Accept-Language: cs to receive error messages in Czech or German. The product's default_locale is used as fallback.