Skip to content

Implements OIDC RP-Initiated Logout#36724

Merged
wxiaoguang merged 11 commits intogo-gitea:mainfrom
krjakbrjak:VNI-oidc-logout
Mar 1, 2026
Merged

Implements OIDC RP-Initiated Logout#36724
wxiaoguang merged 11 commits intogo-gitea:mainfrom
krjakbrjak:VNI-oidc-logout

Conversation

@krjakbrjak
Copy link
Copy Markdown
Contributor

At logout time, if the user authenticated via OIDC, we look up the provider's end_session_endpoint (already discovered by Goth from the OIDC metadata) and redirect there with client_id and post_logout_redirect_uri. No database changes, no token storage.

Non-OIDC OAuth2 providers (GitHub, GitLab, etc.) are unaffected — they fall back to local-only logout.

Setup (IdP side)

Add Gitea's URL to the client's Valid post logout redirect URIs in your IdP config (e.g. https://gitea.example.com/).

Solves #14270
gitea-oidc-logout.webm

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 23, 2026
@github-actions github-actions bot added modifies/go Pull requests that update Go code modifies/frontend labels Feb 23, 2026
Nikita Vakula added 2 commits February 24, 2026 10:12
When logging out of Gitea, users authenticated via OpenID Connect are
now redirected to their identity provider's end_session_endpoint, ending
the IdP session as well. This prevents the common issue where logging
out of Gitea still leaves the IdP session active, causing automatic
re-authentication on the next login attempt.

Uses the `client_id` parameter per the RP-Initiated Logout spec rather
than storing `id_token_hint`, requiring no database changes. Non-OIDC
OAuth2 providers gracefully fall back to local-only logout.

Signed-off-by: Nikita Vakula <nikita.vakula@alpsalpine.com>
The fetch-redirect delegate rejects non-Gitea URLs, which blocks
OIDC logout redirects to the identity provider. Use direct navigation
for external URLs.

Signed-off-by: Nikita Vakula <nikita.vakula@alpsalpine.com>
@lunny
Copy link
Copy Markdown
Member

lunny commented Feb 24, 2026

It looks like this code may be duplicated from #30072.

@krjakbrjak
Copy link
Copy Markdown
Contributor Author

It looks like this code may be duplicated from #30072.

Thanks for the note @lunny ! I'm aware of #30072 but my implementation takes a deliberately lighter approach. #30072 uses id_token_hint, which requires a new database model (ExternalAuthToken), migrations, and session-level token tracking — that's why it's an XL-sized PR. My PR instead uses the client_id parameter (which the RP-Initiated Logout spec also supports), which means zero database changes, zero token storage, and much less changes. The code isn't derived from #30072 — the implementations share essentially no logic beyond what the OIDC spec itself requires. I needed something that works without db changes and is applicable on top of any gitea release. this is what I am using in a production so far, but thought it would be great to have it finally as a part of gitea. Is there anything I can do to help move this forward?

Copy link
Copy Markdown
Contributor

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 pull request implements OIDC RP-Initiated Logout functionality for Gitea, allowing users who authenticated via an OIDC provider to be properly logged out from both Gitea and the identity provider. The implementation discovers the provider's end_session_endpoint from the OIDC metadata and redirects to it with the appropriate parameters (client_id and post_logout_redirect_uri). Non-OIDC OAuth2 providers fall back to local-only logout, maintaining backward compatibility.

Changes:

  • Added frontend logic to handle external URL redirects for OIDC logout endpoints
  • Implemented backend function to retrieve OIDC end session endpoint from provider metadata
  • Integrated OIDC logout into the sign-out flow with fallback to local logout

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
web_src/js/features/common-fetch-action.ts Adds external URL detection and direct navigation to bypass same-site restriction for OIDC logout redirects
services/auth/source/oauth2/providers.go Implements GetOIDCEndSessionEndpoint to retrieve the OIDC end session endpoint from provider configuration
routers/web/auth/oauth.go Adds buildOIDCEndSessionURL to construct the OIDC logout URL with required parameters
routers/web/auth/auth.go Modifies SignOut to check for OIDC logout and redirect to end session endpoint before local logout

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

@github-actions github-actions bot added the modifies/templates This PR modifies the template files label Feb 27, 2026
@wxiaoguang wxiaoguang force-pushed the VNI-oidc-logout branch 3 times, most recently from 333fab9 to ceaa485 Compare February 27, 2026 09:04
@wxiaoguang
Copy link
Copy Markdown
Contributor

My PR instead uses the client_id parameter (which the RP-Initiated Logout spec also supports)

Can you add the spec reference as code comment?

@krjakbrjak
Copy link
Copy Markdown
Contributor Author

krjakbrjak commented Feb 27, 2026

@wxiaoguang Thanks for the refactoring! Could you share what was wrong with the original approach?

Also, one thing I noticed: if the user is OAuth2 but the provider is not OIDC (e.g. GitHub), buildOIDCEndSessionURL returns "", which overwrites the default. Should this be:

if ctx.Doer != nil && ctx.Doer.LoginType == auth.OAuth2 {
    if builtUrl := buildOIDCEndSessionURL(ctx, ctx.Doer); builtUrl != "" {
        redirectTo = builtUrl
    }
}

btw, switching from Post to Get requires some adjustments in the tests, currently TestSignOut is failing because of that.

wxiaoguang and others added 2 commits February 27, 2026 17:38
Signed-off-by: Nikita Vakula <nikita.vakula@alpsalpine.com>
@krjakbrjak
Copy link
Copy Markdown
Contributor Author

My PR instead uses the client_id parameter (which the RP-Initiated Logout spec also supports)

Can you add the spec reference as code comment?

Added

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 27, 2026
@wxiaoguang
Copy link
Copy Markdown
Contributor

Thanks for the refactoring! Could you share what was wrong with the original approach?

The JS doesn't need to change. "GET" is the right approach, the same as GitHub.

Also, one thing I noticed: if the user is OAuth2 but the provider is not OIDC (e.g. GitHub), buildOIDCEndSessionURL returns "", which overwrites the default. Should this be:

Sorry, I made a mistake, fixed in new commits and added a new "assert"

@wxiaoguang wxiaoguang self-requested a review February 27, 2026 12:31
@GiteaBot GiteaBot added lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Feb 27, 2026
@wxiaoguang
Copy link
Copy Markdown
Contributor

Will try to add more tests

@wxiaoguang wxiaoguang force-pushed the VNI-oidc-logout branch 3 times, most recently from e94dfd7 to 41acca1 Compare February 27, 2026 13:04
Copy link
Copy Markdown
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

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

Hopefully it is good enough now.

It's really tricky to write a test for the new endpoint .....

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 27, 2026
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Feb 27, 2026
@wxiaoguang wxiaoguang enabled auto-merge (squash) March 1, 2026 05:59
@wxiaoguang wxiaoguang merged commit 649ebeb into go-gitea:main Mar 1, 2026
26 checks passed
@GiteaBot GiteaBot added this to the 1.26.0 milestone Mar 1, 2026
zjjhot added a commit to zjjhot/gitea that referenced this pull request Mar 2, 2026
* giteaofficial/main: (21 commits)
  Enable docker layer caching for `dry-run` and `nightly` container builds (go-gitea#36738)
  Add admin badge to navbar avatar (go-gitea#36790)
  WorkflowDispatch api optionally return runid (go-gitea#36706)
  upgrade minimatch (go-gitea#36760)
  Add `never` option to `PUBLIC_URL_DETECTION` configuration (go-gitea#36785)
  Refactor avatar package, support default avatar fallback (go-gitea#36788)
  Mark unused&immature activitypub as "not implemented" (go-gitea#36789)
  Add “Copy Source” to markup comment menu (go-gitea#36726)
  Update Nix flake (go-gitea#36787)
  Implements OIDC RP-Initiated Logout (go-gitea#36724)
  Fix README symlink resolution in subdirectories like .github (go-gitea#36775)
  [skip ci] Updated translations via Crowdin
  Correct spelling (go-gitea#36783)
  refactor: replace legacy tw-flex utility classes with flex-text-block/inline (go-gitea#36778)
  Fix `no-content` message not rendering after comment edit (go-gitea#36733)
  Fix typos and grammar in English locale (go-gitea#36751)
  Move Fomantic dropdown CSS to custom module (go-gitea#36530)
  Use "Enable Gravatar" but not "Disable" (go-gitea#36771)
  feat: add branch_count to repository API (go-gitea#35351) (go-gitea#36743)
  Deprecate RenderWithErr (go-gitea#36769)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants