Skip to content

Integrating Quine Enterprise with Your Identity Provider

Quine Enterprise supports OpenID Connect (OIDC) for authentication and role-based access control (RBAC). This guide explains how to set up OIDC with any identity provider that implements the OIDC standard.

How OIDC Authentication Works

OIDC is a standard protocol that lets you use your existing identity provider (like Okta, Azure AD, Auth0, or self-hosted solutions) to manage user access to Quine Enterprise.

When you enable OIDC:

  • Users log in with their identity provider credentials
  • Quine Enterprise receives information about their roles
  • Access to features is automatically controlled based on those roles

What You Need From Your Identity Provider

Before configuring Quine Enterprise, your identity provider must be set up with the following:

Required Configuration

Your identity provider must provide these OIDC endpoint URLs. The exact path structure varies by provider, but all OIDC-compliant providers publish these endpoints in their configuration:

  • Issuer URL (Location URL): The base identity provider URL (e.g., https://{IDP_DOMAIN} or https://{IDP_DOMAIN}/{TENANT_OR_REALM})

  • Authorization Endpoint: Where users are redirected to authenticate. Path varies significantly by provider:

  • Token Endpoint: Where authorization codes are exchanged for tokens. Path varies by provider:

  • Login Path: OIDC provider's login endpoint path (appended to locationUrl for user redirect)

Rather than memorizing endpoint paths, OIDC-compliant providers publish a discovery document at https://{IDP_DOMAIN}/.well-known/openid-configuration containing the exact endpoints you need.

Additionally, you need:

  • Client ID: Application identifier in your identity provider
  • Client Secret: Secure password for your application

Required Roles

Your identity provider must include these six roles, which Quine Enterprise uses to control access. Each role is designed for a specific job function. Admin and Billing are specialized roles with narrow scopes; the product roles follow a clear hierarchy where each level includes all capabilities of the level below it.

Role Intended for What it can do What it cannot do
SuperAdmin Platform owners who need unrestricted access Everything — use sparingly Nothing is restricted
Admin Operations or SRE monitoring system health View metrics, cluster status, application state; shut down the application; control low-level system settings Read or write data, manage ingests, or modify any product features
Architect Senior engineers designing pipeline infrastructure Everything a DataEngineer can do, plus namespace management, shard limit configuration, user-defined function registration, and application metrics Administrative operations (shutdown, cluster status, system control)
DataEngineer Engineers building and operating data pipelines Create and manage ingests, query and write to the graph, manage standing queries, run algorithms, cancel queries Access application metrics, manage namespaces, configure shard limits, register user-defined functions
Analyst Business users and data analysts exploring data Query the graph, view ingests, view standing queries, view namespaces, use the Exploration UI Create, modify, or delete any resources
Billing Finance or procurement reviewing license usage View the license usage UI and its backing endpoint Access any other product features or administrative functions

Role Hierarchy

The product roles follow a clear containment hierarchy:

AnalystDataEngineerArchitectSuperAdmin

Each role in this chain includes all capabilities of the roles to its left, plus additional ones. Admin and Billing sit outside this hierarchy — they have specialized permission sets that do not overlap with the product roles.

Capabilities

Each role grants a set of capabilities that control access to specific API operations. The table below shows exactly which capabilities each role includes.

Capability Description SuperAdmin Admin Architect DataEngineer Analyst Billing
Graph
GraphRead Execute read-only Cypher queries against the graph.
GraphWrite Execute Cypher queries that modify graph data.
AllNodeScan Execute Cypher queries that scan all nodes in the graph.
Ingest
IngestRead List ingests and view their statuses.
IngestWrite Create new ingests.
IngestControl Pause and resume running ingests.
IngestDelete Stop and delete ingests.
Standing Query
StandingQueryRead List standing queries and view their configurations, but not their result streams.
StandingQueryWrite Create standing queries and add outputs.
StandingQueryDelete Delete standing queries and their outputs.
StandingQueryPropagate Re-propagate standing query registration to all applicable graph nodes.
Namespace
NamespaceRead List graphs (namespaces).
NamespaceWrite Create new graphs (namespaces).
NamespaceDelete Delete graphs (namespaces) and all their data.
Algorithm
AlgorithmRun Execute graph algorithms such as random walk.
AlgorithmResultsSave Execute an algorithm and save its results to a file.
Stored Query
StoredQueryRead View saved sample queries and quick queries.
StoredQueryWrite Create and edit sample queries and quick queries.
Node Appearance
NodeAppearanceRead View node appearance configurations.
NodeAppearanceWrite Create and edit node appearance configurations.
Query
QueryCancel Cancel a running graph query.
Administration
ApplicationStateRead View application build info, running configuration, and graph hash code.
ApplicationMetricsRead View application metrics.
ClusterStatusRead View cluster membership and status.
RolesRead View available roles and their permission sets.
Shutdown Initiate graceful application shutdown.
SystemControl Trigger garbage collection and read persisted system metadata.
NodeSleep Force a specific graph node into the sleep state.
GraphDebugRead View low-level debug information about specific graph nodes, including properties and edges.
Infrastructure
ShardLimitsRead View shard size limits.
ShardLimitsWrite Update shard size limits.
UserDefinedFunctionWrite Register user-defined functions and procedures.
UI
InteractiveApiView View the interactive REST API documentation.
License
LicenseRead View license details, entitlements, and usage data.

Setting Up Roles in Your Identity Provider

To enable role-based access control, you must configure your identity provider to support these six roles. While the specific steps vary by provider, the general process is the same across all OIDC-compliant identity providers:

1. Create the Roles

Create each of the six roles within your identity provider's role or group management system. Depending on your provider, these might be called "roles," "groups," "permissions," or "application roles."

2. Assign Users to Roles

After creating the roles, assign your users to the appropriate role(s). A user can have one or more roles depending on their job responsibilities. Users must be assigned to at least one of the six required roles; users without any of these roles will be unable to access Quine Enterprise.

3. Configure the Roles Claim

Configure your identity provider to emit a roles claim in the OIDC access token. Two requirements are non-negotiable:

  • The claim must be at the top level of the JWT. Quine Enterprise reads roles from the JWT root only. Nested locations — such as resource_access.<client>.roles, realm_access.roles, or schema-URI-style claim names — are not consulted. Most identity providers default to a nested location, and require a custom claim mapper, transformation, or rule to also emit a top-level roles claim.

  • Role values must match exactly. The values inside roles must be one or more of the six exact PascalCase strings: SuperAdmin, Admin, Architect, Analyst, DataEngineer, Billing. Matching is case-sensitive with no normalization — variants like admin, ADMIN, data-engineer, or dataEngineer are silently discarded.

A token Quine Enterprise accepts looks like this (other claims trimmed for clarity):

{
  "iss": "https://idp.example.com/...",
  "aud": "your-client-id",
  "sub": "a76a8d54-50d4-4ff2-a38b-135d426af310",
  "roles": ["SuperAdmin"]
}

If your identity provider's existing roles or groups are named something else (e.g., Acme-Admins, data_engineer), add a per-value mapping rule that translates each one to the corresponding Quine Enterprise role name before emitting it. Most providers support either renaming on emission or value-by-value mapping.

Diagnosing a misconfigured roles claim

If the roles claim is set up incorrectly, you will see one of two distinct symptoms:

Symptom Likely Cause
Browser loops between the login page and Quine Enterprise; /api/v2/auth/me returns 401 with CouldNotDecodeClaim in the response body's message field The roles claim is missing from the JWT root — likely still emitted only at a nested path
Login succeeds but every action is denied; /api/v2/auth/me returns 200 with empty roles: [] and permissions: [] The roles claim is at the JWT root, but the values do not match the six exact PascalCase spellings

To inspect what your identity provider is actually emitting, decode the access token's payload (the middle base64 segment between the two dots):

echo '<jwt>' | cut -d. -f2 | base64 -d | jq .

Consult your identity provider's documentation for the specific mechanism — typically called a claim mapper, claim transformation, or token customization rule — and configure it to:

  • Emit a top-level roles claim in the access token
  • Map your provider's role or group names to the six required values above
  • Ensure the role names are sent exactly as defined, case-sensitive

Once configured, when users authenticate through your identity provider, the OIDC token will automatically include their assigned roles at the expected location, and Quine Enterprise will use those roles to control their access to features.

Configuring Quine Enterprise for OIDC

Quine Enterprise is configured using Java system properties passed through Helm values. The configuration specifies the OIDC endpoint URLs, client credentials, and session management settings.

Quine Enterprise Full JAR System Properties Example

When running the Quine Enterprise JAR, below shows an example of configuring OIDC using Java system properties:

quine.conf
thatdot {
  audit {
    loglevel=INFO
  }
}
quine {
  license-key=
  auth {
    session {
      secret=
      expiration-seconds=3600
      secure-cookies=true
    }
    oidc {
      full {
        provider {
          location-url=
          authorization-url=
          token-url=
          login-path=
        }
        client {
          id=
          secret=
        }
      }
    }
  }
}
java -jar \
  -Dconfig.file=quine.conf \
  jars/quine-enterprise.jar

Populate each empty property with actual values.

OIDC Helm Values

Quine Enterprise requires the following OIDC properties to be set in your Helm values:

oidc:
  enabled: true
  provider:
    locationUrl: https://<IDP_DOMAIN>/<TENANT_OR_REALM>
    authorizationUrl: https://<IDP_DOMAIN>/<AUTHORIZATION_ENDPOINT_PATH>
    tokenUrl: https://<IDP_DOMAIN>/<TOKEN_ENDPOINT_PATH>
    loginPath: <LOGIN_PATH_FRAGMENT>
  client:
    existingSecret:
      name: <CLIENT_CREDENTIALS_SECRET>

Replace the placeholders with your identity provider's values:

  • <IDP_DOMAIN>: Your identity provider's domain (e.g., auth.example.com)
  • <TENANT_OR_REALM>: Your tenant, realm, or organization identifier (if required by your provider)
  • <AUTHORIZATION_ENDPOINT_PATH>: The full authorization endpoint path from your provider's .well-known/openid-configuration
  • <TOKEN_ENDPOINT_PATH>: The full token endpoint path from your provider's .well-known/openid-configuration
  • <LOGIN_PATH>: The login path segment (e.g., auth, authorize, or oauth2/v1/authorize depending on provider)

Session Management Properties

Helm Values

The helm chart for Quine Enterprise allows you to configure the session encryption secret, the session expiration time, and whether or not to use http-only secure cookies for session handling.

By default, the Quine Enterprise helm chart autogenerates the session secret, along with setting 3600 seconds (1 hour) for the session expiration time, and setting secure cookies to true. These can be overridden using the following helm values. Providing your own session secret is done by setting autoGenerate to false, and providing a reference to a Secret and its key.

Configure how user sessions are managed with Helm values:

oidc:
  session:
    autoGenerate: false
    existingSecret:
      name: ""
      key: ""
    expirationSeconds: 3600
    secureCookies: true

JAR via System Properties

Configure how user sessions are managed with Java System Properties. Replace the session secret value with your own:

-Dquine.auth.session.secret=<SECRET>
-Dquine.auth.session.expiration-seconds=3600
-Dquine.auth.session.secure-cookies=true

Authentication Methods

Once OIDC is configured, users and applications can interact with Quine Enterprise in two different ways depending on their use case:

Browser-Based UI Access (Session Cookies)

When a user accesses Quine Enterprise's web interface through a browser:

  1. The user is redirected to your identity provider's login page
  2. After successful authentication, the identity provider redirects the user back to Quine Enterprise
  3. Quine Enterprise automatically creates an HTTP session and stores it in a session cookie
  4. All subsequent browser requests include this session cookie, which Quine Enterprise uses to identify the authenticated user and their assigned roles
  5. The session remains valid for the configured expiration time (default: 1 hour)

No manual token handling is required – the browser automatically sends the session cookie with each request.

API Access (Bearer Tokens)

For programmatic access to Quine Enterprise's API (such as from scripts, tools, or external services), you need to use bearer tokens:

Prerequisites

Your identity provider should have a service account or machine-to-machine client credentials configured with the appropriate role(s) assigned. Consult your identity provider's documentation for specific steps to create client credentials.

Getting an Access Token

To access Quine Enterprise's API, first obtain an access token from your identity provider using the client credentials grant:

curl -X POST \
  <TOKEN_ENDPOINT> \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<CLIENT_ID>" \
  -d "client_secret=<CLIENT_SECRET>"

Replace the placeholders: - <TOKEN_ENDPOINT>: Your identity provider's token endpoint (from the .well-known/openid-configuration discovery document) - <CLIENT_ID>: The client ID for your service account - <CLIENT_SECRET>: The client secret for your service account

The response will include an access_token that you can use to make API calls:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Using the Token in API Calls

Use the access token in the Authorization header of your API requests:

curl -X GET \
  http://localhost:8080/api/v2/some-endpoint \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

The token will be validated by Quine Enterprise, and the request will proceed if the token is valid and the associated service account has the appropriate role(s) for that API endpoint.

Token Expiration: Tokens typically expire after a short period. When a token expires, request a new one from your identity provider using the client credentials flow above.

How to Interpret Auth Errors

If a user attempts to issue a request to an endpoint they don't have authorization with, they will receive an error of the following shape:

{
  "errors": [
    {
      "message": "Missing Permission: <MISSING_PERMISSION>",
      "type": "ApiError"
    }
  ]
}

The <MISSING_PERMISSION> shows why the user was not authorized to perform the action due to the missing permission.

Audit Logging

To enable audit logging, add the -Dthatdot.audit.loglevel=INFO java system property to your configuration.

When set, you will then see audit logs emitted from Quine Enterprise. Audit logs track important security events such as user authentication, token refresh, and API calls. This provides a complete audit trail for compliance, security monitoring, and forensics.

Field Explanations

Authentication Attempt ID

The Authentication Attempt ID is a unique identifier generated at the start of each login flow. It remains constant throughout the entire authentication process and allows you to correlate all the individual steps of a login attempt in the audit log.

  • Purpose: Trace the complete sequence of validation steps for a single login
  • Scope: Spans from initial OAuth state validation through final session creation
  • Uniqueness: Cryptographically strong UUID generated per login attempt (FIPS-compliant when available)
  • Example: dfa5fca3-26db-48c5-864a-c8a29abcefac
Action ID

The Action ID is a unique identifier generated for each API request. It allows you to correlate the initial API call attempt with its outcome (success, prevented, or exception).

  • Purpose: Track the complete lifecycle of an individual API request
  • Scope: From request initiation through response completion
  • Uniqueness: Cryptographically strong UUID generated per API request (FIPS-compliant when available)
  • Example: 28f89843-4567-4523-bad1-7316a7ab8eb2
User Identifiers

When an authenticated user makes an API call, three user-related identifiers appear in the audit log:

  • sub (Subject): The unique user identifier from the OAuth provider. This is the permanent identifier for the user in your system.
  • Example: b55a4959-744e-400e-84de-26a22774cda8

  • a64 (Access Token Hash): The first 64 bits of the HMAC SHA-256 hash of the user's access token. This provides a short identifier for tracing token-specific activity without logging sensitive credentials.

  • Example: MgGBEDKIaxY=

  • s64 (Session Token Hash): The first 64 bits of the HMAC SHA-256 hash of the user's session token. This identifies which session was used for the request.

  • Example: vhEmIRYLdEU=

Example Audit Logs

Login
2025-11-14T17:10:33.589322628Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] Validating OAuth State. Provided (hashed): 4zW+vj65uVs=
2025-11-14T17:10:33.589634878Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] State Validation succeeded.
2025-11-14T17:10:33.590030044Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] Exchanging Authentication Code for Token. Code hash: xO2Di/Ty7CM=
2025-11-14T17:10:33.622655794Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] Validating Token. ID Token hash: SUe4WMtoIrM=, Access Token hash: MgGBEDKIaxY=
2025-11-14T17:10:33.663103253Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] Valid ID Token. sub: b55a4959-744e-400e-84de-26a22774cda8
2025-11-14T17:10:33.666020419Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] Valid Nonce. sub: b55a4959-744e-400e-84de-26a22774cda8
2025-11-14T17:10:33.667495253Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] ID Token verification succeeded. sub: b55a4959-744e-400e-84de-26a22774cda8
2025-11-14T17:10:33.673789169Z [Login] [Authentication Attempt ID: dfa5fca3-26db-48c5-864a-c8a29abcefac] succeeded. sub: b55a4959-744e-400e-84de-26a22774cda8, Session Token hash: vhEmIRYLdEU=

What to look for: All log entries for a single login attempt share the same Authentication Attempt ID. If a login fails, you can use the ID to review all validation steps that were performed.

API Calls
2025-11-14T17:10:34.433407753Z [API Call] [Action ID: 28f89843-4567-4523-bad1-7316a7ab8eb2] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Quick Queries] called. Path: /queryUi/quickQueries
2025-11-14T17:10:34.433419003Z [API Call] [Action ID: 62d7db21-f3a1-44f3-8740-8911255062dd] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Node Appearances] called. Path: /queryUi/nodeAppearances
2025-11-14T17:10:34.433402503Z [API Call] [Action ID: ad5e5315-8ae7-487b-bb06-939790bb9609] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Sample Queries] called. Path: /queryUi/sampleQueries
2025-11-14T17:10:34.435678670Z [API Call] [Action ID: 28f89843-4567-4523-bad1-7316a7ab8eb2] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Quick Queries] succeeded.
2025-11-14T17:10:34.435745253Z [API Call] [Action ID: ad5e5315-8ae7-487b-bb06-939790bb9609] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Sample Queries] succeeded.
2025-11-14T17:10:34.435745253Z [API Call] [Action ID: 62d7db21-f3a1-44f3-8740-8911255062dd] [sub: b55a4959-744e-400e-84de-26a22774cda8, a64: MgGBEDKIaxY=, s64: vhEmIRYLdEU=] [List Node Appearances] succeeded.

What to look for: Each API request appears twice in the audit log—once when the request is initiated ("called") and once with the outcome ("succeeded"). Both log entries share the same Action ID, allowing you to correlate them. The Action ID uniquely identifies that specific API request.