Implements OIDC RP-Initiated Logout#36724
Conversation
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>
e29e457 to
259a1dd
Compare
|
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? |
There was a problem hiding this comment.
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.
333fab9 to
ceaa485
Compare
Can you add the spec reference as code comment? |
ceaa485 to
cb23aff
Compare
|
@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), if ctx.Doer != nil && ctx.Doer.LoginType == auth.OAuth2 {
if builtUrl := buildOIDCEndSessionURL(ctx, ctx.Doer); builtUrl != "" {
redirectTo = builtUrl
}
}btw, switching from |
Signed-off-by: Nikita Vakula <nikita.vakula@alpsalpine.com>
Added |
3ffa64b to
25d8c70
Compare
The JS doesn't need to change. "GET" is the right approach, the same as GitHub.
Sorry, I made a mistake, fixed in new commits and added a new "assert" |
|
Will try to add more tests |
e7050c1 to
fc183fc
Compare
e94dfd7 to
41acca1
Compare
41acca1 to
06a84bc
Compare
wxiaoguang
left a comment
There was a problem hiding this comment.
Hopefully it is good enough now.
It's really tricky to write a test for the new endpoint .....
* 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) ...
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 withclient_idandpost_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