Skip to content

feat: provision users from the userinfo endpoint (opaque bearer tokens) - #1564

Open
alex-yatsenko wants to merge 1 commit into
nextcloud:mainfrom
alex-yatsenko:feat/userinfo-provisioning
Open

alex-yatsenko wants to merge 1 commit into
nextcloud:mainfrom
alex-yatsenko:feat/userinfo-provisioning

Conversation

@alex-yatsenko

Copy link
Copy Markdown

Implements the TODO in UserInfoValidator::getProvisioningStrategy() — the one tracked in #1258, and related to #1255.

Why

UserInfoValidator validates opaque access tokens by calling the provider's userinfo endpoint, but it returned an empty string from getProvisioningStrategy(), and Backend skips provisioning entirely when the strategy is empty:

$provisioningStrategy = $validator->getProvisioningStrategy();
if ($provisioningStrategy) {
    $this->provisionUser($validator->getProvisioningStrategy(), $provider, $tokenUserId, $headerToken, $existingUser);
}

A self-encoded JWT carries its claims, so SelfEncodedTokenProvisioning can decode them. An opaque token carries nothing — the claims only exist behind userinfo. For providers that issue opaque tokens the account still gets created, but group membership and attribute sync never happen, and nothing is logged: the failure is completely silent.

What

  • OCA\UserOIDC\User\Provisioning\UserInfoProvisioning — counterpart of SelfEncodedTokenProvisioning, deliberately mirroring it and differing only in where the payload comes from (OIDCService::userinfo() instead of JWT::decode()). It reuses ProvisioningService::provisionUser(), so the group whitelist (groupWhitelistRegex) and all mapping settings keep applying exactly as before — it does not add a way around them.
  • UserInfoValidator::getProvisioningStrategy() now returns UserInfoProvisioning::class. If fetching userinfo fails at provisioning time it logs the error and returns null: the very same token was just validated against that endpoint in the validator, so a failure here is a transport failure, not an authorization one.
  • Unit tests for both paths (payload reaches ProvisioningService, endpoint failure is handled and does not provision).

Testing

  • php -l on all changed files.
  • Two new unit tests in tests/unit/User/Provisioning/UserInfoProvisioningTest.php.
  • Carried as a downstream patch (and running in production) since August 2026 on Nextcloud 34 with an IdP that issues opaque access tokens: groups and the display name arrive on the bearer path, and the whitelist filter keeps rejecting groups that are not in it.

We are happy to reshape this to whatever the maintainers prefer (e.g. sharing code with SelfEncodedTokenProvisioning, or wiring the strategy differently) — the point is that the bearer path should provision like the interactive one does.

Refs #1258
Refs #1255

UserInfoValidator returned an empty string from getProvisioningStrategy()
with a TODO, so users authenticated with an **opaque** bearer token were
never provisioned: the token carries no claims, and nothing fetched them
from the provider's userinfo endpoint either. Providers that issue opaque
access tokens (instead of self-encoded JWTs) therefore got no group
membership and no attribute sync on the bearer path.

Add UserInfoProvisioning, the counterpart of SelfEncodedTokenProvisioning:
it takes the payload from the provider's userinfo endpoint instead of
decoding it out of the token. UserInfoValidator now names that strategy,
so the existing "bearer provisioning" setting works for opaque tokens too.

The class deliberately mirrors SelfEncodedTokenProvisioning and reuses
ProvisioningService, so the group whitelist filter keeps applying exactly
as before.

Refs nextcloud#1258
Refs nextcloud#1255

Signed-off-by: Александр Яценко <286242565+alex-yatsenko@users.noreply.github.com>
@alex-yatsenko
alex-yatsenko force-pushed the feat/userinfo-provisioning branch from f8259a5 to 6be4327 Compare October 7, 2026 14:12
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