Skip to content

Implement token exchange from OCM#57234

Open
enriquepablo wants to merge 12 commits into
nextcloud:masterfrom
enriquepablo:master
Open

Implement token exchange from OCM#57234
enriquepablo wants to merge 12 commits into
nextcloud:masterfrom
enriquepablo:master

Conversation

@enriquepablo
Copy link
Copy Markdown

@enriquepablo enriquepablo commented Dec 23, 2025

See #57152 #57166

Summary

This PR implements the token exchange flow from OCM, allowing Nextcloud to use bearer auth with short lived tokens. This opens up interoperability with OpenCloud/ownCloud OCIS and the possibility to implement webapp shares in the future, which requires this.

Discussion

This is a preliminary PR for discussion. If this goes through there are some things missing with which we'll be grateful to get some guidance:

  • docs and tests
  • keeping retrieved access tokens in the db
  • removing tokens when removing shares

There is also the question that for access tokens, we are keeping a reference to the corresponding refresh token in the uid field of the access token db record.

Prerequisite

This needs nextcloud/3rdparty#2413 before merging

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 7, 2026

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@enriquepablo
Copy link
Copy Markdown
Author

Disclaimer: Some of the code in this PR (mainly regarding the tests) was generated by Claude Opus 4.5. I have provided it with very specific prompts, and thoroughly reviewed the output.

@mickenordin mickenordin force-pushed the master branch 2 times, most recently from 4bd40db to 405de22 Compare May 5, 2026 13:02
@provokateurin provokateurin removed their request for review May 6, 2026 07:01
@mickenordin mickenordin requested a review from provokateurin as a code owner May 6, 2026 07:51
mickenordin added a commit to enriquepablo/server that referenced this pull request May 6, 2026
Combines the rebased kano-dual-stack-rfc-9421-http-sig PR (RFC 9421
HTTP signature support, OCM Ed25519 keys, JWKS endpoint, occ key
management) with enriquepablo's OCM token-exchange and JWT access
tokens. The exchange-token flow lives on top of the new RFC 9421
signing path (see the follow-up federatedfilesharing fix).

# Conflicts:
#	lib/private/OCM/OCMDiscoveryService.php
@mickenordin mickenordin force-pushed the master branch 4 times, most recently from 28e946f to 23b9d24 Compare May 7, 2026 09:23
Copy link
Copy Markdown
Contributor

@susnux susnux left a comment

Choose a reason for hiding this comment

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

IIRC OCM is federatedfilessharing and federation so better implement it there and use proper manager / abstraction rather than span the implementation across four different apps.

Not sure how to review all of the core things, this all affects security related parts of the code. So it would be much better to split the PR into multiple minimal PRs that can be properly reviewed for security rather than one large PR 👀

Comment thread lib/private/User/Session.php Outdated

$this->manager->emit('\OC\User', 'preLogin', [$dbToken->getLoginName(), $password]);

// See line 173 in this module, needed for completeLogin
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not really helpful the code will change in the future, better directly add a comment why this is needed rather than link to some line that will change anyways in the future.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This sounds not like this should be implemented in files_sharing but rather federatedfilessharing app.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks like it should belong to the federation app itself not the dav app.

@enriquepablo
Copy link
Copy Markdown
Author

@susnux perhaps if you can find the time, we can schedule a little while to sit together and go through the code, and decide what is the best way to move this forward.

@provokateurin
Copy link
Copy Markdown
Member

provokateurin commented May 11, 2026

Hey @enriquepablo I would like to review this PR, but in the current shape it is a bit hard. Would it be possible for you to squash a few commits into more self-contained/atomic commits, such that I can review commit-by-commit? This would make it way easier than reviewing the whole PR at once.

@provokateurin
Copy link
Copy Markdown
Member

Also a guide review in a video call would be awesome, like you already suggested!

@enriquepablo
Copy link
Copy Markdown
Author

@provokateurin I will work on the commits as suggested, hopefully tomorrow, I'll ping you back here once I'm done and then we can schedule a video call.

Thank you and @susnux !

@mickenordin
Copy link
Copy Markdown
Contributor

@provokateurin I will work on the commits as suggested, hopefully tomorrow, I'll ping you back here once I'm done and then we can schedule a video call.

Thank you and @susnux !

I will be happy to join a call as well!

@mickenordin
Copy link
Copy Markdown
Contributor

Hey @enriquepablo I would like to review this PR, but in the current shape it is a bit hard. Would it be possible for you to squash a few commits into more self-contained/atomic commits, such that I can review commit-by-commit? This would make it way easier than reviewing the whole PR at once.

@provokateurin Maybe you would like to review this one too: #60136

They go a little bit together... Carl has already approved, but we need one more 🥺

@enriquepablo
Copy link
Copy Markdown
Author

@provokateurin @susnux @mickenordin I have squashed the commits down to 12. The 2nd commit is a bit large, I was descending into an unmanageable conflict hell trying to regroup the commits with more granularity. So I think we are ready for the call - I would discuss there also the code relocations suggested by susnux.
There are some CI failures due to the dependency of this PR on #60136.

enriquepablo and others added 12 commits May 15, 2026 09:42
Allow Bearer token auth for WebDAV requests.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
End-to-end OCM bearer-auth flow:

- a token endpoint (apps/dav) that exchanges a long-lived
  refresh token for a short-lived JWT access token, with
  form-urlencoded payloads, exposed via OCM discovery
- a Sabre Bearer-auth backend that validates incoming
  WebDAV requests carrying an OCM access token
- `IUserSession::doTryTokenLogin($token)` to authenticate
  by token without an `IRequest`
- federated share provider issues permanent refresh tokens
  to remotes on share creation; signs POSTs to the remote
  token endpoint; honours the `must-exchange-token` capability
- files_sharing client exchanges refresh tokens for access
  tokens when mounting a remote share configured for
  bearer auth, and uses the access token as the WebDAV
  Bearer header
- cloud_federation_api adapted to the multi-protocol share
  creation format from the latest OCM draft
- federated WebDAV client adapted to Guzzle 7

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Introduce `OcmTokenMap` mapping an `oc_authtoken` id to the
refresh token it was issued for. Migration adds the
`oc_ocm_token_map` table. Token-exchange responses are
validated before being persisted.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
By using a JWT that the receiver can verify against a public key, we
make it easy for third party services to validate the token
independently. This is relevant for example in the context of webapp
shares that may defer to a separate service to deliver the actual
webapp.

NOTE: This requires nextcloud/3rdparty#2413 to
be merged before this.

Signed-off-by: Micke Nordin <kano@sunet.se>
Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Add a refresh-token column to `federated_reshares` so refresh
tokens issued to remotes survive across share-creation
requests. The migration is backwards-compatible with shares
created before the upgrade.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Add `access_token` and `access_token_expires` columns to
`share_external`. The expires timestamp deduplicates
concurrent refresh requests across processes.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
When a WebDAV request fails with 401 and the stored access
token is expired, attempt one transparent refresh against the
OCM token endpoint and retry. Limited to a single retry per
request to avoid loops when the refresh itself fails.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
CleanupExpiredOcmTokensJob periodically deletes expired
`oc_ocm_token_map` rows and their backing `oc_authtoken`
entries.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
When mounting a federated share created on an instance that
predates the bearer-auth upgrade, fall back to password-based
authentication instead of attempting token exchange.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Bundle of tooling-level fixes accumulated during the PR:
psalm fixes across affected files, code-style fixes, openapi
spec regeneration, sqlite integration test fixes, missing
`Override` attributes, and composer autoloader regeneration
for new migrations and entities.

Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants