mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:07:31 +00:00
feat(OIDC): handle logout hint on end_session_endpoint (#10039)
# Which Problems Are Solved The OIDC session endpoint allows to pass a `id_token_hint` to identify the session to terminate. In case the application is not able to pass that, e.g. Console currently allows multiple sessions to be open, but will only store the id_token of the current session, allowing to pass the `logout_hint` to identify the user adds some new possibilities. # How the Problems Are Solved In case the end_session_endpoint is called with no `id_token_hint`, but a `logout_hint` and the v2 login UI is configured, the information is passed to the login UI also as `login_hint` parameter to allow the login UI to determine the session to be terminated, resp. let the user decide. # Additional Changes Also added the `ui_locales` as parameter to handle and pass to the V2 login UI. # Dependencies ⚠️ ~These changes depend on https://github.com/zitadel/oidc/pull/774~ # Additional Context closes #9847 --------- Co-authored-by: Marco Ardizzone <marco@zitadel.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
@@ -30,6 +31,8 @@ import (
|
||||
const (
|
||||
LoginClientHeader = "x-zitadel-login-client"
|
||||
LoginPostLogoutRedirectParam = "post_logout_redirect"
|
||||
LoginLogoutHintParam = "logout_hint"
|
||||
LoginUILocalesParam = "ui_locales"
|
||||
LoginPath = "/login"
|
||||
LogoutPath = "/logout"
|
||||
LogoutDonePath = "/logout/done"
|
||||
@@ -283,14 +286,19 @@ func (o *OPStorage) TerminateSessionFromRequest(ctx context.Context, endSessionR
|
||||
// we'll redirect to the UI (V2) and let it decide which session to terminate
|
||||
//
|
||||
// If there's no id_token_hint and for v1 logins, we handle them separately
|
||||
if endSessionRequest.IDTokenHintClaims == nil &&
|
||||
(authz.GetFeatures(ctx).LoginV2.Required || headers.Get(LoginClientHeader) != "") {
|
||||
if endSessionRequest.IDTokenHintClaims == nil && (authz.GetFeatures(ctx).LoginV2.Required || headers.Get(LoginClientHeader) != "") {
|
||||
redirectURI := v2PostLogoutRedirectURI(endSessionRequest.RedirectURI)
|
||||
// if no base uri is set, fallback to the default configured in the runtime config
|
||||
if authz.GetFeatures(ctx).LoginV2.BaseURI == nil || authz.GetFeatures(ctx).LoginV2.BaseURI.String() == "" {
|
||||
return o.defaultLogoutURLV2 + redirectURI, nil
|
||||
logoutURI := authz.GetFeatures(ctx).LoginV2.BaseURI
|
||||
// if no logout uri is set, fallback to the default configured in the runtime config
|
||||
if logoutURI == nil || logoutURI.String() == "" {
|
||||
logoutURI, err = url.Parse(o.defaultLogoutURLV2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
logoutURI = logoutURI.JoinPath(LogoutPath)
|
||||
}
|
||||
return buildLoginV2LogoutURL(authz.GetFeatures(ctx).LoginV2.BaseURI, redirectURI), nil
|
||||
return buildLoginV2LogoutURL(logoutURI, redirectURI, endSessionRequest.LogoutHint, endSessionRequest.UILocales), nil
|
||||
}
|
||||
|
||||
// V1:
|
||||
@@ -367,12 +375,25 @@ func (o *OPStorage) federatedLogout(ctx context.Context, sessionID string, postL
|
||||
return login.ExternalLogoutPath(sessionID)
|
||||
}
|
||||
|
||||
func buildLoginV2LogoutURL(baseURI *url.URL, redirectURI string) string {
|
||||
baseURI.JoinPath(LogoutPath)
|
||||
q := baseURI.Query()
|
||||
func buildLoginV2LogoutURL(logoutURI *url.URL, redirectURI, logoutHint string, uiLocales []language.Tag) string {
|
||||
if strings.HasSuffix(logoutURI.Path, "/") && len(logoutURI.Path) > 1 {
|
||||
logoutURI.Path = strings.TrimSuffix(logoutURI.Path, "/")
|
||||
}
|
||||
|
||||
q := logoutURI.Query()
|
||||
q.Set(LoginPostLogoutRedirectParam, redirectURI)
|
||||
baseURI.RawQuery = q.Encode()
|
||||
return baseURI.String()
|
||||
if logoutHint != "" {
|
||||
q.Set(LoginLogoutHintParam, logoutHint)
|
||||
}
|
||||
if len(uiLocales) > 0 {
|
||||
locales := make([]string, len(uiLocales))
|
||||
for i, locale := range uiLocales {
|
||||
locales[i] = locale.String()
|
||||
}
|
||||
q.Set(LoginUILocalesParam, strings.Join(locales, " "))
|
||||
}
|
||||
logoutURI.RawQuery = q.Encode()
|
||||
return logoutURI.String()
|
||||
}
|
||||
|
||||
// v2PostLogoutRedirectURI will take care that the post_logout_redirect_uri is correctly set for v2 logins.
|
||||
|
Reference in New Issue
Block a user