Support for OIDC Client credential
Context
In our application, we use the Authorization Code Flow with PKCE, which is well-suited for frontend clients that require user authentication. This flow enables secure token exchange on behalf of the end user after an interactive login through the Identity Provider. It differs from flows like Client Credentials, which are intended for system-to-system communication without user involvement.
Client Credentials Flow – Overview
The Client Credentials Flow is one of the standard OAuth 2.0 flows supported by OpenID Connect (OIDC). Unlike the Authorization Code Flow, which is designed for user-centric interactions, the Client Credentials Flow is used when there is no end-user involved. It’s typically used for machine-to-machine (M2M) communication where a backend service needs to authenticate itself to another backend service (e.g., an API).
Use the Client Credentials Flow when:
A backend or service account (not a user) needs to access a protected resource.
There is no interactive login.
The client is fully trusted (e.g., server-side applications, internal microservices).
How It Works
The client (e.g., an API consumer) authenticates directly with the authorization server (IdP).
It sends a POST request to the token endpoint, including:
grant_type=client_credentials
client_id and client_secret
(Optional) scope
The IdP validates the credentials.
If valid, it returns an access token (typically a JWT).
The client uses this token in the Authorization header to access protected resources.
How can be configured in our system
To support Client Credentials Flow, our system allows the registration of Resource Servers through the admin UI. A Resource Server represents a protected backend API that will validate access tokens issued to trusted clients.
The resource server list is present under IdP OIDC and has a specific tab for it

From that tab we can view all the resource server created and we can add from the right side menu a new one.

Creating or updating a resource server we will face this modal where is very similar with the OIDC application creation that we already know. From this modal we need to set a client id, the secret, scopes and subject type that the client will need to match.
Creation of the resource server will reflect by adding in the shibboleth/shibboleth/oidc-veridium-clients.json in a new list for resource server. From this file will be written automatically in shibboleth/relying-party.xml as
<bean c:relyingPartyIds="resource2" id="OIDC_CLIENT_resource2" parent="RelyingPartyByName" >
<property name="profileConfigurations">
<list>
<bean p:accessTokenLifetime="PT10M" p:accessTokenType="JWT" p:encryptionOptional="true" p:resolveAttributes="true" parent="OAUTH2.TokenAudience"/>
</list>
</property>
</bean>
and in shibboleth/oidc/oidc-clients.json as follow format:
{
"client_id": "resource2",
"client_secret": "secret",
"grant_types": [],
"scope": "openid profile email",
"subject_type": "public",
"redirect_uris": [],
"jwks_uri": ""
}
Once the resource server is created, we can now attach from a OIDC client an audience to it as following:

When creating or editing a OIDC application we have a new grant types named client_credentials that is specific for this flow. When we are adding this as grant types the audience section will appear and now we can select a resource for that we intend to do audience for.
Having this setup, we can now request a access token. We can check this by trigger a postman request (having header: Content-Type → application/x-www-form-urlencoded):
https://{{idp_hostname}}/idp/profile/oidc/token?grant_type=client_credentials&scope=profile&client_id=veridium_client&client_secret=secret&audience=resource2

From this we will get a access_token
JWT that can be verified in https://www.jwt.io/ for example and decode the code. In the decoded section we can spot claims that we are looking for
{
"sub": "veridium_client",
"aud": "resource1",
"auth_time": 1753952875,
"scope": "profile",
"iss": "https://cbodnar.veridium-dev.com:11443",
"for_op": "AAdzZWNyZXQxSV0y9b-3IILi0i3PAK5-EaSdUhtKWJyXgPp0uTiAKIcatI62DkJSrQIraLiza4vwUv__9ll4sy4B4eXf3gehR0lttnpYdy3sK-L9vOrkFoOkaQ4nOmKLQgaXxJVTJ3kj19xEnrSHFyscbIm6",
"exp": 1753953475,
"iat": 1753952875,
"client_id": "veridium_client",
"jti": "_0c04da4db0fa2058d889203f53913d49",
"sid": "_b120bde843cf1251f2f728ea13b963cd"
}