diff --git a/management/internals/shared/grpc/pkce_flow_test.go b/management/internals/shared/grpc/pkce_flow_test.go index 32780a25c..8724bacd8 100644 --- a/management/internals/shared/grpc/pkce_flow_test.go +++ b/management/internals/shared/grpc/pkce_flow_test.go @@ -17,18 +17,6 @@ func TestApplySessionExtendFlowPolicy(t *testing.T) { disablePromptLogin bool loginFlag uint32 }{ - { - name: "extend forces prompt=login over a silent flow", - flow: &proto.PKCEAuthorizationFlow{ - ProviderConfig: &proto.ProviderConfig{ - DisablePromptLogin: true, - LoginFlag: uint32(common.LoginFlagMaxAge0), - }, - }, - sessionExtend: true, - disablePromptLogin: false, - loginFlag: uint32(common.LoginFlagPromptLogin), - }, { name: "extend replaces max_age=0 so login_hint is honoured", flow: &proto.PKCEAuthorizationFlow{ @@ -42,17 +30,41 @@ func TestApplySessionExtendFlowPolicy(t *testing.T) { loginFlag: uint32(common.LoginFlagPromptLogin), }, { - name: "login keeps the configured flow untouched", + name: "extend replaces the none flag so the extend is not silent", + flow: &proto.PKCEAuthorizationFlow{ + ProviderConfig: &proto.ProviderConfig{ + DisablePromptLogin: false, + LoginFlag: uint32(common.LoginFlagNone), + }, + }, + sessionExtend: true, + disablePromptLogin: false, + loginFlag: uint32(common.LoginFlagPromptLogin), + }, + { + name: "extend respects DisablePromptLogin", flow: &proto.PKCEAuthorizationFlow{ ProviderConfig: &proto.ProviderConfig{ DisablePromptLogin: true, LoginFlag: uint32(common.LoginFlagMaxAge0), }, }, - sessionExtend: false, + sessionExtend: true, disablePromptLogin: true, loginFlag: uint32(common.LoginFlagMaxAge0), }, + { + name: "login keeps the configured flow untouched", + flow: &proto.PKCEAuthorizationFlow{ + ProviderConfig: &proto.ProviderConfig{ + DisablePromptLogin: false, + LoginFlag: uint32(common.LoginFlagMaxAge0), + }, + }, + sessionExtend: false, + disablePromptLogin: false, + loginFlag: uint32(common.LoginFlagMaxAge0), + }, } for _, tc := range tests { diff --git a/management/internals/shared/grpc/server.go b/management/internals/shared/grpc/server.go index 795e33790..c8aca53d1 100644 --- a/management/internals/shared/grpc/server.go +++ b/management/internals/shared/grpc/server.go @@ -1252,16 +1252,24 @@ func (s *Server) GetPKCEAuthorizationFlow(ctx context.Context, req *proto.Encryp // prompt=login the IdP honours login_hint and offers the peer's own account, // whereas max_age=0 leaves the user to find it among every account signed in. // +// DisablePromptLogin is left alone. It is set for IdPs that break on +// prompt=login — Authentik triggers a double authentication, and social logins +// fail outright — so overriding it would trade a recoverable session extend for +// a login that cannot complete at all. Those deployments keep the silent flow +// and, with several accounts signed in, an extend answered from the wrong one +// still fails the user match. +// // Called after ValidateFlowResponse so that a per-peer override cannot reinstate // the silent flow for an extend. func applySessionExtendFlowPolicy(flow *proto.PKCEAuthorizationFlow, sessionExtend bool) { if !sessionExtend { return } - if cfg := flow.GetProviderConfig(); cfg != nil { - cfg.DisablePromptLogin = false - cfg.LoginFlag = uint32(common.LoginFlagPromptLogin) + cfg := flow.GetProviderConfig() + if cfg == nil || cfg.GetDisablePromptLogin() { + return } + cfg.LoginFlag = uint32(common.LoginFlagPromptLogin) } // SyncMeta endpoint is used to synchronize peer's system metadata and notifies the connected,