# OIDC and OAuth integration

OpenIAM acts as a fully-featured **OAuth 2.0 Authorization Server** and **OpenID Connect Provider (OP)**.

This document covers two things:

1. **Admin UI** — how to configure an OAuth/OIDC client in the webconsole
2. **Endpoints** — the live URLs an application uses to run OAuth/OIDC flows

## Concepts: Scopes as Resources

In OpenIAM, **OAuth scopes are modelled as Resources** in the resource catalogue.\
When you assign scopes to an OAuth client, you are selecting which Resources the client is allowed to request.\
Standard OIDC scopes (`openid`, `profile`, `email`) are also backed by system Resources.

## Creating an OAuth client

{% stepper %}
{% step %}

### Create an authentication provider

To create a new authentication provider:

* Log in to **Webconsole** and go to **Access Control** → **Authentication Providers**.
* Select **Create New Provider**.
* Select **OAuth Client** from **Select a Provider Type**.

<figure><img src="/files/1e791e3dad5c8df9a36804ba4d4ee5e02db61a8f" alt=""><figcaption></figcaption></figure>

Give the provider a descriptive **Name** (e.g., `My App – Production`).

The system will auto-generate:

<table><thead><tr><th width="156.33331298828125">Field</th><th width="155">Example</th><th>Notes</th></tr></thead><tbody><tr><td><strong>Client ID</strong></td><td><code>3f8a1c2d-...</code></td><td>UUID, read-only after creation</td></tr><tr><td><strong>Client Secret</strong></td><td><code>aBcD1234...</code></td><td>Read-only, shown once; rotate via Regenerate</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure the OAuth client provider

<figure><img src="/files/1e791e3dad5c8df9a36804ba4d4ee5e02db61a8f" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="236.3333740234375">Field Name</th><th>Description</th></tr></thead><tbody><tr><td>Provider name</td><td>A descriptive name for this configuration, such as <code>OpenIAM OAuth2 with Spring Boot</code>.</td></tr><tr><td>Redirect URL</td><td>Redirect URLs are a critical part of the OAuth flow. After a user successfully authorizes an application, the authorization server will redirect the user back to the application with either an authorization code or access token in the URL. Since the redirect URL can contain sensitive information, it is critical that the service doesn't redirect the user to an arbitrary location.</td></tr><tr><td>Allow multiple Active Tokens</td><td>Set this value to <code>Off</code>, which is the default.</td></tr><tr><td>Signing Algorithm</td><td>Select the algorithm used to sign tokens issued for your application or API. For example, <code>RS-256</code>.</td></tr><tr><td>JWT Issuer</td><td>Identifies the client that the JWT is issued to. You can use a descriptive value such as <code>openiam-spring-test</code>.</td></tr><tr><td>Final JWT Issuer view</td><td>Generated automatically after you enter the <strong>JWT Issuer</strong> value.</td></tr><tr><td>OpenID Connect Discovery URL</td><td>Generated automatically after you enter the <strong>JWT Issuer</strong> value. Use this URL to configure OIDC clients.</td></tr><tr><td>Authorization Grant Flow</td><td>Select the grant type your application will use. This setting must match the flow configured in the client application. For this example, select <code>Authorization Code</code>.</td></tr><tr><td>Client Authentication Type</td><td>Describes how the client sends credentials to the authorization server. You can choose <strong>Basic Authentication</strong> or <strong>Request Body</strong>.</td></tr><tr><td>Default Scopes</td><td>Scopes limit the access granted to a token. Select the scopes from the dropdown. In OpenIAM, scopes are resources that you manage through <strong>Resource Manager</strong>.</td></tr><tr><td>Skip scope approval</td><td>Set this to <code>Off</code>.</td></tr><tr><td>Token expiration</td><td>The access token expires after the specified period of inactivity. A common value is <em>30</em> minutes.</td></tr><tr><td>Use refresh token</td><td>Refresh tokens let the client request a new access token. In most cases, set this value to <code>Off</code>.</td></tr><tr><td>Protect by 2FA</td><td>Set this value to <code>Off</code> unless you want to use 2FA during the authentication process.</td></tr></tbody></table>

This example shows a provider configuration for the Spring Boot test application referenced earlier in this page.

After you save the configuration, OpenIAM generates the `clientId` and `clientSecret` for the OAuth 2.0 client.
{% endstep %}

{% step %}

### Configure core settings

Configure the following:

* **JWT Issuer** — a short identifier used to construct the OIDC issuer URL: `/idp/oauth2/{jwtIssue}`. It must be unique across all providers.
* **Issuer URL** — computed as `https://{host}/idp/oauth2/{jwtIssue}`
* **Discovery URL** — computed as `https://{host}/idp/oauth2/{jwtIssue}/.well-known/openid-configuration`
  {% endstep %}

{% step %}

### Choose a grant flow

You can select one in the **Authorization Grant Flow** dropdown.

<table><thead><tr><th width="211.66668701171875">Grant Flow</th><th>When to use</th></tr></thead><tbody><tr><td><code>AUTHORIZATION_CODE</code></td><td>Web apps with a back-end server (most common, most secure)</td></tr><tr><td><code>AUTHORIZATION_CODE</code> + PKCE</td><td>Single-page apps, mobile / native apps (no client secret)</td></tr><tr><td><code>CLIENT_CREDENTIALS</code></td><td>Machine-to-machine (no user involved)</td></tr><tr><td><code>REFRESH_TOKEN</code></td><td>Any flow that needs long-lived access via refresh tokens</td></tr><tr><td><code>IMPLICIT</code></td><td><strong>Legacy only.</strong> Not recommended — use Authorization Code + PKCE instead</td></tr><tr><td><code>HYBRID</code></td><td>Returns code + token (or id_token) in the authorization response</td></tr></tbody></table>

{% hint style="info" %}
Multiple flows can co-exist: e.g., enable `AUTHORIZATION_CODE` + check **Use Refresh Token** to also allow the refresh grant.
{% endhint %}
{% endstep %}

{% step %}

### Select client authentication type

It controls how the client proves its identity when calling the Token endpoint.

<table><thead><tr><th width="139">Auth Type</th><th width="311.33331298828125">Transport</th><th>When to use</th></tr></thead><tbody><tr><td><code>BASIC</code></td><td>HTTP <code>Authorization: Basic base64(id:secret)</code></td><td>Default for confidential apps</td></tr><tr><td><code>POST</code></td><td><code>client_id</code> + <code>client_secret</code> in POST body</td><td>When Basic Auth is not supported</td></tr><tr><td><code>JWT</code></td><td>Client-signed JWT (private key)</td><td>High-security, no secret transmitted</td></tr><tr><td><code>ASSERTION</code></td><td>Generic assertion (SAML or JWT bearer)</td><td>Federation scenarios</td></tr><tr><td><code>DEVICE</code></td><td>Out-of-band device flow</td><td>Smart TVs, CLIs, IoT</td></tr></tbody></table>

For **Client Authentication Type = JWT**, also set:

* **JWT Signing Algorithm** — e.g., `RS256`, `HS256`, `ES256`
* **Client JWT Validation URL** — JWKS endpoint to fetch the client's public key for validation
* **Client JWT Validation Key** — Symmetric (HMAC) key if using HS256

For **Client Assertion Type**, choose:

* `JWT_BEARER` — RFC 7523 JWT Bearer grant
* `SAML_BEARER` — RFC 7522 SAML 2.0 Bearer grant
  {% endstep %}

{% step %}

### Configure token and session settings

<table><thead><tr><th width="217.33331298828125">Field</th><th width="134.33331298828125">Unit</th><th>Description</th></tr></thead><tbody><tr><td><strong>Token Expiration</strong></td><td>seconds</td><td>Lifetime of access tokens (e.g., <code>3600</code> = 1 hour)</td></tr><tr><td><strong>Max Active Session Time</strong></td><td>seconds</td><td>Maximum total authenticated session time</td></tr><tr><td><strong>Use Refresh Token</strong></td><td>boolean</td><td>Enable refresh token grant for this client</td></tr><tr><td><strong>Multiple Active Tokens Allowed</strong></td><td>boolean</td><td>Allow concurrent active tokens (default: one token per user per client)</td></tr></tbody></table>
{% endstep %}

{% step %}

### Configure authentication acopes

In the **OAuth Scopes** multi-select, pick the Resources this client is allowed to request.

Common selections:

* `openid` — Required for OIDC; triggers ID token issuance
* `profile` — Basic user profile claims (name, locale, etc.)
* `email` — Email address claim
* Custom resources — Business-specific API scopes
  {% endstep %}

{% step %}

### Select redirect URIs

Add every allowed callback URL in the **Redirect URIs** list.

Rules:

* Must match **exactly** (including trailing slashes) what the app sends in `redirect_uri`
* Add all environments: `https://app.example.com/callback`, `http://localhost:3000/callback`
  {% endstep %}

{% step %}

### Select advanced options

<table><thead><tr><th width="239">Option</th><th>Effect</th></tr></thead><tbody><tr><td><strong>Skip Scopes Dialog</strong></td><td>Suppress the user consent screen — scopes are auto-approved</td></tr><tr><td><strong>Protected by 2FA</strong></td><td>User must complete 2FA before a token is granted</td></tr><tr><td><strong>Send ID Token as Access Token</strong></td><td>Returns the ID token value as the access token (non-standard, for legacy integrations)</td></tr><tr><td><strong>Public Application Key</strong></td><td>A stable key for public/native clients that cannot store a <code>client_secret</code> securely</td></tr></tbody></table>
{% endstep %}

{% step %}

### Save and retrieve credentials

Click **Save**. The **Client ID** and **Client Secret** are displayed.\
Share these with the application developer:

{% code overflow="wrap" %}

```html
Client ID:     3f8a1c2d-4e5f-6789-abcd-ef0123456789
Client Secret: <shown after save — store securely, not visible again>
Issuer:        https://iam.example.com/idp/oauth2/myapp
Discovery:     https://iam.example.com/idp/oauth2/myapp/.well-known/openid-configuration
```

{% endcode %}
{% endstep %}
{% endstepper %}

## Managing OAuth tokens per user

Users' token can be managed using the respective tab in the Users menu **Webconsole** → **Users** → \[select user] → **OAuth Tokens** tab. It shows a table of active tokens.

<table><thead><tr><th width="170.66668701171875">Column</th><th>Description</th></tr></thead><tbody><tr><td>Client</td><td>OAuth client (provider) name</td></tr><tr><td>Grant Type</td><td>Flow used to obtain the token</td></tr><tr><td>Issued</td><td>Creation timestamp</td></tr><tr><td>Expires</td><td>Expiry timestamp</td></tr><tr><td>Actions</td><td><strong>Revoke</strong> button to immediately invalidate the token</td></tr></tbody></table>

## API endpoints reference

All endpoints are hosted on the IDP module. Base URL: `https://{host}/idp`

### OIDC discovery

```
GET /idp/oauth2/{issuer}/.well-known/openid-configuration
```

Returns the full OIDC Provider Metadata JSON. Clients that support auto-discovery (most modern libraries) only need this URL.

**Example response (abbreviated):**

```json
{
  "issuer": "https://iam.example.com/idp/oauth2/myapp",
  "authorization_endpoint": "https://iam.example.com/idp/oauth2/authorize",
  "token_endpoint": "https://iam.example.com/idp/oauth2/token",
  "userinfo_endpoint": "https://iam.example.com/idp/oauth2/userinfo",
  "jwks_uri": "https://iam.example.com/idp/oauth2/myapp/.well-known/jwks",
  "response_types_supported": ["code", "token", "id_token", "code token", "code id_token"],
  "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token", "implicit"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "private_key_jwt"],
  "id_token_signing_alg_values_supported": ["RS256", "HS256", "ES256"],
  "scopes_supported": ["openid", "profile", "email"]
}
```

### Authorization endpoint

```
GET /idp/oauth2/authorize
```

Initiates an OAuth/OIDC flow. The browser (not the server) hits this URL.

**Query parameters:**

<table><thead><tr><th width="212">Parameter</th><th width="150.33331298828125">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>response_type</code></td><td>Yes</td><td><code>code</code> (Authorization Code), <code>token</code> (Implicit), <code>code token</code>, <code>code id_token</code> (Hybrid)</td></tr><tr><td><code>client_id</code></td><td>Yes</td><td>The client's UUID</td></tr><tr><td><code>redirect_uri</code></td><td>Yes</td><td>Must match a registered redirect URI exactly</td></tr><tr><td><code>scope</code></td><td>Yes</td><td>Space-separated. Include <code>openid</code> for OIDC.</td></tr><tr><td><code>state</code></td><td>Recommended</td><td>Random value; echoed back to prevent CSRF</td></tr><tr><td><code>nonce</code></td><td>Required for OIDC</td><td>Random value embedded in ID token to prevent replay</td></tr><tr><td><code>prompt</code></td><td>Optional</td><td><code>none</code> (no UI), <code>login</code> (force re-auth), <code>select_account</code></td></tr><tr><td><code>max_age</code></td><td>Optional</td><td>Max seconds since last authentication</td></tr><tr><td><code>code_challenge</code></td><td>PKCE</td><td>Base64url(SHA256(code_verifier))</td></tr><tr><td><code>code_challenge_method</code></td><td>PKCE</td><td><code>S256</code> (recommended) or <code>plain</code></td></tr></tbody></table>

**Example — Authorization Code request:**

```
GET /idp/oauth2/authorize
  ?response_type=code
  &client_id=3f8a1c2d-4e5f-6789-abcd-ef0123456789
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
  &scope=openid%20profile%20email
  &state=xyz-random-state
  &nonce=abc-random-nonce
```

**Success redirect:**

```html
https://app.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz-random-state
```

**Error redirect:**

{% code overflow="wrap" %}

```html
https://app.example.com/callback?error=access_denied&error_description=User+denied+access&state=xyz-random-state
```

{% endcode %}

### Token endpoint

```
POST /idp/oauth2/token
Content-Type: application/x-www-form-urlencoded
```

Exchanges a code for tokens, or directly issues tokens for non-interactive grants.

**Common parameters:**

<table><thead><tr><th width="206.6666259765625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>grant_type</code></td><td><code>authorization_code</code>, <code>client_credentials</code>, <code>refresh_token</code></td></tr><tr><td><code>client_id</code></td><td>Client UUID (for <code>client_secret_post</code> auth)</td></tr><tr><td><code>client_secret</code></td><td>Client secret (for <code>client_secret_post</code> auth)</td></tr><tr><td><code>code</code></td><td>Authorization code (Authorization Code flow only)</td></tr><tr><td><code>redirect_uri</code></td><td>Must match the authorization request (Authorization Code flow only)</td></tr><tr><td><code>refresh_token</code></td><td>Refresh token (Refresh Token flow only)</td></tr><tr><td><code>scope</code></td><td>Requested scopes (Client Credentials flow)</td></tr><tr><td><code>code_verifier</code></td><td>PKCE verifier (Authorization Code + PKCE only)</td></tr></tbody></table>

**Authentication:** send `Authorization: Basic base64(client_id:client_secret)` (preferred) or include `client_id`/`client_secret` in the POST body.

**Example response:**

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "8xLOxBtZp8",
  "id_token": "eyJhbGciOiJSUzI1NiJ9...",
  "scope": "openid profile email"
}
```

### UserInfo endpoint

```
GET  /idp/oauth2/userinfo
POST /idp/oauth2/userinfo
Authorization: Bearer <access_token>
```

Returns claims about the authenticated user. Requires an access token granted with at least `openid` scope.

**Example response:**

```json
{
  "sub": "3f8a1c2d-4e5f-6789-abcd-ef0123456789",
  "name": "Jane Smith",
  "given_name": "Jane",
  "family_name": "Smith",
  "email": "jane.smith@example.com",
  "email_verified": true,
  "locale": "en-US"
}
```

Claims returned depend on the scopes granted:

* `openid` → `sub`
* `profile` → `name`, `given_name`, `family_name`, `locale`, etc.
* `email` → `email`, `email_verified`

### JWKS endpoint

```
GET /idp/oauth2/{issuer}/.well-known/jwks
```

Returns the provider's public keys in JSON Web Key Set format. Used by resource servers (APIs) and relying parties to verify token signatures without calling OpenIAM.

**Example response:**

```json
{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "key-id-1",
      "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2...",
      "e": "AQAB"
    }
  ]
}
```

> There is also a legacy per-client JWKS endpoint: `GET /idp/oauth2/.well-known/jwks/{clientId}` (deprecated, kept for backward compatibility).

### Token introspection

```
GET  /idp/oauth2/token/info?token={access_token}
POST /idp/oauth2/token/info
```

Validates a token and returns its metadata. Intended for resource servers that need to verify tokens issued by OpenIAM.

**Example response (active token):**

```json
{
  "active": true,
  "sub": "jane.smith",
  "client_id": "3f8a1c2d-...",
  "scope": "openid profile email",
  "exp": 1741200000
}
```

### Token revocation

```
POST /idp/oauth2/revoke
GET  /idp/oauth2/revoke
```

Immediately invalidates an access token or refresh token.

<table><thead><tr><th width="193.33331298828125">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>token</code></td><td>The token to revoke</td></tr><tr><td><code>token_type_hint</code></td><td>Optional: <code>access_token</code> or <code>refresh_token</code></td></tr></tbody></table>

## Grant flow examples

### Authorization Code Flow

Best for: confidential web apps with a server-side back-end.

{% code overflow="wrap" expandable="true" %}

```powerquery
1. Browser → OpenIAM:
   GET /idp/oauth2/authorize?response_type=code&client_id=...&redirect_uri=...&scope=openid profile&state=...&nonce=...

2. OpenIAM → Browser (redirect after login + consent):
   https://app.example.com/callback?code=AUTH_CODE&state=...

3. Server → OpenIAM (back-channel):
   POST /idp/oauth2/token
   Authorization: Basic base64(client_id:client_secret)
   grant_type=authorization_code&code=AUTH_CODE&redirect_uri=...

4. OpenIAM → Server:
   { "access_token": "...", "id_token": "...", "refresh_token": "...", "expires_in": 3600 }
```

{% endcode %}

### Authorization code + PKCE (for public applications)

Best for: SPAs, mobile apps, CLI tools — clients that cannot keep a secret.

{% code overflow="wrap" expandable="true" %}

```powerquery
1. App generates:
   code_verifier  = random 43–128 char string
   code_challenge = BASE64URL(SHA256(code_verifier))

2. Browser → OpenIAM:
   GET /idp/oauth2/authorize?response_type=code&client_id=...&redirect_uri=...
     &scope=openid&state=...&code_challenge=CHALLENGE&code_challenge_method=S256

3. OpenIAM → Browser (redirect):
   https://app.example.com/callback?code=AUTH_CODE&state=...

4. App → OpenIAM:
   POST /idp/oauth2/token
   grant_type=authorization_code&code=AUTH_CODE&redirect_uri=...
   &client_id=...&code_verifier=VERIFIER
   (no client_secret needed)

5. OpenIAM → App:
   { "access_token": "...", "id_token": "...", "expires_in": 3600 }
```

{% endcode %}

### Client credentials flow

Best for: service-to-service API calls (no user involved).

```
POST /idp/oauth2/token
Authorization: Basic base64(client_id:client_secret)

grant_type=client_credentials&scope=api.read api.write
```

**Response:**

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "api.read api.write"
}
```

{% hint style="info" %}
No `id_token` or `refresh_token` is issued for this grant.
{% endhint %}

### Refresh token flow

Best for: obtaining a new access token without user re-authentication. Requires **Use Refresh Token** to be enabled on the client.

```powerquery
POST /idp/oauth2/token
Authorization: Basic base64(client_id:client_secret)

grant_type=refresh_token&refresh_token=8xLOxBtZp8
```

**Response:**

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "new-refresh-token"
}
```

### Implicit flow (Legacy)

{% hint style="danger" %}
**Not recommended.** Use Authorization Code + PKCE instead. Kept for backward compatibility only.
{% endhint %}

```
GET /idp/oauth2/authorize
  ?response_type=token
  &client_id=...
  &redirect_uri=...
  &scope=openid profile
  &state=...
```

Tokens are returned directly in the redirect fragment (URL hash), never in a back-channel request.

### Hybrid flow

Returns both a code and a token (or id\_token) in the authorization response, allowing the front-end to get an id\_token immediately while the back-end exchanges the code for an access token.

```
GET /idp/oauth2/authorize
  ?response_type=code id_token
  &client_id=...
  &redirect_uri=...
  &scope=openid profile
  &state=...
  &nonce=...
```

**Redirect:**

```
https://app.example.com/callback
  ?code=AUTH_CODE
  &id_token=eyJhbGciOiJSUzI1NiJ9...
  &state=...
```

## ID Token (OIDC) claims

The ID token is a signed JWT. Standard claims:

<table><thead><tr><th width="131.33331298828125">Claim</th><th>Description</th></tr></thead><tbody><tr><td><code>iss</code></td><td>Issuer: <code>https://{host}/idp/oauth2/{jwtIssue}</code></td></tr><tr><td><code>sub</code></td><td>Subject: user's internal ID</td></tr><tr><td><code>aud</code></td><td>Audience: <code>client_id</code></td></tr><tr><td><code>exp</code></td><td>Expiry (Unix timestamp)</td></tr><tr><td><code>iat</code></td><td>Issued-at (Unix timestamp)</td></tr><tr><td><code>nonce</code></td><td>Echoed nonce (replay protection)</td></tr><tr><td><code>name</code></td><td>Full name (if <code>profile</code> scope granted)</td></tr><tr><td><code>email</code></td><td>Email address (if <code>email</code> scope granted)</td></tr></tbody></table>

Verify signature using the public key from the [JWKS endpoint](#jwks-endpoint).

## Client authentication methods

Summary for developers:

| Method                                                   | Token request header/body                 | Admin setting                                         |
| -------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------- |
| `client_secret_basic`                                    | `Authorization: Basic base64(id:secret)`  | Auth Type: `BASIC`                                    |
| `client_secret_post`                                     | `client_id=...&client_secret=...` in body | Auth Type: `POST`                                     |
| `private_key_jwt`                                        | `client_assertion=<signed-JWT>` in body   | Auth Type: `JWT`                                      |
| `urn:ietf:params:oauth:grant-type:saml2-bearer`          | SAML assertion in body                    | Auth Type: `ASSERTION`, Assertion Type: `SAML_BEARER` |
| `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` | JWT assertion in body                     | Auth Type: `ASSERTION`, Assertion Type: `JWT_BEARER`  |

## Field reference

Complete list of all configurable fields on an OAuth provider:

<table><thead><tr><th width="222">Field</th><th width="121.6666259765625">Type</th><th width="103.33331298828125">Default</th><th>Description</th></tr></thead><tbody><tr><td><code>clientId</code></td><td>UUID</td><td>auto</td><td>Read-only. Use as <code>client_id</code> in requests.</td></tr><tr><td><code>clientSecret</code></td><td>String</td><td>auto</td><td>Read-only. Shown after save.</td></tr><tr><td><code>jwtIssue</code></td><td>String</td><td>—</td><td>Short ID used to build issuer URL. Unique per provider.</td></tr><tr><td><code>grandFlow</code></td><td>Enum</td><td>—</td><td>Grant type(s): <code>AUTHORIZATION_CODE</code>, <code>CLIENT_CREDENTIALS</code>, <code>REFRESH_TOKEN</code>, <code>IMPLICIT</code>, <code>HYBRID</code></td></tr><tr><td><code>clientAuthType</code></td><td>Enum</td><td><code>BASIC</code></td><td>Client authentication method: <code>BASIC</code>, <code>POST</code>, <code>JWT</code>, <code>ASSERTION</code>, <code>DEVICE</code></td></tr><tr><td><code>clientAssertionType</code></td><td>Enum</td><td>—</td><td><code>SAML_BEARER</code> or <code>JWT_BEARER</code> (when Auth Type is <code>ASSERTION</code>)</td></tr><tr><td><code>jwtAlgorithm</code></td><td>Enum</td><td><code>RS256</code></td><td>Token signing algorithm: <code>RS256</code>, <code>HS256</code>, <code>ES256</code>, etc.</td></tr><tr><td><code>clientJWTValidationURL</code></td><td>URL</td><td>—</td><td>JWKS endpoint to validate client JWT assertions</td></tr><tr><td><code>clientJWTValidationKey</code></td><td>String</td><td>—</td><td>HMAC key for client JWT validation (HS256)</td></tr><tr><td><code>clientScopes</code></td><td>List</td><td>—</td><td>Resource IDs representing the scopes the client may request</td></tr><tr><td><code>redirectURLs</code></td><td>List</td><td>—</td><td>Allowed redirect URIs (exact match)</td></tr><tr><td><code>tokenExpiration</code></td><td>Integer</td><td>—</td><td>Access token TTL in seconds</td></tr><tr><td><code>maxActiveSessionTime</code></td><td>Integer</td><td>—</td><td>Max authenticated session length in seconds</td></tr><tr><td><code>useRefreshToken</code></td><td>Boolean</td><td>false</td><td>Enable refresh token grant</td></tr><tr><td><code>mutliActiveTokenAllowed</code></td><td>Boolean</td><td>false</td><td>Allow more than one active token per user</td></tr><tr><td><code>skipScopesDialog</code></td><td>Boolean</td><td>false</td><td>Auto-approve scopes; suppress user consent screen</td></tr><tr><td><code>protectedBy2FA</code></td><td>Boolean</td><td>false</td><td>Require 2FA before issuing tokens</td></tr><tr><td><code>publicApplicationKey</code></td><td>String</td><td>—</td><td>Stable key for public clients that cannot store a secret</td></tr><tr><td><code>sendIdTokenAsAccessToken</code></td><td>Boolean</td><td>false</td><td>Return the ID token value as the access token (non-standard)</td></tr></tbody></table>

## Notes and known issues

**OIDC role entitlements — required system setting:** For OIDC role entitlements to work correctly, go to **Administration → System configuration → System** tab and enable **Is OAuth client Authorization Disabled (back compatibility for cases when all OAuth clients were available for any users)**. If this is not enabled, users without explicit entitlements to the OAuth authentication provider will receive an `insufficient_rights` error at login.

**HMAC signing algorithms:** When using HMAC to sign JWTs, OpenIAM does not use a public/private key pair — HMAC relies on a shared secret key, so the provider configuration will not contain a key field.

**JWT validation error:** If the logs show:

{% code overflow="wrap" %}

```
JWT: The JWT returned by the token endpoint could not be validated against the retrieved JSON Web Key Set.
```

{% endcode %}

Switch the signing algorithm to **RSASSA-PKCS-v1\_5** with **SHA-512** to resolve the issue.


---

# 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-beta.openiam.com/federation/oidc-and-oauth-integration.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.
