# OpenID Connect

{% hint style="info" %}
This feature is only available for Bindplane Enterprise, Google Enterprise and Google Editions.
{% endhint %}

{% hint style="warning" %}
Changing the Authentication type on the Bindplane server will automatically remove all existing users and permissions. The first user to log in after the change will become an Organization Admin and owner of all existing Projects. Subsequent users will need to be re-invited to their respective projects or provisioned properly via [custom claims](#id-4.-custom-claims-mapping).
{% endhint %}

### 1. Prerequisites

Before beginning, ensure you have the following:

* An OpenID Connect (OIDC) provider configured and available.
* OAuth2 Client ID and Client Secret from your OIDC provider.

### 2. Identity Provider Configuration

Each Identity Provider will have different steps for configuring an OIDC application. Below are details commonly needed for most configurations.

* Bindplane uses an **Authorization Code** flow
* **Redirect URI**: \<remoteURL/webURL>**/oidc/redirect**

### 3. Bindplane Server Configuration

#### Configuration Steps

1. Open the Bindplane configuration file (by default at `/etc/bindplane/config.yaml`).
2. Add or modify the following OIDC configuration settings:

```yaml
auth:
  type: oidc
  oidc:
    issuer: "https://your-oidc-provider.com"
    oauth2ClientID: "your-client-id"
    oauth2ClientSecret: "your-client-secret"
    scopes:
      - openid
      - profile
      - email
```

3. Replace the placeholder values:
   * `issuer`: Your OIDC provider's URL
   * `oauth2ClientID`: OAuth2 client ID from your OIDC provider
   * `oauth2ClientSecret`: OAuth2 client Secret from your OIDC provider

**Optional: Just-In-Time Provisioning with Custom Claims**

Enable `disableInvitations` to require users to have valid custom claims for provisioning. This enables just-in-time (JIT) provisioning without requiring manual invitations.

```yaml
auth:
  type: oidc
  oidc:
    issuer: "https://your-oidc-provider.com"
    oauth2ClientID: "your-client-id"
    oauth2ClientSecret: "your-client-secret"
    scopes:
      - openid
      - profile
      - email
    disableInvitations: true
```

When `disableInvitations` is enabled, users must provide valid custom claims in their OIDC token to be provisioned. When disabled (default), users can log in with an invitation code even without custom claims. See [Custom Claims Mapping](#id-4.-custom-claims-mapping) below.

4. Restart Bindplane to apply the changes:

```bash
systemctl restart bindplane
```

### Environment Variables

The same settings can also be provided using environment vairables:

```
BINDPLANE_OIDC_OAUTH2_CLIENT_ID=your-client-id
BINDPLANE_OIDC_OAUTH2_CLIENT_SECRET=your-client-secret
BINDPLANE_OIDC_ISSUER=https://your-oidc-provider.com
BINDPLANE_OIDC_SCOPES=openid,profile,email
BINDPLANE_OIDC_DISABLE_INVITATIONS=true
```

#### 4. Custom Claims Mapping

Custom claims in your OIDC token enable automatic role assignment and project access provisioning during login. Bindplane supports two approaches: **IdP groups/roles** and **direct token claims**.

**Supported Custom Claims**

| Claim                    | Type         | Description                                                                                    | Example                                                   |
| ------------------------ | ------------ | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `bindplane_default_role` | string       | Default role for users when no project-specific role is set. Values: `admin`, `user`, `viewer` | `"admin"`                                                 |
| `bindplane_org_admin`    | string       | Whether the user is an organization administrator. Values: `"true"`, `"false"`                 | `"true"`                                                  |
| `bindplane_projects`     | string       | Comma-separated list of project/project IDs with optional per-project roles                    | `"project1,project2"` or `"admin:project1,user:project2"` |
| `groups` or `group_ids`  | array/string | IdP groups for role inference                                                                  | `["bindplane-admin", "bindplane-projects-<Project-1>"]`   |
| `roles`                  | array/string | IdP roles for role inference                                                                   | `["bindplane-user"]`                                      |

#### **Approach 1: Direct Token Claims**

Direct token claims provide explicit role assignments via custom claims in the OIDC token.

**Example token payload:**

```json
{
  "sub": "user123",
  "email": "user@example.com",
  "bindplane_default_role": "user",
  "bindplane_org_admin": "false",
  "bindplane_projects": "admin:<PROJECT-ID-1>,viewer:<PROJECT-ID-2>"
}
```

**Claims Behavior:**

* **bindplane\_default\_role**: Sets the default role for projects without a project-specific role. Defaults to `viewer` if not set.
* **bindplane\_org\_admin**: When `"true"`, the user becomes an organization administrator with `admin` role on all projects. Organization admins ignore `bindplane_projects` and `bindplane_default_role` claims as the user will gain admin access to all projects within the organization.
* **bindplane\_projects**: Comma-separated list of project IDs. Two formats are supported:
  * **Project IDs only** (e.g., `"<Project-ID-1,Project-ID-2>"`): User gets the role from `bindplane_default_role`, or `viewer` if not set.
  * **Per-project roles** (e.g., `"admin:<Project-ID-1>,user:<Project-ID-2>,viewer:<Project-ID-3>"`): User gets the specified role for each projects, overriding `bindplane_default_role`.

When `bindplane_projects` is set, the user only has access to listed projects. Existing access to unlisted projects are revoked.

#### **Approach 2: Groups-Based Role Inference**

If your OIDC provider doesn't support custom claims, you can use IdP groups or roles for role inference.

**Recognized group/role names** (case-insensitive):

* `bindplane-admin` → `admin` role
* `bindplane-user` → `user` role
* `bindplane-viewer` → `viewer` role
* `admin`, `user`, `viewer` → corresponding role

**Project membership via groups:** Use the prefix `bindplane-projects-<Project-ID>` to grant access to specific projects:

```
bindplane-projects-<Project-ID-1>
bindplane-projects-<Project-ID-2>
```

**Groups behavior:**

1. The first matching role name (case-insensitive) in groups sets the default role
2. If `bindplane-org-admin` group is present, the user becomes an organization admin and project admin across all the projects.
3. Groups matching `bindplane-projects-<Project-ID>` grant access to those projects

**Example token payload:**

```json
{
  "sub": "user123",
  "email": "user@example.com",
  "groups": [
    "bindplane-admin",
    "bindplane-projects-<PROJECT-1>",
    "bindplane-projects-<PROJECT-2>"
  ]
}
```

Result: User gets `admin` role access to `<PROJECT-1>` and `<PROJECT-2>`.

**Role Assignment Priority**

When both approaches are present:

1. **Explicit `bindplane_default_role` claim** → Uses this role (ignores groups/roles)
2. **Groups/roles inference** → Infers role from IdP groups (if `bindplane_default_role` not set)
3. **Per-project roles in `bindplane_projects`** → Uses specified role for each project

**Example with mixed claims:**

```json
{
  "sub": "user123",
  "email": "user@example.com",
  "bindplane_default_role": "admin",
  "groups": ["bindplane-viewer"],
  "bindplane_projects": "user:<PROJECT-ID-1>"
}
```

Result:

* User gets `admin` role for `<PROJECT-ID-1>` (explicit claim overrides everything)
* Groups are ignored (because `bindplane_default_role` is set)
* For any other project, user gets `admin` (from `bindplane_default_role`, not from groups)

**Least Privileged User (LPU) Principle**

When a user has multiple explicit role assignments across different projects (via `role:projectId` format), Bindplane applies the least privileged principle.

**Role hierarchy** (most to least privileged):

```
Admin > User > Viewer
```

**LPU behavior:** The minimum privilege from explicit assignments becomes the fallback role for projects without explicit role assignment. This ensures users don't inadvertently gain unintended access.

**Example:**

```
bindplane_projects: "admin:<PROJECT-ID-1>,user:<PROJECT-ID-2>,viewer:<PROJECT-ID-2>"
```

* User gets `admin` on `Project 1`
* User gets `viewer` on `Project 2`&#x20;

**Organization Admin vs Project Access**

**Organization Admins** (`bindplane_org_admin: "true"`):

* User becomes an organization administrator
* User gets `admin` role on **all** projects in the organization
* `bindplane_projects` and `bindplane_default_role` claims are ignored

**Project-Level Access** (`bindplane_org_admin` unset or `"false"`):

* User gets access based on `bindplane_projects` and `bindplane_default_role`
* Access is scoped to projects listed in `bindplane_projects`
* Role defaults to `viewer` if not specified

**Conflicting Claims Resolution**

If a user's token contains conflicting information, Bindplane resolves it as follows:

* **Multiple role assignments**: LPU principle applies; the least privileged role is used as the fallback
* **Organization admin + project access**: Organization admin takes precedence; project claims are ignored
* **Invalid role names**: Unrecognized role values default to `viewer`
* **Malformed project IDs**: Invalid entries in `bindplane_projects` are skipped

**Note:** If the token/claims are incorrect or not parsed correctly then no provisioning changes are made and their logins retain their pre-existing permissions.

### 5. User Enrollment

After configuration, users will be redirected to your OIDC provider for authentication when accessing Bindplane.

The first user that logs in after configuration will be automatically created as the Organization Admin. Subsequent users will need to be invited or manually added to a Project before they are able to login using OIDC. For more details on adding additional users see:

* [Add Users using the Bindplane CLI](/cli-and-api/cli.md)

When `disableInvitations` is enabled, user role and project access are synced on every login, ensuring changes to IdP claims are reflected immediately in Bindplane.

### 6. Token claim name customizations

Starting in Bindplane version [v1.100.2](https://docs.bindplane.com/changelog/), within the server configuration you can modify the default names of `bindplane_default_role` , `bindplane_org_admin`, `bindplane_projects` to fit whatever schema/organizational naming policy limitations. Configure these under `auth.oidc.customClaims` .

Below are the fields that you can use to customize where Bindplane looks in the token to provision users.

| Field                                      | Default                  |
| ------------------------------------------ | ------------------------ |
| `auth.oidc.customClaims.groups`            | `groups`                 |
| `auth.oidc.customClaims.groupIds`          | `group_ids`              |
| `auth.oidc.customClaims.roles`             | `roles`                  |
| `auth.oidc.customClaims.organizationAdmin` | `bindplane_org_admin`    |
| `auth.oidc.customClaims.projects`          | `bindplane_projects`     |
| `auth.oidc.customClaims.defaultRole`       | `bindplane_default_role` |

```yaml
auth:
  type: oidc
  oidc:
    # Rename the claims Bindplane reads on the ID token. Omit a key to keep the default claim name.
    customClaims:
      # Default key: "groups"
      groups: "groups"

      # Default key: "group_ids"
      # Fallback list of group identifiers if groups is missing, empty, or parses to an empty list, Bindplane uses group_ids as a fallback.
      groupIds: "group_ids"

      # Default key: "roles"
      roles: "roles"

      # Default key: "bindplane_org_admin"
      organizationAdmin: "bindplane_org_admin"

      # Default key: "bindplane_projects"
      projects: "bindplane_projects"

      # Default key: "bindplane_default_role"
      defaultRole: "bindplane_default_role"
```

Use these to change the IdP group/role membership strings Bindplane matches (not JWT claim names). They apply to values in the [`groups`](#approach-2-groups-based-role-inference) claims configured above.

| Field                                        | Default               |
| -------------------------------------------- | --------------------- |
| `auth.oidc.customClaims.orgAdminGroupName`   | `bindplane-org-admin` |
| `auth.oidc.customClaims.projectsGroupPrefix` | `bindplane-projects-` |
| `auth.oidc.customClaims.adminGroupName`      | `bindplane-admin`     |
| `auth.oidc.customClaims.userGroupName`       | `bindplane-user`      |
| `auth.oidc.customClaims.viewerGroupName`     | `bindplane-viewer`    |

```yaml
auth:
  type: oidc
  oidc:
    # Strings Bindplane matches inside the groups and roles claims (after resolving claim names above).
    customClaims:
      # Default: "bindplane-org-admin"
      orgAdminGroupName: "bindplane-org-admin"

      # Default: "bindplane-projects-"
      # Prefix for group entries that encode project access, e.g. "bindplane-projects-<projectId>".
      # Also valid to supply in this format e.g. "bindplane-projects-<role>:<Project ID>" i.e. groups: ["bindplane-projects-admin:01PROJECTID", "bindplane-projects-viewer:01PROJECTID2"]
      projectsGroupPrefix: "bindplane-projects-"

      # Default: "bindplane-admin"
      adminGroupName: "bindplane-admin"

      # Default: "bindplane-user"
      userGroupName: "bindplane-user"

      # Default: "bindplane-viewer"
      viewerGroupName: "bindplane-viewer"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bindplane.com/configuration/bindplane/authentication/openid-connect-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
