Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

### 0.5.1 (upcoming)

* [PLT-3581] Add configurable sign-out URL via `--sign-out-url` / `OAUTH2_PROXY_SIGN_OUT_URL` to support non-standard IdP logout flows (e.g. Autentica/REDSARA)

## Previous development

### 0.5.0 (2026-05-11)

* [PLT-2583] Bump oauth2-proxy upstream to v7.15.2 (security fixes: authentication bypasses CVE-2026-34986, CVE-2026-32281 and others)
Expand Down
13 changes: 13 additions & 0 deletions docs/docs/configuration/alpha_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ Provider holds all configuration for a single provider
| `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. |
| `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider<br/>or providers utilize OIDC configurations. |
| `loginGovConfig` | _[LoginGovOptions](#logingovoptions)_ | LoginGovConfig holds all configurations for LoginGov provider. |
| `sisConfig` | _[SISOptions](#sisoptions)_ | SISConfig holds all configurations for SIS provider. |
| `id` | _string_ | ID should be a unique identifier for the provider.<br/>This value is required for all providers. |
| `provider` | _[ProviderType](#providertype)_ | Type is the OAuth provider<br/>must be set from the supported providers group,<br/>otherwise 'Google' is set as default |
| `name` | _string_ | Name is the providers display name<br/>if set, it will be shown to the users in the login page. |
Expand All @@ -592,6 +593,7 @@ Provider holds all configuration for a single provider
| `code_challenge_method` | _string_ | The code challenge method |
| `additionalClaims` | _[]string_ | Additional claims to be obtained from the upstream IDP, either from the id_token or from the userinfo endpoint if configured. |
| `backendLogoutURL` | _string_ | URL to call to perform backend logout, `{id_token}` would be replaced by the actual `id_token` if available in the session |
| `signOutURL` | _string_ | SignOutURL overrides the provider's default sign-out redirect URL |

### ProviderType
#### (`string` alias)
Expand All @@ -615,6 +617,17 @@ AlphaConfig](https://oauth2-proxy.github.io/oauth2-proxy/configuration/alpha-con
However, [**the feature to implement multiple providers is not
complete**](https://github.com/oauth2-proxy/oauth2-proxy/issues/926).

### SISOptions

(**Appears on:** [Provider](#provider))



| Field | Type | Description |
| ----- | ---- | ----------- |
| `SISRootURL` | _string_ | SISRootURL is the OpenID Connect SISRoot URL |
| `ClearExtraCookieNames` | _[]string_ | ClearExtraCookieNames sets cookie names to clear after sign out |

### SecretSource

(**Appears on:** [ClaimSource](#claimsource), [HeaderValue](#headervalue), [TLS](#tls))
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/options/legacy_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ type LegacyProvider struct {
GoogleAdminAPIUserScope string `flag:"google-admin-api-user-scope" cfg:"google_admin_api_user_scope"`

SISRootURL string `flag:"sis-root-url" cfg:"sis_root_url"`
SignOutURL string `flag:"sign-out-url" cfg:"sign_out_url"`
ClearExtraCookieNames []string `flag:"clear-extra-cookie-names" cfg:"clear_extra_cookie_names"`

// These options allow for other providers besides Google, with
Expand Down Expand Up @@ -720,6 +721,7 @@ func (l *LegacyProvider) convert() (Providers, error) {
CodeChallengeMethod: l.CodeChallengeMethod,
BackendLogoutURL: l.BackendLogoutURL,
AuthRequestResponseMode: l.AuthRequestResponseMode,
SignOutURL: l.SignOutURL,
}

// This part is out of the switch section for all providers that support OIDC
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/options/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ type Provider struct {

// URL to call to perform backend logout, `{id_token}` would be replaced by the actual `id_token` if available in the session
BackendLogoutURL string `yaml:"backendLogoutURL"`
// SignOutURL overrides the provider's default sign-out redirect URL
SignOutURL string `yaml:"signOutURL,omitempty"`
}

// ProviderType is used to enumerate the different provider type options
Expand Down
1 change: 1 addition & 0 deletions providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData,
"profile": {dst: &p.ProfileURL, raw: providerConfig.ProfileURL},
"validate": {dst: &p.ValidateURL, raw: providerConfig.ValidateURL},
"resource": {dst: &p.ProtectedResource, raw: providerConfig.ProtectedResource},
"signout": {dst: &p.SignOutURL, raw: providerConfig.SignOutURL},
} {
var err error
*u.dst, err = url.Parse(u.raw)
Expand Down
4 changes: 2 additions & 2 deletions providers/sis.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ func (p *SISProvider) GetSignOutURL(redirectURI string) string {
// copy URL
redirect := *p.SignOutURL
if redirectURI != "" {
v := url.Values{}
v.Add("rd", redirectURI)
v := redirect.Query()
v.Set("rd", redirectURI)
redirect.RawQuery = v.Encode()
}
return redirect.String()
Expand Down
35 changes: 35 additions & 0 deletions providers/sis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,41 @@ func TestSISProviderOverrides(t *testing.T) {
assert.Equal(t, "profile", p.Data().Scope)
}

func TestSISProviderGetSignOutURL(t *testing.T) {
tests := []struct {
name string
signOutURL string
redirectURI string
expected string
}{
{
name: "no redirect preserves sign-out URL as-is",
signOutURL: "https://sis.example.com/sso/logout",
redirectURI: "",
expected: "https://sis.example.com/sso/logout",
},
{
name: "redirect appended as rd param",
signOutURL: "https://sis.example.com/sso/logout",
redirectURI: "https://app.example.com/home",
expected: "https://sis.example.com/sso/logout?rd=https%3A%2F%2Fapp.example.com%2Fhome",
},
{
name: "existing query params preserved when adding rd",
signOutURL: "https://autentica.example.com/logout?appId=5784",
redirectURI: "https://app.example.com/home",
expected: "https://autentica.example.com/logout?appId=5784&rd=https%3A%2F%2Fapp.example.com%2Fhome",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
u, _ := url.Parse(tt.signOutURL)
p := NewSISProvider(&ProviderData{SignOutURL: u}, options.SISOptions{})
assert.Equal(t, tt.expected, p.GetSignOutURL(tt.redirectURI))
})
}
}

func TestSISProviderRedeem(t *testing.T) {
b := testSISBackend(map[string]string{
"/sso/oauth2.0/accessToken": "access_token=imaginary_access_token&expires=10000",
Expand Down