8000 grant-type:jwt-bearer similar to client credentials but with proper support for URL client_id by elf-pavlik · Pull Request #2053 · CommunitySolidServer/CommunitySolidServer · GitHub
[go: up one dir, main page]

Skip to content

Conversation

elf-pavlik
Copy link
Contributor
@elf-pavlik elf-pavlik commented Aug 17, 2025

Warning

very early and rough draft, practically proof of concept

supersedes #2041

TODO

  • copy boilerplate from client credentials
  • custom oidc-provider grant handler
    • does it make sense to check if assertion exists in store and if it does still vefify the JWT?
  • rely on ClientIDAdapter unless new adapter is needed
  • check if assertion was revoked
  • restrict to a single assertion per client id per account
    • should be per WebID?
    • would it be needed to have multiple assertions for the same client per WebID?
  • payload from JwtAssertionsDetailsHandler
  • error codes, including custom oidc-provider grant handler
  • try to minimize duplication with client credentials
  • scan for inline TODO
  • Tests

CSS JWT assertions authn

CSS supports client credentials which use a combintation of:

client_id
client_secret

and internally has those credentials associated with webid of the user which created them.
Current implementation doesn't support use of URL as client_id, I made a PR with a naive quick fix. It would be very limited since with multiple tenants only one could register a client with any given URL.

RFC7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants defines grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer which can be used together with an assertion encoded as JWT.

This allows any user to issue a distinct assertion for the client with a given URL. And when token is requested based on that assertion OP will know which WebID to use as webid claim in a token.

assertion

The assertion is issued by the OP as signed JWT
An example from Identity.test.ts

const grantType = 'urn:ietf:params:oauth:grant-type:jwt-bearer';

const res = await fetch(tokenUrl, {
  method: 'POST',
  headers: {
    'content-type': APPLICATION_X_WWW_FORM_URLENCODED,
    dpop: dpopHeader,
  },
  body: `grant_type=${grantType}&assertion=${assertion}&client_id=${clientId}&scope=webid`,
});

The assertion already includes client_id in client claim. It is used due to how oidc-provider package work. It might be possible to remove it in the future.

current draft

When verified only the signature is checked so it doesn't need to be stored by the OP except for revocations (currently not checked)
An example logged from integration test in Identity.test.ts

eyJhbGciOiJFUzI1NiJ9.eyJjbGllbnQiOiJodHRwOi8vbG9jYWxob3N0OjYwMDkvY2xpZW50LWlkIiwiYWdlbnQiOiJodHRwOi8vbG9jYWxob3N0OjYwMDkvdGVzdC9wcm9maWxlL2NhcmQjbWUiLCJpYXQiOjE3NTUzODIzNzQ5MDAsImp0aSI6IjdiNjU5ODhlLTIzNDQtNDM2OC1hN2FiLTI1MDNjNGFiOGEzNCJ9.pB1oBT0YLnHbD_qu4VlpGy1WSgjgPs1fXOYIruu9YMH4bSdlJIFkrjOH7oz8grOAajXxhNiU0g_K3BREh4orQg
{
  "client": "http://localhost:6009/client-id",
  "agent": "http://localhost:6009/test/profile/card#me",
  "iat": 1755382374900,
  "jti": "7b65988e-2344-4368-a7ab-2503c4ab8a34"
}

planned

Sender constrained using client's public key 👇

client authentication

current draft

token_endpoint_auth_method: 'none'

Effectivelly the assertion acts as client secret (bearer)

planned

token_endpoint_auth_method: 'private_key_jwt'

RFC7523 also defines client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer which has a separate JWT client_assertion which is created and signed by the client.

It would discover keys based on Client ID document.

Note

This would be in lines of authenticating client based on redirect_uris in ClientID Document

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.

1 participant
0