Skip to main content

Authentication

Qaynaq supports authentication to protect the web UI and REST API. By default, authentication is disabled. You can enable Basic Auth for simple setups or OAuth2/OIDC for integration with identity providers like Keycloak, Okta, Auth0, or any OAuth2-compliant provider.

Authentication Modes

Set the AUTH_TYPE environment variable to choose a mode:

ValueDescription
noneNo authentication (default). All endpoints are open.
basicUsername and password authentication.
oauth2OAuth2/OIDC with an external identity provider.

What Gets Protected

When authentication is enabled:

  • Protected: All /api/* endpoints (flows, workers, secrets, caches, rate limits, settings) and the web UI dashboard.
  • Not protected: Flow ingestion endpoints (/ingest/*) remain open to allow webhook and data ingestion from external systems. Auth info and login endpoints are also always accessible.
  • Separately protected: The MCP endpoint (/mcp) has its own token-based authentication that can be enabled independently. See MCP Authentication below.

Basic Authentication

Basic auth provides simple username/password protection. Set these environment variables:

VariableRequiredDescription
AUTH_TYPEYesSet to basic
AUTH_BASIC_USERNAMEYesLogin username
AUTH_BASIC_PASSWORDYesLogin password
SECRET_KEYYes32-byte key used for signing JWT tokens
export AUTH_TYPE=basic
export AUTH_BASIC_USERNAME=admin
export AUTH_BASIC_PASSWORD=your-secure-password
export SECRET_KEY=this_is_a_32_byte_key_for_AES!!!

When basic auth is enabled, the login page shows a username/password form. After successful login, a JWT token is issued and used for subsequent API requests.

API Usage

To authenticate API requests, first obtain a token:

curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-secure-password"}'

Response:

{"token":"eyJhbG...","token_type":"Bearer"}

Then include the token in subsequent requests:

curl http://localhost:8080/api/v1/flows \
-H "Authorization: Bearer eyJhbG..."

OAuth2 / OIDC Authentication

OAuth2 mode lets you delegate authentication to an external identity provider. Qaynaq implements the standard Authorization Code flow and works with any OAuth2-compliant provider, including:

  • Keycloak
  • Okta
  • Auth0
  • Google Workspace
  • Azure AD / Entra ID
  • Any OIDC-compliant provider

Configuration

VariableRequiredDescription
AUTH_TYPEYesSet to oauth2
AUTH_OAUTH2_CLIENT_IDYesOAuth2 client ID
AUTH_OAUTH2_CLIENT_SECRETYesOAuth2 client secret
AUTH_OAUTH2_ISSUER_URLYesOIDC issuer URL (e.g. https://accounts.google.com, http://localhost:8090/realms/qaynaq). Qaynaq fetches <issuer>/.well-known/openid-configuration at startup and discovers the authorization, token, and userinfo endpoints.
AUTH_OAUTH2_SCOPESNoComma-separated scopes (default: openid,email,profile)
AUTH_OAUTH2_ALLOWED_USERSNoComma-separated list of allowed email addresses
AUTH_OAUTH2_ALLOWED_DOMAINSNoComma-separated list of allowed email domains
AUTH_OAUTH2_SESSION_COOKIE_NAMENoSession cookie name (default: qaynaq_session)
SECRET_KEYYes32-byte key used for signing JWT tokens

Provider Requirements

Qaynaq only supports OIDC-compliant providers. You need:

  1. Issuer URL -- the base URL of your provider's OIDC realm. The provider must serve a valid <issuer>/.well-known/openid-configuration document containing authorization_endpoint, token_endpoint, and userinfo_endpoint.
  2. Client ID and Secret -- created when you register Qaynaq as a client in your provider.
  3. Redirect URI -- register http(s)://<your-qaynaq-host>/auth/callback as an allowed redirect URI in your provider's client configuration. Qaynaq derives this from the incoming request host at runtime.

The provider's userinfo endpoint must return a JSON response that includes an email field.

Access Restrictions

You can restrict which users can log in using email-based filtering:

  • AUTH_OAUTH2_ALLOWED_USERS -- Only the listed email addresses can access Qaynaq. Example: alice@company.com,bob@company.com
  • AUTH_OAUTH2_ALLOWED_DOMAINS -- Only users with email addresses from the listed domains can access. Example: company.com,partner.org

If neither is set, all authenticated users from the identity provider are allowed.

For a step-by-step setup with Keycloak, see the Keycloak Authentication guide.

Authentication Flow

When authentication is enabled, the login page adapts automatically:

  • Basic auth: Shows a username and password form.
  • OAuth2: Shows a "Sign In" button that redirects to the identity provider.
  • None: Shows a "Continue to Dashboard" button.

After successful authentication, a JWT token (valid for 24 hours) is issued. The web UI stores this token and includes it in all API requests. When the token expires, the user is redirected back to the login page.

MCP Authentication

The MCP endpoint (/mcp) can be protected with API tokens, separate from the main application authentication. This allows you to control which MCP clients (Claude Desktop, Cursor, etc.) can access your tools.

How It Works

  1. Enable app authentication first - MCP token management requires basic or OAuth2 authentication to be enabled on the application. Without app auth, the settings page is accessible to everyone.
  2. Enable MCP protection - Open Settings > Authentication and toggle "Require authentication".
  3. Create API tokens - Switch to the API Tokens tab and create one named token per MCP client. The token value is shown only once - copy and store it securely.
  4. Configure your MCP client - Pass the token to your MCP client using one of the methods below.

For interactive clients that can complete an OAuth flow (Claude Desktop, Cursor), prefer MCP OAuth over static tokens.

Passing the Token

MCP clients can authenticate using either method:

Query parameter (recommended for mcp-remote / npx setups):

{
"mcpServers": {
"qaynaq": {
"command": "npx",
"args": [
"mcp-remote",
"http://your-host:8080/mcp?token=at_your_token_here"
]
}
}
}

Authorization header (for clients that support custom headers):

{
"mcpServers": {
"qaynaq": {
"url": "http://your-host:8080/mcp",
"headers": {
"Authorization": "Bearer at_your_token_here"
}
}
}
}

Token Management

Tokens are managed through Settings > API Tokens in the web UI or via the API:

EndpointMethodDescription
/api/v0/settings/mcpGETGet MCP protection status and token list
/api/v0/settings/mcpPUTEnable or disable MCP protection
/api/v0/settings/mcp/tokensGETList all API tokens
/api/v0/settings/mcp/tokensPOSTCreate a new API token
/api/v0/settings/mcp/tokens/{id}DELETEDelete a token
/api/v0/settings/mcp/oauth-sessionsGETList active OAuth sessions (when MCP OAuth is enabled)
/api/v0/settings/mcp/oauth-sessions/{id}DELETERevoke an OAuth session
/api/v0/settings/mcp/oauth-clientsGETList registered OAuth clients
/api/v0/settings/mcp/oauth-clients/{id}DELETEDelete an OAuth client registration
/api/v0/settings/mcp/oauth-clients/{id}/consentDELETERevoke a client's consent and refresh tokens
/api/v0/mcp/oauth/consent-requestGET, POSTBacking endpoints for the SPA consent page

Each token has a name, scopes, creation date, and last-used timestamp. The last-used time is tracked in memory and flushed to the database periodically, so there is no performance overhead on every MCP request.

tip

Create separate tokens for each MCP client (e.g., "Claude Desktop", "Cursor", "CI Pipeline"). This way you can revoke access for a specific client without affecting others.

warning

When MCP protection is enabled, all existing MCP client connections without a valid token will stop working. Make sure to update your client configurations before enabling protection.

Security Notes

  • JWT tokens are signed with the SECRET_KEY using HMAC-SHA256. Use a strong, unique 32-byte key in production.
  • Basic auth credentials are compared using constant-time comparison to prevent timing attacks.
  • OAuth2 state parameters are validated to prevent CSRF attacks and expire after 10 minutes.
  • Tokens expire after 24 hours. Users must re-authenticate after expiration.