Skip to content

Authentication

Authenticate users with the Koldan platform via username/password credentials, OAuth 2.0 authorization codes (with optional PKCE), token refresh, and logout. All endpoints delegate to the configured OIDC identity provider and return standard OAuth 2.0 token responses.

Public - No authentication required

Base path: /api/v1/auth

Integrating without user interaction?

If you are building a service-to-service integration, a background worker, or any automation that runs without a user present, skip the authentication flows below and use an API Key instead. API Keys are long-lived, do not require token refresh, and can be scoped to specific permissions - making them the recommended approach for non-interactive access to the Koldan API.

Method Endpoint Description
POST /api/v1/auth/exchange-auth-code Exchange Authorization Code
POST /api/v1/auth/refresh-token Refresh Token
POST /api/v1/auth/logout Logout
POST /api/v1/auth/login Login

Login

POST /api/v1/auth/login

Deprecated

The direct login endpoint is deprecated and will be removed in a future release.

Use instead:

  • Authorization Code flow with PKCE - for browser-based and mobile applications where a user is present.
  • API Keys - for service-to-service integrations, background workers, and automations that run without user interaction.

Authenticate a user with username and password credentials. On success, the OIDC provider issues an OAuth 2.0 token set (access token, refresh token, and optional ID token). The access token should be used as a Bearer token in subsequent API requests.

LoginRequest
Field Type Required Description
username string Yes The user's username.
password string Yes The user's password.
LoginRequest
{
  "username": "john.doe",
  "password": "s3cur3P@ssw0rd"
}
curl -X POST https://koldan.dixilang.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "john.doe",
    "password": "s3cur3P@ssw0rd"
  }'
import requests

resp = requests.post(
    "https://koldan.dixilang.com/api/v1/auth/login",
    json={
        "username": "john.doe",
        "password": "s3cur3P@ssw0rd"
    }
)
print(resp.json())
OAuthTokenResponse
Field Type Nullable Description
access_token string No The JWT access token used for authenticating API requests.
refresh_token string No The refresh token used to obtain a new access token when the current one expires.
token_type string No The token type. Always "Bearer".
expires_in integer No Number of seconds until the access token expires.
id_token string Yes The OIDC ID token containing user identity claims. May be null depending on the provider configuration.
scope string Yes Space-separated list of scopes granted to the token.
OAuthTokenResponse
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 300,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "scope": "openid profile email"
}
Status Description
200 OK Authentication successful. The response body contains the OAuth 2.0 token set.
401 Unauthorized Invalid credentials. Check username and password.
409 Conflict User data conflict (e.g., duplicate username detected during post-login synchronization).
503 Service Unavailable The identity provider is unreachable. Retry later.

Logout

POST /api/v1/auth/logout

Log out a user by invalidating their refresh token with the OIDC provider. After logout, the refresh token can no longer be used to obtain new access tokens.

LogoutRequest
Field Type Required Description
refreshToken string Yes The refresh token to invalidate.
LogoutRequest
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
curl -X POST https://koldan.dixilang.com/api/v1/auth/logout \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'
import requests

resp = requests.post(
    "https://koldan.dixilang.com/api/v1/auth/logout",
    json={
        "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
)
print(resp.text)
Response
Status Description
200 OK User successfully logged out. The refresh token has been invalidated.
400 Bad Request Logout failed. The refresh token may be invalid, already expired, or the identity provider rejected the request.

Exchange Authorization Code

POST /api/v1/auth/exchange-auth-code

Exchange an OAuth 2.0 authorization code for an access token using the Authorization Code with PKCE flow. The codeVerifier is required to complete the token exchange securely.

When to use this endpoint

Use this endpoint after completing an OAuth 2.0 / OIDC authorization flow in a browser or mobile application. The authorization server redirects the user back to your application with a code parameter - send that code here to obtain tokens.

UnifiedLoginRequest
Field Type Required Description
code string Yes The authorization code received from the OIDC provider's authorization endpoint.
redirectUri string Yes The redirect URI that was used in the original authorization request. Must match exactly.
codeVerifier string Yes The PKCE code verifier. Must match the code_challenge sent in the original authorization request.
UnifiedLoginRequest
{
  "code": "abc123-authorization-code",
  "redirectUri": "https://app.example.com/callback",
  "codeVerifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}
curl -X POST https://koldan.dixilang.com/api/v1/auth/exchange-auth-code \
  -H "Content-Type: application/json" \
  -d '{
    "code": "abc123-authorization-code",
    "redirectUri": "https://app.example.com/callback",
    "codeVerifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  }'
import requests

resp = requests.post(
    "https://koldan.dixilang.com/api/v1/auth/exchange-auth-code",
    json={
        "code": "abc123-authorization-code",
        "redirectUri": "https://app.example.com/callback",
        "codeVerifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
    }
)
print(resp.json())
OAuthTokenResponse

Returns an OAuthTokenResponse object (see field table in Login).

OAuthTokenResponse
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 300,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "scope": "openid profile email"
}
Status Description
200 OK Token exchange successful. The response body contains the OAuth 2.0 token set.
401 Unauthorized Token exchange failed. The authorization code may be invalid, expired, or the redirect URI does not match.
409 Conflict User data conflict during post-login synchronization.
503 Service Unavailable The identity provider is unreachable. Retry later.

Refresh Token

POST /api/v1/auth/refresh-token

Refresh an expired access token using a valid refresh token. Returns a new OAuth 2.0 token set with a fresh access token.

Token Lifecycle

Access tokens are short-lived (typically 5 minutes). Use this endpoint to seamlessly obtain a new access token without requiring the user to re-authenticate. The refresh token itself may also be rotated - always store the latest refresh_token from the response.

RefreshTokenRequest
Field Type Required Description
refreshToken string Yes The refresh token obtained from a previous login or token refresh response.
RefreshTokenRequest
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
curl -X POST https://koldan.dixilang.com/api/v1/auth/refresh-token \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'
import requests

resp = requests.post(
    "https://koldan.dixilang.com/api/v1/auth/refresh-token",
    json={
        "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
)
print(resp.json())
OAuthTokenResponse

Returns an OAuthTokenResponse object (see field table in Login).

OAuthTokenResponse
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 300,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "scope": "openid profile email"
}
Status Description
200 OK Access token successfully refreshed. The response body contains the new OAuth 2.0 token set.
400 Bad Request Failed to refresh access token. The refresh token may be invalid, expired, or already revoked.

Authentication Flows

Koldan supports multiple authentication flows depending on your application type:

Direct Login (Resource Owner Password)

The simplest flow for server-side applications and scripts. Send the user's credentials directly to the Login endpoint.

sequenceDiagram
    participant C as Client
    participant K as Koldan API
    participant O as OIDC Provider

    C->>K: POST /api/v1/auth/login<br>{ username, password }
    K->>O: Token Request
    O-->>K: OAuthTokenResponse
    K-->>C: 200 OK { access_token, … }

Authorization Code Flow with PKCE

Recommended for browser-based and mobile applications. The user authenticates directly with the OIDC provider and your application exchanges the resulting authorization code for tokens using PKCE.

sequenceDiagram
    participant U as User
    participant A as Client App
    participant O as OIDC Provider
    participant K as Koldan API

    U->>A: Login
    A->>A: Generate code_verifier & code_challenge
    A->>O: Redirect to /authorize<br>with code_challenge
    U->>O: Authenticate with provider
    O-->>U: Authenticated
    O-->>A: Redirect with ?code=abc123
    A->>K: POST /api/v1/auth/exchange-auth-code<br>{ code, redirectUri, codeVerifier }
    K-->>A: 200 OK { access_token, … }

PKCE is Required

All clients must use PKCE when using the Authorization Code flow. Generate a code_verifier and code_challenge before the authorization request, then include the codeVerifier when calling the Exchange Authorization Code endpoint.

Using Tokens

Once authenticated, include the access token in the Authorization header of all API requests:

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
curl -X GET https://koldan.dixilang.com/api/v1/some-resource \
  -H "Authorization: Bearer $JWT"
import requests

resp = requests.get(
    "https://koldan.dixilang.com/api/v1/some-resource",
    headers={"Authorization": f"Bearer {JWT}"}
)
print(resp.json())

For API key authentication as an alternative to Bearer tokens, see API Keys.


Best Practices

Authentication Recommendations

  • Never store tokens in local storage. Use secure, HTTP-only cookies or in-memory storage to protect tokens from XSS attacks.
  • Refresh proactively. Refresh the access token before it expires to avoid request failures. Use the expires_in field to schedule refreshes.
  • Handle token rotation. Always store the latest refresh_token from each response - the OIDC provider may rotate refresh tokens.
  • Always use PKCE. The Authorization Code flow requires PKCE - generate a code_verifier and code_challenge for every authorization request.
  • Invalidate tokens on logout. Always call the Logout endpoint to revoke refresh tokens when a user signs out.
  • Protect credentials in transit. All authentication requests must be made over HTTPS.
  • Prefer authorization code flow. When possible, use the Exchange Authorization Code flow instead of direct login to avoid handling user passwords.