Skip to content

feat: add client credentials as a MUST#245

Open
jeswr wants to merge 1 commit intomainfrom
feat/client-credentials-grant
Open

feat: add client credentials as a MUST#245
jeswr wants to merge 1 commit intomainfrom
feat/client-credentials-grant

Conversation

@jeswr
Copy link
Member

@jeswr jeswr commented Feb 15, 2026

This PR makes client credentials a MUST as part of the solid-oidc specification. The CSS and ESS both currently implement client credentials. There respective documentation can be found as follows:

Questions:

  • How long does this need to remain open after editor approval to be merged?
  • What is the versioning policy here / how should the version be changed.

cc @acoburn @joachimvh @elf-pavlik @thhck @uvdsl @dmitrizagidulin

Copilot AI review requested due to automatic review settings February 15, 2026 20:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds mandatory support for the OAuth 2.0 Client Credentials Grant to the Solid-OIDC specification to enable non-interactive authentication for scripts, automated agents, and server-to-server communication. Both major implementations (Community Solid Server and Enterprise Solid Server) already support this feature.

Changes:

  • Added Client Credentials Grant as a MUST requirement for OpenID Providers
  • Updated Core Concepts section to clarify support for both interactive (Authorization Code + PKCE) and non-interactive (Client Credentials) authentication flows
  • Updated discovery requirements to mandate advertising client_credentials in grant_types_supported metadata
  • Updated Token Instantiation section to explicitly cover both Authorization Code Grant and Client Credentials Grant

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

with `grant_type=client_credentials` and the `webid` scope.

The OP MUST validate the `client_id` and `client_secret`, and if valid, MUST return
a DPoP-bound Access Token. The Client MUST include a valid DPoP proof [[!DPOP]]
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an inconsistency between this statement and line 319 in the Token Instantiation section. This line states the OP must return "a DPoP-bound Access Token" for the Client Credentials Grant, but line 319 (which explicitly covers both Authorization Code Grant and Client Credentials Grant per line 316) states "the OP MUST return a DPoP-bound OIDC ID Token". These two statements need to be aligned. Based on the structure of the specification and line 319's scope covering both grant types, this should likely say "a DPoP-bound OIDC ID Token" instead of "Access Token".

Suggested change
a DPoP-bound Access Token. The Client MUST include a valid DPoP proof [[!DPOP]]
a DPoP-bound OIDC ID Token. The Client MUST include a valid DPoP proof [[!DPOP]]

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acoburn could you please guide on language

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ID Tokens are only meaningful terms in the context of OIDC, in the context of the client credentials grant of OAuth2 one should use "Access Tokens" as the proper terminology.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also hints at some long-standing challenges with Solid-OIDC. In Solid-OIDC, an OpenID provider generates ID tokens for use with Solid Clients and Servers, but these ID tokens are used as Access Tokens. Arguably, this is incorrect.

Furthermore, DPoP is defined as a mechanism to protect Access Tokens. Using DPoP with ID Tokens is not defined. Insofar as Solid-OIDC is about defining ID Tokens, it is incorrect to use DPoP, and insofar as Solid-OIDC is a about defining Access Tokens, it is correct to use DPoP but incorrect to use OpenID Connect.

Comment on lines +301 to +304
When using the Client Credentials Grant, the Client authenticates with the OP using a
`client_id` and `client_secret` pair previously obtained through client registration
(either static or dynamic). The Client sends a token request to the OP's token endpoint
with `grant_type=client_credentials` and the `webid` scope.
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential contradiction with the statement at lines 121-122 which says "client registration, whether dynamic, or static, is entirely optional." The Client Credentials Grant inherently requires client registration to obtain the client_id and client_secret pair. Consider either: (1) clarifying at lines 121-122 that client registration is optional for some flows but required for Client Credentials Grant, or (2) adding a note in the Client Credentials section that explicitly acknowledges this requirement represents an exception to the general optional nature of client registration mentioned in the Core Concepts section.

Suggested change
When using the Client Credentials Grant, the Client authenticates with the OP using a
`client_id` and `client_secret` pair previously obtained through client registration
(either static or dynamic). The Client sends a token request to the OP's token endpoint
with `grant_type=client_credentials` and the `webid` scope.
When using the Client Credentials Grant, the Client MUST be registered with the OP and
authenticate using a `client_id` and `client_secret` pair previously obtained through
client registration (either static or dynamic). This requirement is an exception to the
general statement in the Core Concepts section that client registration is optional. The
Client sends a token request to the OP's token endpoint with `grant_type=client_credentials`
and the `webid` scope.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acoburn @joachimvh can you confirm this is accurate with your implementations?

Comment on lines +426 to +428
Additionally, the OP MUST include `client_credentials` in its `grant_types_supported`
metadata property to indicate support for non-interactive authentication
via the Client Credentials Grant (see [[#client-credentials]]).
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requirement duplicates the one already stated in the Client Credentials Grant section (lines 310-311). The same requirement appears twice: once in the Client Credentials Grant section and once here in the Conformance Discovery section. Consider removing the duplication by keeping only one of these statements, or if both are intentional, clarify why the requirement is repeated. Typically, the discovery/conformance section would be the natural place for such metadata requirements, making lines 310-311 potentially redundant.

Suggested change
Additionally, the OP MUST include `client_credentials` in its `grant_types_supported`
metadata property to indicate support for non-interactive authentication
via the Client Credentials Grant (see [[#client-credentials]]).
Additionally, an OP that supports non-interactive authentication
via the Client Credentials Grant (see [[#client-credentials]]) indicates this support by including
`client_credentials` in its `grant_types_supported` metadata property.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only to implement this change if we go with MAY wording over MUST.

@elf-pavlik
Copy link
Member

@laurensdeb could you please also review it?
I recall you mentioning come certification issues before writing https://github.com/solid/solid-oidc/blob/main/alternative-flows.md

I think we should add a note about limitation around Client IDs that are URLs, I have PR to CSS that allows it

Still only one user can use client with given Client ID URL. Since it is often used for scripts that aren't multi tenant it migth be fine. In case of multi tenant clients, I also made an early draft that uses another flow/grant

@acoburn does ESS support client credentials with Client ID URL?


# Client Credentials Grant # {#client-credentials}

OpenID Providers MUST support the OAuth 2.0 Client Credentials Grant [[!RFC6749]] (Section 4.4)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally OpenID Connect does not define a client credentials grant mechanism for OPs. It would be more correct to refer to Authorization Servers rather than OpenID Providers.

communication.

When using the Client Credentials Grant, the Client authenticates with the OP using a
`client_id` and `client_secret` pair previously obtained through client registration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid making any assumptions on which assertions a client provides to the AS for the client credentials grant. Quite a few Authorization Services rely on public keypairs to authenticate clients, cfr. RFC7523, for example this is the case in MS Entra

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(either static or dynamic). The Client sends a token request to the OP's token endpoint
with `grant_type=client_credentials` and the `webid` scope.

The OP MUST validate the `client_id` and `client_secret`, and if valid, MUST return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above, I would not normatively require the use of a client_secret.

with the token request.

The OP MUST advertise `client_credentials` in its `grant_types_supported`
metadata property in its OpenID Connect Discovery 1.0 [[!OIDC-DISCOVERY]] document.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the grant_types_supported metadata field of OpenID connect is optional. I don't think it makes sense to introduce a MUST therefore, in particular given that this is an OAuth grant type.

Copy link
Contributor

@laurensdeb laurensdeb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally don't think it makes a lot of sense to introduce client_credentials grant as part of the Solid-OIDC specification. The general remarks I made previously on supporting additional grant types are still quite relevant here.

The main issue I see is that OIDC builds on top of the OAuth2 protocol, therefore it would make more sense to do a thorough refactoring here and extract aspects specific to OAuth in a Solid-OAuth specification, and have the Solid-OIDC specification extend that for the authorization_code grant.

The introduction of a Solid-OAuth specification would have the benefit of being able to e.g. drop the requirement of DPoP for client_credentials grant, as it makes very little sense for a confidential client (which would typically be the case for a client_credentials based flow).

@elf-pavlik
Copy link
Member

elf-pavlik commented Feb 16, 2026

The introduction of a Solid-OAuth specification would have the benefit of being able to e.g. drop the requirement of DPoP for client_credentials grant, as it makes very little sense for a confidential client (which would typically be the case for a client_credentials based flow).

@laurensdeb could you please clarify? Even with confidential clients, when aud is not restricted to a specific AS, DPoP is needed so the AS which receives the id token (authentication credential) can not reuse that token/credential elsewhere.

Copy link
Member

@acoburn acoburn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than focus on particular line changes in this PR, there are some high level issues that would be good to clarify.

  1. Use cases: this change seems to be motivated by a desire to support scripts and bots. As such, there are several different ways to address this, and client_credentials is just one approach. There is also the use of refresh tokens (already compatible with Solid-OIDC) and other mechanisms such as the jwt-bearer grant type from RFC 7523. Client Credentials (as typically implemented with a client_id/client_secret pair) has some notable security concerns (e.g. relying on a shared secret rather than on public key cryptography). Adding a hard requirement on this for Solid-OIDC may be misguided.
  2. OAuth vs OpenID Connect: Solid-OIDC is clearly a mechanism to integrate Solid with OpenID Connect. As such, Solid-OIDC supports browser-based authentication flows (authorization_code flow), since that is the motivating use case for OpenID Connect. Adding a grant type from OAuth 2 is not the best fit for an OpenID Connect profile. Here, an authentication mechanism defined in a different specification (e.g., Solid-OAuth) may be a better approach
  3. Identity binding: While the Inrupt ESS platform currently supports client credential flows via its OpenID Connect broker, one challenge is that any client_credential grant needs a pre-existing identity binding. Typically, a client_id value is an opaque UUID and scoped to a particular OP. The only way to ensure that this client_id value is bound to a WebID identity is to do so at registration time. Note that, functionally, this is nearly identical to using a refresh token. And specifically, this does not address the case of authenticating autonomous bots.
  4. Alternatives: I would highly recommend considering alternatives, such as the use of Client Id Metadata documents, which largely derives from Solid-OIDC and adds features that are needed for autonomous bots, such as authentication.

@acoburn
Copy link
Member

acoburn commented Feb 16, 2026

The introduction of a Solid-OAuth specification would have the benefit of being able to e.g. drop the requirement of DPoP for client_credentials grant, as it makes very little sense for a confidential client (which would typically be the case for a client_credentials based flow).

@laurensdeb could you please clarify? Even with confidential clients, when aud is not restricted to a specific AS, DPoP is needed so the AS which receives the id token (authentication credential) can not reuse that token/credential elsewhere.

If there were some Solid-OAuth specification, I would highly recommend requiring an audience constraint via the aud claim. With that requirement in place, DPoP becomes largely unnecessary as a requirement. (Certain deployment scenarios may still wish to require DPoP for other reasons, but the motivating use case for DPoP was the concern about having a malicious Solid server replay a token at some other Solid server, and this would be addressed with audience constraints).

@elf-pavlik
Copy link
Member

In this sketch https://elf-pavlik.github.io/lws-auth/view/oidc/?dynamic=sequence
I don't use DPoP, instead there is a token exchange with both User AS and Resource AS to keep audiences set to specific parties.

@laurensdeb
Copy link
Contributor

@elf-pavlik As Aaron mentioned, in a more general Solid-OAuth scenario an audience constrained access token would make more sense than a sender constrained access token using DPoP. I agree that there still is a risk of a malicious RS or AS intercepting a token, so a mechanism still needs to be in place to constrain the token to a target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants