This commit is contained in:
Alban Fonrouge 2025-12-09 14:40:23 +00:00 committed by GitHub
commit e71be73642
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 1 deletions

View File

@ -38,6 +38,20 @@ X-Auth-Request-Redirect: https://my-oidc-provider/sign_out_page
BEWARE that the domain you want to redirect to (`my-oidc-provider.example.com` in the example) must be added to the [`--whitelist-domain`](../configuration/overview) configuration option otherwise the redirect will be ignored. Make sure to include the actual domain and port (if needed) and not the URL (e.g "localhost:8081" instead of "http://localhost:8081").
ID Token can be injected in the redirect url by using `{id_token}` placeholder. For example to redirect to `https://my-oidc-provider.example.com/sign_out_page?id_token_hint={id_token}&post_logout_redirect_uri=https://my-app.example.com`;
```
/oauth2/sign_out?rd=https%3A%2F%2Fmy-oidc-provider.example.com%2Fsign_out_page%3Fid_token_hint%3D%7Bid_token%7D%26post_logout_redirect_uri%3Dhttps%3A%2F%2Fmy-app.example.com
```
or alternatively in the header:
```
GET /oauth2/sign_out HTTP/1.1
X-Auth-Request-Redirect: https://my-oidc-provider.example.com/sign_out_page?id_token_hint={id_token}&post_logout_redirect_uri=https://my-app.example.com
...
```
### Auth
This endpoint returns 202 Accepted response or a 401 Unauthorized response.

View File

@ -54,6 +54,8 @@ const (
authOnlyPath = "/auth"
userInfoPath = "/userinfo"
staticPathPrefix = "/static/"
idTokenPlaceholder = "{id_token}"
)
var (
@ -752,6 +754,15 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) {
return
}
if strings.Contains(redirect, idTokenPlaceholder) {
session, err := p.getAuthenticatedSession(rw, req)
if err != nil {
logger.Errorf("error getting authenticated session during SignOut, won't replace id_token placeholder in redirect URL: %v", err)
} else {
redirect = strings.ReplaceAll(redirect, idTokenPlaceholder, session.IDToken)
}
}
p.backendLogout(rw, req)
http.Redirect(rw, req, redirect, http.StatusFound)
@ -773,7 +784,7 @@ func (p *OAuthProxy) backendLogout(rw http.ResponseWriter, req *http.Request) {
return
}
backendLogoutURL := strings.ReplaceAll(providerData.BackendLogoutURL, "{id_token}", session.IDToken)
backendLogoutURL := strings.ReplaceAll(providerData.BackendLogoutURL, idTokenPlaceholder, session.IDToken)
// security exception because URL is dynamic ({id_token} replacement) but
// base is not end-user provided but comes from configuration somewhat secure
resp, err := http.Get(backendLogoutURL) // #nosec G107

View File

@ -15,6 +15,7 @@ import (
"time"
"github.com/coreos/go-oidc/v3/oidc"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/hmacauth"
@ -3531,3 +3532,49 @@ func TestGetOAuthRedirectURI(t *testing.T) {
})
}
}
func TestIdTokenPlaceholderInSignOut(t *testing.T) {
opts := baseTestOptions()
opts.WhitelistDomains = []string{"my-oidc-provider.example.com"}
err := validation.Validate(opts)
assert.NoError(t, err)
const emailAddress = "john.doe@example.com"
const userName = "9fcab5c9b889a557"
created := time.Now()
session := &sessions.SessionState{
User: userName,
Groups: []string{"a", "b"},
Email: emailAddress,
IDToken: "eYjjjjjj.vvvv.ddd",
AccessToken: "oauth_token",
CreatedAt: &created,
}
proxy, err := NewOAuthProxy(opts, func(email string) bool {
return true
})
assert.NoError(t, err)
// Save the required session
rw := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/", nil)
err = proxy.sessionStore.Save(rw, req, session)
assert.NoError(t, err)
rw = httptest.NewRecorder()
rdUrl := url.QueryEscape("https://my-oidc-provider.example.com/sign_out_page?id_token_hint={id_token}&post_logout_redirect_uri=https://my-app.example.com/")
req, _ = http.NewRequest("GET", "/oauth2/sign_out?rd="+rdUrl, nil)
req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{
RequestID: "11111111-2222-4333-8444-555555555555",
Session: session,
})
proxy.SignOut(rw, req)
newLocation := rw.Header().Values("Location")[0]
assert.Equal(t, "https://idp.com/endsession?id_token_hint=eYjjjjjj.vvvv.ddd&post_logout_redirect_uri=http://myapp.com", newLocation)
}