Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save OIDC tokens to OpenProject database #16940

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

ba1ash
Copy link
Member

@ba1ash ba1ash commented Oct 11, 2024

Ticket

https://community.openproject.org/wp/58365

What are you trying to accomplish?

Storing access and refresh tokens for users that initiate their session through OIDC, so that we can later use them to obtain tokens for accessing third party resources, such as Nextcloud.

What approach did you choose and why?

Storing the access and refresh token on a new table that is intended to store all access tokens for the current session's user, including the ones later obtained through Token Exchange. This provides a clear place to look for credentials and additionally keeps the back-channel logout logic separated from token storage (as opposed to storing the tokens on the user_session_link.

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

@ba1ash ba1ash self-assigned this Oct 11, 2024
@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch from 9a35b87 to 67f649f Compare December 10, 2024 15:55
@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch 2 times, most recently from deac74f to 658fbe9 Compare December 12, 2024 11:55
@NobodysNightmare
Copy link
Contributor

An alternative approach to storing the tokens on the UserSessionLinks table might be to associate another table to the session that specifically stores tokens only.

In general, we are not done yet: One next step will be to write code that can take a valid access token stored here and exchange it through OAuth 2.0 Token Exchange for a token that can be used to access a third party service. Eventually there will be multiple third party services, that we want to exchange tokens for and then we want to reuse those tokens until they expire.

This means we could store all of those tokens in the same table (e.g. with an additional audience column) along with our own tokens. I'd prefer this approach for storing all tokens the same way. On the other hand, some special logic will be required, since for token exchange we will always want to use our own tokens to perform the exchange.

@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch from 658fbe9 to 9f8fff8 Compare December 12, 2024 12:14
@NobodysNightmare
Copy link
Contributor

I did what I suggested above. This PR now contains both, the original version (check the diff of commit 1) and the one suggested by me (check the diff of the total PR). My personal prefererence is the current version of this PR.

@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch 2 times, most recently from 03cb4fb to 14c5ed9 Compare December 13, 2024 07:42
@NobodysNightmare NobodysNightmare marked this pull request as ready for review December 13, 2024 07:57
@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch 3 times, most recently from b59ad82 to 201f5cd Compare December 13, 2024 08:27
@NobodysNightmare NobodysNightmare requested a review from a team December 13, 2024 09:08
@NobodysNightmare NobodysNightmare changed the title Save OIDC tokens to OpenProject database. Save OIDC tokens to OpenProject database Dec 13, 2024
@NobodysNightmare
Copy link
Contributor

NobodysNightmare commented Dec 13, 2024

One other thought that crossed my mind today and was then repeated by @wielinde:

Should we store the tokens on the session or on the user?

Arguments against session:

  • We'd have to push the correct session into all storage-services, instead of pushing the user there
  • A session is harder to obtain than a user (imagine calling a service from a background worker)

The argument for session:

  • Right now we obtain the tokens in the context of an SSO session, so they may be affected by IDP logout
    • thus it's not safe to use tokens from arbitrary sessions
    • but maybe we can obtain a token for long-term offline use instead? (that could be bound to user safely)

@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch from 201f5cd to 1130ff2 Compare December 13, 2024 14:36
@NobodysNightmare
Copy link
Contributor

NobodysNightmare commented Dec 17, 2024

but maybe we can obtain a token for long-term offline use instead? (that could be bound to user safely)

For Keycloak in default config, this is possible by adding the offline_access scope to the list of requested scopes. This will make sure that the lifetime of refresh tokens is not limited and they are not revoked after logout anymore.

So we could attach tokens to the user instead of the session, if we can ensure that they are not expiring. I see elevated potential for misconfiguration here, but on the other hand it still sounds like the cleanest available solution to me.

edit: However, seeing that offline_access is a standardized scope name, we could make sure that there is a properly configured OIDC provider available...

Storing tokens in the database to have them available for
requests to third parties (e.g. Nextcloud) later.

The OIDC session is now marked as optional, since the
session link is also used to store access and refresh tokens
associated with the session. Those tokens might be present,
even if the session id (which belongs to the optional
OIDC Back-Channel Logout specification) is missing.
This commit provides an alternative implementation
for storing tokens compared to the parent commit.

The idea is that we will not only need to store access
and refresh tokens obtained via Omniauth, but also the ones
to access third party services that will most likely be obtained
through OAuth 2.0 Token Exchange. This structure allows to store
all of these tokens in the same data model, while keeping the
implementation separated from the back-channel logout logic.
Doing so hopefully simplifies token handling a bit.
It's now not required to pass specific sessions into services
as long as a user is passed.
This theoretically also enables us to act in the name of a user from
a background job, though we have no specific plans for that yet.

A possible downside is, that we now require being handed long-term tokens
(i.e. tokens with offline_access scope). On the other hand, we'd have had
to consider keeping our tokens fresh for the previous implementation, which
we also didn't solve yet.
@NobodysNightmare NobodysNightmare force-pushed the save-oidc-tokens-to-open-project-database branch from 1ab8a1c to 06f4d7d Compare December 18, 2024 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants