mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +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:
@@ -498,7 +498,7 @@ func TestOPStorage_TerminateSession(t *testing.T) {
|
||||
_, err = rp.Userinfo[*oidc.UserInfo](CTX, tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider)
|
||||
require.NoError(t, err)
|
||||
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state")
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state", "", nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String())
|
||||
|
||||
@@ -535,7 +535,7 @@ func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) {
|
||||
_, err = rp.Userinfo[*oidc.UserInfo](CTX, tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.Subject, provider)
|
||||
require.NoError(t, err)
|
||||
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state")
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state", "", nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String())
|
||||
|
||||
@@ -551,6 +551,17 @@ func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func buildLogoutURL(origin, logoutURLV2 string, redirectURI string, extraParams map[string]string) string {
|
||||
u, _ := url.Parse(origin + logoutURLV2 + redirectURI)
|
||||
q := u.Query()
|
||||
for k, v := range extraParams {
|
||||
q.Set(k, v)
|
||||
}
|
||||
u.RawQuery = q.Encode()
|
||||
// Append the redirect URI as a URL-escaped string
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -565,7 +576,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
||||
return clientID
|
||||
}(),
|
||||
authRequestID: createAuthRequest,
|
||||
logoutURL: http_utils.BuildOrigin(Instance.Host(), Instance.Config.Secure) + Instance.Config.LogoutURLV2 + logoutRedirectURI + "?state=state",
|
||||
logoutURL: buildLogoutURL(http_utils.BuildOrigin(Instance.Host(), Instance.Config.Secure), Instance.Config.LogoutURLV2, logoutRedirectURI+"?state=state", map[string]string{"logout_hint": "hint", "ui_locales": "it-IT en-US"}),
|
||||
},
|
||||
{
|
||||
name: "login v2 config",
|
||||
@@ -574,7 +585,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
||||
return clientID
|
||||
}(),
|
||||
authRequestID: createAuthRequestNoLoginClientHeader,
|
||||
logoutURL: http_utils.BuildOrigin(Instance.Host(), Instance.Config.Secure) + Instance.Config.LogoutURLV2 + logoutRedirectURI + "?state=state",
|
||||
logoutURL: buildLogoutURL(http_utils.BuildOrigin(Instance.Host(), Instance.Config.Secure), Instance.Config.LogoutURLV2, logoutRedirectURI+"?state=state", map[string]string{"logout_hint": "hint", "ui_locales": "it-IT en-US"}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -601,7 +612,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
||||
assertTokens(t, tokens, false)
|
||||
assertIDTokenClaims(t, tokens.IDTokenClaims, User.GetUserId(), armPasskey, startTime, changeTime, sessionID)
|
||||
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, "", logoutRedirectURI, "state")
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, "", logoutRedirectURI, "state", "hint", oidc.ParseLocales([]string{"it-IT", "en-US"}))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.logoutURL, postLogoutRedirect.String())
|
||||
|
||||
|
@@ -311,7 +311,7 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) {
|
||||
require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId())
|
||||
|
||||
// end session
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state")
|
||||
postLogoutRedirect, err := rp.EndSession(CTX, provider, tokens.IDToken, logoutRedirectURI, "state", "", nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, logoutRedirectURI+"?state=state", postLogoutRedirect.String())
|
||||
|
||||
|
Reference in New Issue
Block a user